1 // Copyright (c) 2005, 2006 ASCLEPIOS Project, INRIA Sophia-Antipolis (France)
2 // Copyright (c) 2007 Geometrica Project, INRIA Sophia-Antipolis (France)
3 // Copyright (c) 2008 GeometryFactory, Sophia-Antipolis (France)
4 // All rights reserved.
5 //
6 // This file is part of the ImageIO Library, and as been adapted for CGAL (www.cgal.org).
7 //
8 // $URL: https://github.com/CGAL/cgal/blob/v5.3/CGAL_ImageIO/include/CGAL/ImageIO_impl.h $
9 // $Id: ImageIO_impl.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
10 // SPDX-License-Identifier: LGPL-3.0-or-later
11 //
12 
13 #ifdef CGAL_HEADER_ONLY
14 #define CGAL_INLINE_FUNCTION inline
15 #else
16 #define CGAL_INLINE_FUNCTION
17 #endif
18 
19 #ifdef _MSC_VER
20 // Suppress deprecated warning for fileno and strdup
21 #  pragma warning(disable: 4127 4706 4996)
22 
23 #include <fcntl.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <io.h>
27 #include <stdio.h>
28 #endif
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 /* formats actuellement lus
36 
37    format     |   extension(s)   |  lecture  | ecriture
38    INRIMAGE   |  .inr[.gz]       |     X     |     X     -> + .gradient[.gz] + .gradient_direction[.gz]
39    GIS        |  .dim, .ima[.gz] |     X     |     X
40    ANALYZE    |  .hdr, .img[.gz] |     X     |     X
41    PNM        |  .ppm, .pgm      |     X     |     X
42    GIF        |  .gif            |     X     |
43    BMP        |  .gif            |     X     |
44 */
45 #include <CGAL/ImageIO/inr.h>
46 #include <CGAL/ImageIO/gif.h>
47 #include <CGAL/ImageIO/gis.h>
48 #include <CGAL/ImageIO/pnm.h>
49 #include <CGAL/ImageIO/bmp.h>
50 #include <CGAL/ImageIO/iris.h>
51 #include <CGAL/ImageIO/analyze.h>
52 #ifdef MINC_FILES
53 #include <CGAL/ImageIO/mincio.h>
54 #endif
55 
56 
57 #ifdef CGAL_USE_ZLIB
58 #define ZLIB_MAJOR_VERSION ZLIB_VERNUM>>8
59 #define ZLIB_MINOR_VERSION (ZLIB_VERNUM-(ZLIB_MAJOR_VERSION <<8))
60 #define CGAL_USE_GZFWRITE  ZLIB_MAJOR_VERSION > 0x12 || ((ZLIB_MAJOR_VERSION == 0x12) && (ZLIB_MINOR_VERSION >= 0x90))
61 #endif
62 struct Remove_supported_file_format {
~Remove_supported_file_formatRemove_supported_file_format63   ~Remove_supported_file_format()
64   {
65     removeSupportedFileFormat();
66   }
67 };
68 
69 #ifdef CGAL_HEADER_ONLY
70 
get_static_firstFormat()71 inline PTRIMAGE_FORMAT & get_static_firstFormat()
72 {
73   static PTRIMAGE_FORMAT firstFormat = nullptr;
74   return firstFormat;
75 }
76 
get_static_inrimageFormat()77 inline PTRIMAGE_FORMAT & get_static_inrimageFormat()
78 {
79   static PTRIMAGE_FORMAT inrimageFormat = nullptr;
80   return inrimageFormat;
81 }
82 
get_static_rsff()83 inline Remove_supported_file_format & get_static_rsff()
84 {
85   static Remove_supported_file_format rsff;
86   return rsff;
87 }
88 // Dummy call to get_static_rsff(), otherwise it would not get instanced
89 CGAL_UNUSED static Remove_supported_file_format &rsff_dummy_ref = get_static_rsff();
90 
91 
92 #else // not header-only
93 
94 /** the first file format is initialized to null */
95 static PTRIMAGE_FORMAT firstFormat = nullptr;
get_static_firstFormat()96 inline PTRIMAGE_FORMAT & get_static_firstFormat()
97 {
98   return firstFormat;
99 }
100 
101 /** the Inrimage file format (default format) is initialized to null */
102 static PTRIMAGE_FORMAT InrimageFormat = nullptr;
get_static_inrimageFormat()103 inline PTRIMAGE_FORMAT & get_static_inrimageFormat()
104 {
105   return InrimageFormat;
106 }
107 
108 static Remove_supported_file_format rsff;
get_static_rsff()109 inline Remove_supported_file_format & get_static_rsff()
110 {
111   return rsff;
112 }
113 
114 #endif
115 
116 /*--------------------------------------------------
117  *
118  * mimics standard routines
119  *
120  --------------------------------------------------*/
121 
122 
123 
124 extern "C" {
125   /* default allocation routine */
126   static void *(*allocRoutine)(size_t) = 0;
127   /* default deallocation routine */
128   static void (*deleteRoutine)(void *) = 0;
129 }
130 
131 CGAL_INLINE_FUNCTION
ImageIO_alloc(size_t s)132 void *ImageIO_alloc(size_t s) {
133   if(!allocRoutine) allocRoutine = malloc;
134   return ( (*allocRoutine)(s) );
135 }
136 /* call allocation routine */
137 CGAL_INLINE_FUNCTION
ImageIO_free(void * m)138 void ImageIO_free(void *m) {
139   if(!deleteRoutine) deleteRoutine = free;
140   (*deleteRoutine)(m);
141 }
142 /* call deallocation routine */
143 
144 
145 CGAL_INLINE_FUNCTION
ImageIO_limit_len(size_t to_be_read)146 unsigned int ImageIO_limit_len(size_t to_be_read)
147 {
148   return (unsigned int)(std::min)(to_be_read, size_t(1u<<30));
149 }
150 
151 /* mimics fwrite() function.
152    According to _openWriteImage(), openMode will has one
153    of the following value:
154    - OM_STD (for stdout)
155    - OM_GZ
156    - OM_FILE
157 */
158 CGAL_INLINE_FUNCTION
ImageIO_write(const _image * im,const void * buf,size_t len)159 size_t ImageIO_write(const _image *im, const void *buf, size_t len) {
160   size_t to_be_written = len;
161   std::ptrdiff_t l = -1;
162   char *b = (char*)buf;
163 
164   switch(im->openMode) {
165   default :
166   case OM_CLOSE :
167     return 0;
168   case OM_STD :
169 #ifdef CGAL_USE_ZLIB
170     while ( (to_be_written > 0) && ((l = gzwrite(im->fd, (void *) b, ImageIO_limit_len(to_be_written))) > 0) ) {
171       to_be_written -= l;
172       b += l;
173     }
174 #else
175     while ( (to_be_written > 0) && ((l = fwrite( b, 1, ImageIO_limit_len(to_be_written), im->fd )) > 0) ) {
176       to_be_written -= l;
177       b += l;
178     }
179 #endif
180     return ( len - to_be_written );
181 #ifdef CGAL_USE_ZLIB
182   case OM_GZ :
183     while ( (to_be_written > 0) && ((l = gzwrite(im->fd, (void *) b, ImageIO_limit_len(to_be_written))) > 0) ) {
184       to_be_written -= l;
185       b += l;
186     }
187     if(l<0)
188     {
189       int errnum;
190       fprintf(stderr, "zlib error: %s\n", gzerror(im->fd, &errnum));
191     }
192     return ( len - to_be_written );
193 #if CGAL_USE_GZFWRITE
194   case OM_FILE :
195     while ( (to_be_written > 0) && ((l = gzfwrite( b, sizeof(char), ImageIO_limit_len(to_be_written), im->fd )) > 0) ) {
196       to_be_written -= l;
197       b += l;
198     }
199     return ( len - to_be_written );
200 #endif // CGAL_USE_GZFWRITE
201 #else
202   case OM_FILE :
203     while ( (to_be_written > 0) && ((l = fwrite( b, 1, ImageIO_limit_len(to_be_written), im->fd )) > 0) ) {
204       to_be_written -= l;
205       b += l;
206     }
207     return ( len - to_be_written );
208 #endif
209   }
210 }
211 
212 CGAL_INLINE_FUNCTION
ImageIO_limit_read(size_t to_be_read)213 size_t ImageIO_limit_read(size_t to_be_read)
214 {
215   return (std::min)(to_be_read, size_t(1u<<30));
216 }
217 
218 /* mimics fread() function.
219    According to _openReadImage(), openMode will has one
220    of the following value:
221    - OM_STD (for stdin)
222    - OM_GZ *or* OM_FILE
223 */
224 CGAL_INLINE_FUNCTION
ImageIO_read(const _image * im,void * buf,size_t len)225 size_t ImageIO_read(const _image *im, void *buf, size_t len)
226 {
227   size_t to_be_read = len;
228   int l = -1;
229   char *b = (char*)buf;
230 
231   switch(im->openMode) {
232   default :
233   case OM_CLOSE :
234     return 0;
235   case OM_STD :
236 #ifdef CGAL_USE_ZLIB
237     while ( (to_be_read > 0) && ((l = gzread(im->fd, (void *) b, ImageIO_limit_len(to_be_read))) > 0) ) {
238       to_be_read -= l;
239       b += l;
240     }
241 #else
242     while ( (to_be_read > 0) && ((l = fread( b, 1, ImageIO_limit_len(to_be_read), im->fd )) > 0) ) {
243       to_be_read -= l;
244       b += l;
245     }
246 #endif
247     return ( len - to_be_read );
248 #ifdef CGAL_USE_ZLIB
249   case OM_GZ :
250 #if CGAL_USE_GZFWRITE
251   case OM_FILE :
252 #endif// CGAL_USE_GZFWRITE
253     while ( (to_be_read > 0) && ((l = gzread(im->fd, (void *) b, ImageIO_limit_len(to_be_read))) > 0) ) {
254       to_be_read -= l;
255       b += l;
256     }
257     if(l<0)
258     {
259       int errnum;
260       fprintf(stderr, "zlib error: %s\n", gzerror(im->fd, &errnum));
261     }
262     return ( len - to_be_read );
263 #else
264   case OM_FILE :
265     while ( (to_be_read > 0) && ((l = fread( b, 1, ImageIO_limit_len(to_be_read), im->fd )) > 0) ) {
266       to_be_read -= l;
267       b += l;
268     }
269     return ( len - to_be_read );
270 #endif
271   }
272 
273   //return 0;
274 }
275 
276 
277 
278 /* mimics fgets() function.
279    According to _openReadImage(), openMode will has one
280    of the following value:
281    - OM_STD (for stdout)
282    - OM_GZ *or* OM_FILE
283 */
284 CGAL_INLINE_FUNCTION
ImageIO_gets(const _image * im,char * str,int size)285 char *ImageIO_gets( const _image *im, char *str, int size )
286 {
287   char *ret = nullptr;
288   switch(im->openMode) {
289   default :
290   case OM_CLOSE :
291     return nullptr;
292   case OM_STD :
293 #ifdef CGAL_USE_ZLIB
294     ret = (char *) gzgets(im->fd, str, size );
295 #else
296     ret = fgets(str, size, im->fd);
297 #endif
298     break;
299 #ifdef CGAL_USE_ZLIB
300   case OM_GZ :
301 #if CGAL_USE_GZFWRITE
302   case OM_FILE :
303 #endif // CGAL_USE_GZFWRITE
304     ret = (char *) gzgets(im->fd, str, size);
305     break;
306 
307 #else
308   case OM_FILE :
309     ret = fgets(str, size, im->fd);
310     break;
311 #endif
312   }
313   return ret;
314 }
315 
316 
317 
318 CGAL_INLINE_FUNCTION
ImageIO_seek(const _image * im,long offset,int whence)319 long ImageIO_seek( const _image *im, long offset, int whence ) {
320   switch(im->openMode) {
321   case OM_CLOSE :
322   default :
323     return -1;
324 #ifdef CGAL_USE_ZLIB
325   case OM_GZ:
326 #if CGAL_USE_GZFWRITE
327   case OM_FILE:
328 #endif //CGAL_USE_GZFWRITE
329     return gzseek(im->fd, offset, whence );
330 #else
331   case OM_FILE:
332     return fseek( (FILE*)im->fd, offset, whence );
333 #endif
334   }
335 }
336 
337 /* return non 0 in case of error
338  */
339 CGAL_INLINE_FUNCTION
ImageIO_error(const _image * im)340 int ImageIO_error( const _image *im )
341 {
342   switch(im->openMode) {
343   case OM_CLOSE :
344   default :
345     return 0;
346 #ifdef CGAL_USE_ZLIB
347   case OM_GZ :
348 #if CGAL_USE_GZFWRITE
349   case OM_FILE :
350 #endif //CGAL_USE_GZFWRITE
351     static int errnum;
352     (void)gzerror(im->fd, &errnum);
353     return( (errnum != Z_OK) || gzeof(im->fd) );
354 #else
355   case OM_FILE :
356     return( ferror( (FILE*)im->fd ) || feof( (FILE*)im->fd ) );
357 #endif
358   }
359   //return 0;
360 }
361 
362 
363 
364 /* Upon successful completion 0 is returned.
365 
366    Closing the standard output with gzclose()
367    is necessary as it will flush the pending output.
368  */
369 CGAL_INLINE_FUNCTION
ImageIO_close(_image * im)370 int ImageIO_close( _image* im )
371 {
372   int ret=0;
373 
374   switch ( im->openMode ) {
375   default :
376   case OM_CLOSE :
377     break;
378 #ifdef CGAL_USE_ZLIB
379   case OM_GZ :
380   case OM_STD :
381 #if CGAL_USE_GZFWRITE
382   case OM_FILE :
383 #endif//CGAL_USE_GZFWRITE
384     ret = gzclose( im->fd );
385     break;
386 #else
387   case OM_STD :
388     break;
389   case OM_FILE :
390     ret = fclose( (FILE*)im->fd );
391 #endif
392   }
393 
394   im->fd = nullptr;
395   im->openMode = OM_CLOSE;
396 
397   return ret;
398 }
399 
400 
401 
402 
403 
404 
405 
406 /* given an initialized file descriptor and a file name,
407    open file from stdin (if name == nullptr, or name == "-", or name == "<"),
408    or a standard/gzipped file otherwise (gzipped files are handled assuming
409    that it is compiled and linked with zlib).
410    openMode will have one of the following value:
411    - OM_STD (for stdin)
412    - OM_GZ *or* OM_FILE
413 */
414 CGAL_INLINE_FUNCTION
_openReadImage(_image * im,const char * name)415 void _openReadImage(_image* im, const char *name) {
416   if(im->openMode == OM_CLOSE) {
417 
418     /* open from stdin */
419     if( name == nullptr || name[0] == '\0'
420         || (name[0] == '-' && name[1] == '\0')
421         || (name[0] == '<' && name[1] == '\0') ) {
422 #ifdef CGAL_USE_ZLIB
423       im->fd = gzdopen(fileno(stdin), "rb");
424 #else
425       im->fd = fdopen(fileno(stdin), "rb");
426 #endif
427       im->openMode = OM_STD;
428     }
429 
430     else {
431 #ifdef CGAL_USE_ZLIB
432       im->fd = gzopen(name, "rb");
433       if(im->fd) im->openMode = OM_GZ;
434 #else
435       im->fd = fopen(name, "rb");
436       if(im->fd) im->openMode = OM_FILE;
437 #endif
438 
439     }
440 
441   }
442 }
443 
444 
445 
446 
447 
448 /* given an initialized file descriptor and a file name,
449    open file from stdout (if name == nullptr, or name == "-", or name == ">"),
450    a gzipped pipe (if name got the extension ".gz")
451    or a standard file otherwise.
452    openMode will have one of the following value:
453    - OM_STD (for stdout)
454    - OM_GZ
455    - OM_FILE
456 */
457 CGAL_INLINE_FUNCTION
_openWriteImage(_image * im,const char * name)458 void _openWriteImage(_image* im, const char *name)
459 {
460   im->openMode = OM_CLOSE;
461 
462   if( name == nullptr || name[0] == '\0'
463       || (name[0] == '-' && name[1] == '\0')
464       || (name[0] == '>' && name[1] == '\0') ) {
465 
466 #ifdef CGAL_USE_ZLIB
467 #if (defined _LINUX_) || (defined _SOLARIS_) || (defined _SGI_)
468     im->fd = gzdopen(1, "wb");
469 #else
470     im->fd = gzdopen(fileno(stdout), "wb");
471 #endif
472 #else
473     im->fd = (_ImageIO_file) stdout;
474 #endif
475     im->openMode = OM_STD;
476   }
477 
478   else{
479 #ifdef CGAL_USE_ZLIB
480 
481     /* from gzopen() doc:
482        ... The mode parameter is as in fopen ("rb" or "wb") but can
483        also include a compression level ("wb9") or a strategy: 'f' for
484        filtered data as in "wb6f", 'h' for Huffman only compression as
485        in "wb1h" ...
486        However, a small .gz header will be written ... thus gz(d)open can not
487        be used for rgular files.
488     */
489 
490     if( !strncmp(name+strlen(name)-3, ".gz", 3) )
491       {
492 #ifdef _MSC_VER
493         int ffd=_open(name,_O_RDWR | _O_CREAT| _O_TRUNC | _O_BINARY, _S_IREAD|_S_IWRITE);
494         im->fd = gzdopen( ffd, "wb" );
495 #else
496         im->fd = gzopen( name, "wb" );
497 #endif
498         im->openMode = OM_GZ;
499       }
500     else
501     {
502 #if CGAL_USE_GZFWRITE
503       im->fd = (_ImageIO_file) gzopen(name, "wb");
504       im->openMode = OM_FILE;
505 #else
506       fprintf(stderr, "_openWriteImage: error: zlib version 1.2.9 or later\n"
507                       "is required to save in non-compressed files\n");
508       return;
509 #endif// CGAL_USE_GZFWRITE
510     }
511 
512 #else //CGAL_USE_ZLIB
513     {
514       im->fd = (_ImageIO_file) fopen(name, "wb");
515       im->openMode = OM_FILE;
516     }
517 #endif
518   }
519 }
520 
521 
522 
523 /* set allocation and deallocation routines */
524 CGAL_INLINE_FUNCTION
setImageIOAllocationRoutines(ALLOCATION_FUNCTION alloc,DEALLOCATION_FUNCTION del)525 void setImageIOAllocationRoutines(ALLOCATION_FUNCTION alloc,
526                                   DEALLOCATION_FUNCTION del) {
527   if(alloc != nullptr) allocRoutine = alloc;
528   if(del != nullptr) deleteRoutine = del;
529 }
530 
531 
532 
533 
534 
535 /*--------------------------------------------------
536  *
537  *
538  *
539  --------------------------------------------------*/
540 
541 
542 
543 
544 
545 CGAL_INLINE_FUNCTION
_getEndianness()546 ENDIANNESS _getEndianness()
547 {
548   union {
549     unsigned char uc[2];
550     unsigned short us;
551   } twobytes;
552   twobytes.us = 255;
553   /* on linux or dec
554    */
555   if ( twobytes.uc[1] == 0 ) return( END_LITTLE );
556   /* on solaris or sgi
557    */
558   return( END_BIG );
559 }
560 
561 
562 
563 
564 
565 
566 
567 /* Allocates and initializes an image descriptor */
568 CGAL_INLINE_FUNCTION
_initImage()569 _image *_initImage() {
570   _image *im;
571 
572   im = (_image *) ImageIO_alloc(sizeof(_image));
573   if ( im == nullptr ) return( im );
574 
575   /* default image size is 1*1*1 */
576   im->xdim = im->ydim = im->zdim = im->vdim = 1;
577   /* default image voxel size is 1.0*1.0*1.0 */
578   im->vx = im->vy = im->vz = 1.0;
579 
580   /* default image center  is 0 0 0 */
581   im->cx = im->cy = im->cz = 0;
582 
583   /* default image offset  is 0 0 0 */
584   im->tx = im->ty = im->tz = 0.0;
585 
586   /* default image rotation  is 0 0 0 */
587   im->rx = im->ry = im->rz = 0.0;
588 
589   /* no data yet */
590   im->data = nullptr;
591 
592   /* no file associated to image */
593   im->fd = nullptr;
594   im->openMode = OM_CLOSE;
595   im->endianness = END_UNKNOWN;
596 
597   /* unknown data kind
598      default is binary
599    */
600   im->dataMode = DM_BINARY;
601 
602   /* no user string */
603   im->user = nullptr;
604   im->nuser = 0;
605 
606   /* unknown word kind */
607   im->wdim = 0;
608   im->wordKind = WK_UNKNOWN;
609   im->vectMode = VM_SCALAR;
610   im->sign = SGN_UNKNOWN;
611   im->imageFormat = nullptr;
612 
613   /** eventually initializes the supported file formats */
614   if (get_static_firstFormat()==nullptr)
615     initSupportedFileFormat();
616   /* return image descriptor */
617   return im;
618 }
619 
620 CGAL_INLINE_FUNCTION
_createImage(std::size_t x,std::size_t y,std::size_t z,std::size_t v,double vx,double vy,double vz,std::size_t w,WORD_KIND wk,SIGN sgn)621 _image *_createImage(std::size_t x, std::size_t y, std::size_t z, std::size_t v,
622                      double vx, double vy, double vz, std::size_t w,
623                      WORD_KIND wk, SIGN sgn)
624 {
625   _image *im;
626 
627   im = (_image *) ImageIO_alloc(sizeof(_image));
628   if ( im == nullptr ) return( im );
629 
630   im->xdim = x;
631   im->ydim = y;
632   im->zdim = z;
633   im->vdim = v;
634   im->vx = vx;
635   im->vy = vy;
636   im->vz = vz;
637 
638   /* default image center  is 0 0 0 */
639   im->cx = im->cy = im->cz = 0;
640 
641   /* default image offset  is 0 0 0 */
642   im->tx = im->ty = im->tz = 0.0;
643 
644   /* default image rotation  is 0 0 0 */
645   im->rx = im->ry = im->rz = 0.0;
646 
647   /* no data yet */
648   im->data = ImageIO_alloc(std::size_t(x)*std::size_t(y)*std::size_t(z)*std::size_t(v)*std::size_t(w));
649 
650   /* no file associated to image */
651   im->fd = nullptr;
652   im->openMode = OM_CLOSE;
653   im->endianness = END_UNKNOWN;
654 
655   /* unknown data kind
656      default is binary
657    */
658   im->dataMode = DM_BINARY;
659 
660   /* no user string */
661   im->user = nullptr;
662   im->nuser = 0;
663 
664   /* unknown word kind */
665   im->wdim = w;
666   im->wordKind = wk;
667   im->vectMode = VM_SCALAR;
668   im->sign = sgn;
669   im->imageFormat = nullptr;
670 
671   /** eventually initializes the supported file formats */
672   if (get_static_firstFormat()==nullptr)
673     initSupportedFileFormat();
674   /* return image descriptor */
675   return im;
676 }
677 
678 /* return the bounding box of the image */
679 CGAL_INLINE_FUNCTION
_get_image_bounding_box(_image * im,double * x_min,double * y_min,double * z_min,double * x_max,double * y_max,double * z_max)680 void _get_image_bounding_box(_image* im,
681                              double* x_min, double* y_min, double* z_min,
682                              double* x_max, double* y_max, double* z_max) {
683   *x_min = im->tx;
684   *y_min = im->ty;
685   *z_min = im->tz;
686   *x_max = (double(im->xdim) - 1.0)*(im->vx) + *x_min ;
687   *y_max = (double(im->ydim) - 1.0)*(im->vy) + *y_min ;
688   *z_max = (double(im->zdim) - 1.0)*(im->vz) + *z_min ;
689 }
690 
691 /* Free an image descriptor */
692 CGAL_INLINE_FUNCTION
_freeImage(_image * im)693 void _freeImage(_image *im) {
694   unsigned int i;
695 
696   if ( im == nullptr ) return;
697 
698   /* close image if opened */
699   if(im->openMode != OM_CLOSE) ImageIO_close(im);
700 
701   /* free data if any */
702   if(im->data != nullptr) ImageIO_free(im->data);
703   im->data = nullptr;
704 
705   /* free user string array if any */
706   if( (im->nuser > 0) && (im->user != nullptr) ) {
707     for(i = 0; i < im->nuser; i++)
708       if ( im->user[i] != nullptr ) ImageIO_free(im->user[i]);
709     ImageIO_free(im->user);
710   }
711   im->nuser = 0;
712   im->user = nullptr;
713 
714   /* free given descriptor */
715   ImageIO_free(im);
716 }
717 
718 
719 
720 
721 
722 /* Reads an image from a file and returns an image descriptor or nullptr if
723    reading failed.
724    Reads from stdin if image name is nullptr. */
725 CGAL_INLINE_FUNCTION
_readImage(const char * name)726 _image* _readImage(const char *name) {
727   _image *im;
728 
729 
730   /* read header */
731   im = _readImageHeader( name );
732 
733   if(im != nullptr && im->openMode != OM_CLOSE) {
734     /* read body */
735     if(_readImageData(im) < 0) {
736       fprintf(stderr, "_readImage: error: invalid data encountered in \'%s\'\n",
737               name);
738       _freeImage(im);
739       return nullptr;
740     }
741     ImageIO_close(im);
742   }
743 
744   return im;
745 }
746 
747 // raw
748 CGAL_INLINE_FUNCTION
_readImage_raw(const char * name,const unsigned int rx,const unsigned int ry,const unsigned int rz,const double vx,const double vy,const double vz,const unsigned int offset,const std::size_t wdim,WORD_KIND wk,SIGN sgned)749 _image* _readImage_raw(const char *name,
750                        const unsigned int rx,
751                        const unsigned int ry,
752                        const unsigned int rz,
753                        const double vx,
754                        const double vy,
755                        const double vz,
756                        const unsigned int offset,
757                        const std::size_t wdim,
758                        WORD_KIND wk,
759                        SIGN sgned
760                        )
761 {
762   _image *im = nullptr;
763   im = (_image *) ImageIO_alloc(sizeof(_image));
764   if ( im == nullptr )
765     return nullptr;
766 
767   im->xdim = rx;
768   im->ydim = ry;
769   im->zdim = rz;
770   im->vdim = 1;
771   im->vx = vx;
772   im->vy = vy;
773   im->vz = vz;
774 
775   // image center
776   im->cx = im->cy = im->cz = 0;
777 
778   // image offset
779   im->tx = im->ty = im->tz = 0.0;
780 
781   // image rotation
782   im->rx = im->ry = im->rz = 0.0;
783 
784 
785   im->fd = nullptr;
786   im->openMode = OM_CLOSE;
787   im->endianness = END_UNKNOWN;
788 
789   im->dataMode = DM_BINARY;
790 
791   // no user string
792   im->user = nullptr;
793   im->nuser = 0;
794 
795   // word type (unsigned byte)
796   im->wdim = wdim;
797   im->wordKind = wk;
798   im->vectMode = VM_SCALAR;
799   im->sign = sgned;
800   im->imageFormat = nullptr;
801 
802   // read file
803   ::_openReadImage(im, name);
804   if(!im->fd) {
805     fprintf(stderr, "_readImage_raw: error: unable to open file \'%s\'\n", name);
806     _freeImage(im);
807     return nullptr;
808   }
809 
810   // read offset
811   if(offset > 0) {
812     im->data = ImageIO_alloc(offset+1);
813     ImageIO_read(im, im->data, offset);
814     ImageIO_free(im->data);
815   }
816   // allocate memory
817   im->data = ImageIO_alloc(rx*ry*rz*wdim);
818   if(im->data == nullptr)
819     return nullptr;
820 
821   // read
822   ImageIO_read(im, im->data, rx*ry*rz*wdim);
823 
824   ImageIO_close(im);
825   /*
826     unsigned int i,j,k;
827     unsigned char *data = (unsigned char *)im->data;
828     int dimxy = rx * ry;
829     for(i=0;i<rx;i++)
830     for(j=0;j<ry;j++)
831     for(k=0;k<rz;k++)
832     {
833     unsigned char voxel;
834     fread(&voxel,1,1,pFile);
835     data[k * dimxy + j * rx + i] = voxel;
836     }
837   */
838 
839   return im;
840 }
841 
842 /* Reads an image from a file and returns an image descriptor or nullptr if<br>
843    reading failed.<br>
844    Reads from stdin if image name is nullptr.
845    If the image is vectorial, it is uninterlaced. */
846 CGAL_INLINE_FUNCTION
_readNonInterlacedImage(const char * name)847 _image* _readNonInterlacedImage(const char *name) {
848   _image *im;
849 
850   /* read header */
851   im = _readImageHeader(name);
852 
853   if(im && im->openMode != OM_CLOSE) {
854     /* read scalar image body */
855     if(im->vdim == 1) {
856       if(_readImageData(im) < 0) {
857         fprintf(stderr, "_readImage: error: invalid data encountered in \'%s\'\n",
858                 name);
859         _freeImage(im);
860         return nullptr;
861       }
862     }
863     /* read vectorial image body */
864     else {
865       im->vectMode = VM_NON_INTERLACED;
866       if(_readNonInterlacedImageData(im) < 0) {
867         fprintf(stderr, "_readImage: error: invalid data encountered in \'%s\'\n",
868                 name);
869         _freeImage(im);
870         return nullptr;
871       }
872     }
873     ImageIO_close(im);
874    }
875 
876   return im;
877 }
878 
879 
880 
881 
882 
883 
884 
885 
886 
887 
888 
889 /* Write inrimage given in inr in file name. If file name's suffix is
890    .gz, the image is gziped. If file name's suffix is .hdr, the image
891    is written in ANALYZE format. If file name is nullptr, image is written
892    on stdout */
893 CGAL_INLINE_FUNCTION
_writeImage(_image * im,const char * name_to_be_written)894 int _writeImage(_image *im, const char *name_to_be_written ) {
895   int r = ImageIO_NO_ERROR;
896   std::size_t length = 0;
897   char *name = nullptr;
898   char *baseName = nullptr;
899 
900   if ( im == nullptr ) return -1;
901 
902   /* different conventions for the standard input
903    */
904   if ( name_to_be_written == nullptr || name_to_be_written[0] == '\0'
905        || (name_to_be_written[0] == '-' && name_to_be_written[1] == '\0')
906        || (name_to_be_written[0] == '>' && name_to_be_written[1] == '\0') ) {
907     name = nullptr;
908   }
909   else {
910     name = strdup( name_to_be_written );
911   }
912 
913   initSupportedFileFormat();
914 
915   /* what is the wanted format
916    */
917   if ( name == nullptr ) {
918     im->imageFormat = get_static_inrimageFormat();
919   } else {
920     std::size_t i,extLength;
921     PTRIMAGE_FORMAT f;
922     char ext[IMAGE_FORMAT_NAME_LENGTH];
923     char *ptr;
924 
925 
926     /* scan all formats; */
927     im->imageFormat=nullptr;
928     length=strlen(name);
929 
930     for(f=get_static_firstFormat();(f!=nullptr)&& (im->imageFormat==nullptr);f=f->next) {
931       /* scan all extensions for that format */
932       ptr=&f->fileExtension[0];
933 
934       do {
935         /* get next file extension */
936         i=0;
937         for(i=0;((*ptr)!=',' && (*ptr)!='\0');i++,ptr++) {
938           ext[i]=(*ptr);
939         }
940         if ((*ptr)==',') {
941           ext[i]='\0';
942           ptr++;
943         }
944         else {
945           ext[i]='\0';
946         }
947         extLength=strlen(ext);
948 
949         /* test if the tail of name matches the extension */
950         if ( (length > extLength) && (!strcmp( name + length - extLength, ext)) ) {
951           im->imageFormat=f;
952           /* copy original name and removes extension */
953           baseName=strdup(name);
954           for(i= length - extLength;i<length;++i)
955             baseName[i]='\0';
956         }
957 
958       } while (((*ptr)!='\0') && (im->imageFormat==nullptr));
959     }
960 
961     if (!im->imageFormat) {
962       fprintf(stderr, "_writeImage: warning : unknown extension in %s = assuming Inrimage\n",name);
963       im->imageFormat=get_static_inrimageFormat();
964       baseName=strdup(name);
965     }
966   }
967 
968 
969   /* open file descriptor */
970   /* _openWriteImage( im, name ) ;
971 
972 
973 
974   if(!im->fd) {
975      fprintf(stderr, "_writeImage: error: open failed\n");
976      if ( name != nullptr ) free( name );
977      if ( baseName != nullptr ) free( baseName );
978      return ImageIO_OPENING;
979   }
980   */
981 
982   if (im->imageFormat) {
983 
984     if (im->imageFormat->writeImage==nullptr) {
985       im->imageFormat=get_static_inrimageFormat();
986     }
987 
988     if ( 0 ) {
989       fprintf(stderr, "_writeImage: will write '%s' with '%s' format\n",
990               name, im->imageFormat->realName );
991     }
992 
993     if ((*im->imageFormat->writeImage)(name, im)<0) {
994       fprintf(stderr, "_writeImage: error: unable to write \'%s\'\n",
995               name);
996       r = ImageIO_WRITING_HEADER;
997     }
998 
999   }
1000 
1001 
1002 
1003   /* close file descriptor */
1004   ImageIO_close( im );
1005 
1006   im->fd = nullptr;
1007   im->openMode = OM_CLOSE;
1008 
1009   if ( baseName != nullptr ) free( baseName );
1010   if ( name != nullptr ) free( name );
1011 
1012   return r;
1013 }
1014 
1015 
1016 
1017 
1018 
1019 
1020 
1021 
1022 
1023 
1024 
1025 
1026 /* read header from an image file
1027 
1028    if standard input, it's an inrimage
1029    if not, get a magic string
1030    and try to find the good format
1031 
1032    if data are in a separate file,
1033    the header reading procedure will open
1034    the data file.
1035 
1036    error:
1037    0  success
1038    -1 unknown image type
1039    -2 error while opening
1040    -3 error while reading header
1041    -4 error while reading header or data
1042  */
1043 CGAL_INLINE_FUNCTION
_readImageHeader(const char * name)1044 _image *_readImageHeader( const char *name ) {
1045   int error = 0;
1046   return( _readImageHeaderAndGetError( name, &error ) );
1047 }
1048 
1049 
1050 
1051 CGAL_INLINE_FUNCTION
_readImageHeaderAndGetError(const char * name_to_be_read,int * error)1052 _image *_readImageHeaderAndGetError( const char *name_to_be_read, int *error )
1053 {
1054   _image *im;
1055   char magic[5];
1056   char *name = nullptr;
1057   PTRIMAGE_FORMAT f;
1058   int res;
1059 
1060   *error = ImageIO_NO_ERROR;
1061 
1062   /* open image file */
1063   im = _initImage();
1064   if ( name_to_be_read == nullptr || name_to_be_read[0] == '\0'
1065        || (name_to_be_read[0] == '-' && name_to_be_read[1] == '\0')
1066        || (name_to_be_read[0] == '<' && name_to_be_read[1] == '\0') ) {
1067     name = nullptr;
1068   }
1069   else {
1070     name = strdup( name_to_be_read );
1071   }
1072 
1073 
1074   _openReadImage(im, name);
1075 
1076   if(!im->fd) {
1077     if(name == nullptr) {
1078       fprintf(stderr, "_readImageHeaderAndGetError: error: nullptr file name\n");
1079     }  else {
1080       fprintf(stderr, "_readImageHeaderAndGetError: error: unable to open file \'%s\'\n", name);
1081     }
1082     _freeImage(im);
1083     *error = ImageIO_OPENING;
1084     if ( name != nullptr ) free( name );
1085     return nullptr;
1086   }
1087 
1088   initSupportedFileFormat();
1089 
1090   /* what is the wanted format ?
1091      assume that stdin is inrimage
1092    */
1093   if(im->openMode == OM_STD) {
1094     im->imageFormat=get_static_inrimageFormat();
1095   }
1096   else {
1097    /* get magic string for disk files
1098     */
1099     ImageIO_read(im, magic, 4);
1100     magic[4] = '\0';
1101     ImageIO_seek(im, 0L, SEEK_SET);
1102     /** test each format */
1103     for(f=get_static_firstFormat();(f!=nullptr)&& (im->imageFormat==nullptr);f=f->next) {
1104       /* test if it is the correct format based on magic and file extension */
1105       if (((*f->testImageFormat)(magic, name)) >=0) {
1106         im->imageFormat=f;
1107       }
1108     }
1109   }
1110 
1111   if ( im->imageFormat == nullptr ) {
1112     fprintf(stderr, "_readImageHeaderAndGetError: does not find image format for \'%s\'\n", name);
1113     ImageIO_close( im );
1114     _freeImage(im);
1115     *error = ImageIO_UNKNOWN_TYPE;
1116     if ( name != nullptr ) free( name );
1117     return nullptr;
1118   }
1119 
1120   /* now tests if the header can be read correctly */
1121 
1122   res=(*(im->imageFormat)->readImageHeader)(name,im);
1123   /* could read header only */
1124   if (res == 0) {
1125     if ( name != nullptr ) free( name );
1126     return( im );
1127   }
1128   /* could read header and data */
1129   else if ( res > 0 ) {
1130     ImageIO_close(im);
1131     if ( name != nullptr ) free( name );
1132     return im;
1133   }
1134 
1135   /* could not read error : throw error */
1136   fprintf(stderr, "_readImageHeaderAndGetError: an error occurs when reading image\n" );
1137   if ( name == nullptr || im->openMode == OM_STD) {
1138     fprintf(stderr, "\t from \'standard input\'" );
1139   }
1140   else {
1141     fprintf(stderr, "\t from file \'%s\'", name );
1142   }
1143   fprintf(stderr, " using format \'%s\'\n", (im->imageFormat)->realName );
1144   ImageIO_close( im );
1145   _freeImage(im);
1146   *error = ImageIO_READING_HEADER;
1147   if ( name != nullptr ) free( name );
1148   return nullptr;
1149 
1150 }
1151 
1152 
1153 
1154 
1155 
1156 
1157 
1158 CGAL_INLINE_FUNCTION
_swapImageData(_image * im)1159 static void _swapImageData( _image *im )
1160 {
1161   unsigned char *ptr1, *ptr2, b[8];
1162   unsigned short int si, *ptr3, *ptr4;
1163   unsigned int        i, *ptr5, *ptr6;
1164   std::size_t size, length;
1165 
1166   if( _getEndianness() != im->endianness) {
1167 
1168     size = std::size_t(im->xdim) * im->ydim * im->zdim * im->vdim * im->wdim;
1169     if ( size <= 0 ) return;
1170 
1171     length = size / im->wdim;
1172     ptr1 = ptr2 = (unsigned char *) im->data;
1173 
1174     /* 2 bytes swap */
1175     if(im->wdim == 2) {
1176       /*
1177         while(length--) {
1178         b[0] = *ptr1++;
1179         b[1] = *ptr1++;
1180         *ptr2++ = b[1];
1181         *ptr2++ = b[0];
1182         }
1183       */
1184       ptr3 = ptr4 = (unsigned short int *) im->data;
1185       while( length-- ) {
1186         si = *ptr3++;
1187         *ptr4++ = (unsigned short int)(((si >> 8) & 0xff) | (si << 8));
1188       }
1189     }
1190 
1191     /* 4 bytes swap */
1192     else if(im->wdim == 4) {
1193       /*
1194         while(length--) {
1195         b[0] = *ptr1++;
1196         b[1] = *ptr1++;
1197         b[2] = *ptr1++;
1198         b[3] = *ptr1++;
1199         *ptr2++ = b[3];
1200         *ptr2++ = b[2];
1201         *ptr2++ = b[1];
1202         *ptr2++ = b[0];
1203         }
1204       */
1205       ptr5 = ptr6 = (unsigned int *) im->data;
1206       while( length-- ) {
1207         i = *ptr5++;
1208         *ptr6++ =  (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | ((i >> 24) & 0xff);
1209       }
1210     }
1211     /* 8 bytes swap */
1212     else if(im->wdim == 8) {
1213       while(length--) {
1214         b[0] = *ptr1++;
1215         b[1] = *ptr1++;
1216         b[2] = *ptr1++;
1217         b[3] = *ptr1++;
1218         b[4] = *ptr1++;
1219         b[5] = *ptr1++;
1220         b[6] = *ptr1++;
1221         b[7] = *ptr1++;
1222         *ptr2++ = b[7];
1223         *ptr2++ = b[6];
1224         *ptr2++ = b[5];
1225         *ptr2++ = b[4];
1226         *ptr2++ = b[3];
1227         *ptr2++ = b[2];
1228         *ptr2++ = b[1];
1229         *ptr2++ = b[0];
1230       }
1231     }
1232   }
1233 }
1234 
1235 
1236 
1237 
1238 
1239 
1240 /* Read data of an inrimage.
1241    If im->data is not nullptr, assume that the buffer was previously allocated
1242    Swap bytes depending on the endianness and the current architecture  */
1243 CGAL_INLINE_FUNCTION
_readImageData(_image * im)1244 int _readImageData(_image *im) {
1245   unsigned long size, nread;
1246 
1247   if(im->openMode != OM_CLOSE) {
1248     size = im->xdim * im->ydim * im->zdim * im->vdim * im->wdim;
1249 
1250     if ( size <= 0 ) return -3;
1251 
1252     if(!im->data) {
1253       im->data = (unsigned char *) ImageIO_alloc(size);
1254       if(!im->data) return -2;
1255     }
1256 
1257     nread = ImageIO_read(im, im->data, size);
1258     if(nread != size) return -1;
1259 
1260 
1261     /* architecture is big endian and data little endian
1262        length = nb of points
1263      */
1264     _swapImageData( im );
1265 
1266 
1267   }
1268 
1269   return 1;
1270 }
1271 
1272 
1273 
1274 
1275 
1276 /* Read data of a vectorial inrimage, making the resulting buffer non-
1277    inerlaced.
1278    If im->data is not nullptr, assume that the buffer was previously allocated
1279    Swap bytes depending on the endianness and the current architecture. */
1280 CGAL_INLINE_FUNCTION
_readNonInterlacedImageData(_image * im)1281 int _readNonInterlacedImageData(_image *im) {
1282   unsigned long size, nread;
1283   unsigned char **vp, *buf;
1284   unsigned int i, j, k, v, w;
1285 
1286   if(im->vdim == 1) return _readImageData(im);
1287 
1288   if(im->openMode != OM_CLOSE) {
1289     size = im->xdim * im->ydim * im->zdim * im->vdim * im->wdim;
1290 
1291     if ( size <= 0 ) return -3;
1292 
1293     if(!im->data) {
1294       im->data = (unsigned char *) ImageIO_alloc(size);
1295       if(!im->data) return -2;
1296     }
1297 
1298     vp = (unsigned char **) ImageIO_alloc(im->vdim * sizeof(unsigned char *));
1299     buf = (unsigned char *) ImageIO_alloc(im->vdim * im->wdim);
1300     size = im->xdim * im->ydim * im->zdim * im->wdim;
1301     for(v = 0; v < im->vdim; v++)
1302       vp[v] = (unsigned char *) im->data + v * size;
1303 
1304     for(k = 0; k < im->zdim; k++) {
1305       for(j = 0; j < im->ydim; j++) {
1306         for(i = 0; i < im->xdim; i++) {
1307           nread = ImageIO_read(im, buf, im->vdim * im->wdim);
1308           if(nread != im->vdim * im->wdim) return -1;
1309           for(v = 0; v < im->vdim; v++)
1310             for(w = 0; w < im->wdim; w++)
1311               *vp[v]++ = *buf++;
1312           buf -= im->vdim * im->wdim;
1313         }
1314       }
1315     }
1316 
1317     ImageIO_free(buf);
1318     ImageIO_free(vp);
1319 
1320     /* architecture is big endian and data little endian */
1321     _swapImageData( im );
1322 
1323 
1324     /* reorder lines */
1325     /* no non-interlaced data for ANALYZE. But if ever... */
1326 /*     if( im->imageFormat == IF_ANALYZE ) { */
1327 /*        int v ; */
1328 /*        int vdim = im->vdim ; */
1329 /*        int lineSize = im->wdim * im->xdim ; */
1330 /*        int vsize = lineSize * im->ydim * im->zdim ; */
1331 /*        char* swapped = ImageIO_alloc(lineSize) ; */
1332 /*        for( v = 0 ; v < vdim ; ++v ) */
1333 /*        { */
1334 /*           char* buf1 = (char*)im->data + v*vsize ; */
1335 /*           char* buf2 = buf1 + vsize - lineSize ; */
1336 
1337 /*           while( buf1 < buf2 ) */
1338 /*           { */
1339 /*              memcpy( swapped, buf1, lineSize ) ; */
1340 /*              memcpy( buf1, buf2, lineSize ) ; */
1341 /*              memcpy( buf2, swapped, lineSize ) ; */
1342 /*              buf1 += lineSize ; */
1343 /*              buf2 -= lineSize ; */
1344 /*           } */
1345 
1346 /*           ImageIO_free( swapped ) ; */
1347 /*        } */
1348 /*     } */
1349   }
1350 
1351   return 1;
1352 }
1353 
1354 
1355 /* Reads body from a non-interlaced vectorial inrimage whose header has
1356    been read by _readImageHeader. The image buffer is interlaced. */
1357 CGAL_INLINE_FUNCTION
_readNonInterlacedFileData(_image * im)1358 int _readNonInterlacedFileData(_image *im) {
1359   unsigned long size, nread;
1360   unsigned char *ptr1, *vp, *buf;
1361   unsigned int i, j, k, v, w;
1362 
1363   if(im->vdim == 1) return _readImageData(im);
1364 
1365   if(im->openMode != OM_CLOSE) {
1366     size = im->xdim * im->ydim * im->zdim * im->vdim * im->wdim;
1367 
1368     if ( size <= 0 ) return -3;
1369 
1370     if(!im->data) {
1371       im->data = (unsigned char *) ImageIO_alloc(size);
1372       if(!im->data) return -2;
1373     }
1374 
1375     size = im->xdim * im->ydim * im->zdim * im->wdim;
1376     buf = ptr1 = (unsigned char *) ImageIO_alloc(size);
1377 
1378     for(v = 0; v < im->vdim; v++) {
1379       buf = ptr1;
1380       nread = ImageIO_read(im, buf, size);
1381       if(nread != size) return -1;
1382       vp = (unsigned char *) im->data + (v * im->wdim);
1383       for(k = 0; k < im->zdim; k++) {
1384         for(j = 0; j < im->ydim; j++) {
1385           for(i = 0; i < im->xdim; i++) {
1386             for(w = 0; w < im->wdim; w++) *vp++ = *buf++;
1387             vp += (im->vdim - 1) * im->wdim;
1388           }
1389         }
1390       }
1391     }
1392 
1393     ImageIO_free(buf);
1394 
1395     /* architecture is big endian and data little endian */
1396     _swapImageData( im );
1397 
1398 
1399     /* reorder lines */
1400     /* no non-interlaced data for ANALYZE. But if ever... */
1401 /*     if( im->imageFormat == IF_ANALYZE ) { */
1402 /*        int v ; */
1403 /*        int vdim = im->vdim ; */
1404 /*        int lineSize = im->wdim * im->xdim ; */
1405 /*        int vsize = lineSize * im->ydim * im->zdim ; */
1406 /*        char* swapped = ImageIO_alloc(lineSize) ; */
1407 /*        for( v = 0 ; v < vdim ; ++v ) */
1408 /*        { */
1409 /*           char* buf1 = (char*)im->data + v*vsize ; */
1410 /*           char* buf2 = buf1 + vsize - lineSize ; */
1411 
1412 /*           while( buf1 < buf2 ) */
1413 /*           { */
1414 /*              memcpy( swapped, buf1, lineSize ) ; */
1415 /*              memcpy( buf1, buf2, lineSize ) ; */
1416 /*              memcpy( buf2, swapped, lineSize ) ; */
1417 /*              buf1 += lineSize ; */
1418 /*              buf2 -= lineSize ; */
1419 /*           } */
1420 
1421 /*           ImageIO_free( swapped ) ; */
1422 /*        } */
1423 /*     } */
1424   }
1425 
1426   return 1;
1427 }
1428 
1429 
1430 
1431 
1432 
1433 
1434 
1435 
1436 
1437 
1438 /*--------------------------------------------------
1439  *
1440  * ?????
1441  *
1442  --------------------------------------------------*/
1443 
1444 
1445 
1446 
1447 
1448 /* check the type of image in fileName */
1449 CGAL_INLINE_FUNCTION
imageType(const char * fileName)1450 PTRIMAGE_FORMAT imageType(const char *fileName) {
1451   _ImageIO_file f;
1452   char magic[5];
1453   PTRIMAGE_FORMAT format;
1454 
1455   if(!fileName) {
1456 #ifdef CGAL_USE_ZLIB
1457     f = gzdopen(fileno(stdin), "rb");
1458 #else
1459     f = fdopen(fileno(stdin), "rb");
1460 #endif
1461   }
1462   else {
1463 #ifdef CGAL_USE_ZLIB
1464     f = gzopen(fileName, "rb");
1465 #else
1466     f = fopen(fileName, "rb");
1467 #endif
1468   }
1469 
1470   if(!f) return nullptr;
1471 
1472 #ifdef CGAL_USE_ZLIB
1473   gzread( f, (void *) magic, 4);
1474 #else
1475   fread( (void *) magic, 1, 4, f );
1476 #endif
1477 
1478 
1479   magic[4] = '\0';
1480 
1481 #ifdef CGAL_USE_ZLIB
1482   gzclose( f );
1483 #else
1484   if(fileName) fclose( f );
1485 #endif
1486 
1487   if (get_static_firstFormat()==nullptr)
1488     initSupportedFileFormat();
1489 
1490   for(format=get_static_firstFormat();(format!=nullptr);format=format->next) {
1491     /* test if it is the correct header based on magic and file extension */
1492     if (((*format->testImageFormat)(magic,fileName)) >=0) {
1493       return format;
1494     }
1495   }
1496   return 0;
1497 
1498 }
1499 
1500 
1501 
1502 
1503 
1504 /*--------------------------------------------------
1505  *
1506  * Image Format Management
1507  *
1508  --------------------------------------------------*/
1509 
1510 
1511 
1512 
1513 
1514 /** adds a format at the beginning of the list of image formats.
1515     Test if all mandatory fields have been filled */
1516 CGAL_INLINE_FUNCTION
addImageFormat(PTRIMAGE_FORMAT format)1517 int addImageFormat( PTRIMAGE_FORMAT format)
1518 {
1519   if ( (format->testImageFormat) &&
1520        (format->readImageHeader) &&
1521        (strlen(format->fileExtension)>0) &&
1522        (strlen(format->realName)>0) ) {
1523 
1524     format->next=get_static_firstFormat();
1525     get_static_firstFormat()=format;
1526 
1527     return 0;
1528 
1529   }
1530   else {
1531     fprintf(stderr,"addImageFormat: information missing in file format %s\n",
1532             format->realName);
1533     return -1;
1534   }
1535 }
1536 
1537 /** adds a format at the end of the list of image formats.
1538     Test if all mandatory fields have been filled */
1539 CGAL_INLINE_FUNCTION
addImageFormatAtEnd(PTRIMAGE_FORMAT format)1540 int addImageFormatAtEnd( PTRIMAGE_FORMAT format)
1541 {
1542   PTRIMAGE_FORMAT f;
1543   if ( (format->testImageFormat) &&
1544        (format->readImageHeader) &&
1545        (strlen(format->fileExtension)>0) &&
1546        (strlen(format->realName)>0) ) {
1547 
1548     format->next = nullptr;
1549 
1550     if (get_static_firstFormat() == nullptr) {
1551       get_static_firstFormat()=format;
1552     }
1553     else {
1554       for(f=get_static_firstFormat();(f->next!=nullptr);f=f->next)
1555         ;
1556       f->next=format;
1557     }
1558 
1559     return 0;
1560 
1561   }
1562   else {
1563     fprintf(stderr,"addImageFormatAtEnd: information missing in file format %s\n",
1564             format->realName);
1565     return -1;
1566   }
1567 }
1568 
1569 
1570 /** creates supported image formats */
1571 CGAL_INLINE_FUNCTION
initSupportedFileFormat()1572 void initSupportedFileFormat()
1573 {
1574   PTRIMAGE_FORMAT f;
1575   if ( get_static_inrimageFormat() == nullptr ) {
1576     f = createAnalyzeFormat();
1577     addImageFormatAtEnd( f );
1578     f = createBMPFormat();
1579     addImageFormatAtEnd( f );
1580     f = createGifFormat();
1581     addImageFormatAtEnd( f );
1582     f = createGisFormat();
1583     addImageFormatAtEnd( f );
1584     f = createIrisFormat();
1585     addImageFormatAtEnd( f );
1586     f = createPgmFormat();
1587     addImageFormatAtEnd( f );
1588     f = createPgmAscIIFormat();
1589     addImageFormatAtEnd( f );
1590     f = createPpmFormat();
1591     addImageFormatAtEnd( f );
1592     get_static_inrimageFormat() = createInrimageFormat();
1593     addImageFormat( get_static_inrimageFormat() );
1594   }
1595 }
1596 
1597 
1598 
1599 CGAL_INLINE_FUNCTION
firstImageFormat()1600 PTRIMAGE_FORMAT firstImageFormat() {
1601   return get_static_firstFormat();
1602 }
1603 
1604 
1605 
1606 /** prints supported image formats */
1607 CGAL_INLINE_FUNCTION
printSupportedFileFormat()1608 void printSupportedFileFormat() {
1609   PTRIMAGE_FORMAT f;
1610   int i;
1611 
1612   initSupportedFileFormat();
1613 
1614   for(i=0, f=get_static_firstFormat();(f!=nullptr);i++, f=f->next) {
1615     if ( (f->testImageFormat) &&
1616          (f->readImageHeader) &&
1617          (strlen(f->fileExtension)>0) &&
1618          (strlen(f->realName)>0)) {
1619       fprintf( stderr, "#%2d: format name ='%s', extensions='%s'",
1620               i, f->realName, f->fileExtension );
1621       if (f->readImageHeader)
1622         fprintf( stderr, ", read" );
1623       if (f->writeImage)
1624         fprintf( stderr, ", write" );
1625       fprintf( stderr, "\n" );
1626     }
1627   }
1628 }
1629 
1630 
1631 /** remove supported image formats */
1632 CGAL_INLINE_FUNCTION
removeSupportedFileFormat()1633 void removeSupportedFileFormat() {
1634   PTRIMAGE_FORMAT f=get_static_firstFormat();
1635 
1636   while( f != nullptr) {
1637     PTRIMAGE_FORMAT f_old = f;
1638     f = f->next;
1639     ImageIO_free( f_old);
1640   }
1641   get_static_inrimageFormat()=nullptr;
1642 
1643 }
1644 
1645 
1646 /** trilinear interpolation in an _image float type
1647  */
1648 CGAL_INLINE_FUNCTION
triLinInterp(const _image * image,float posx,float posy,float posz,float value_outside)1649 float triLinInterp(const _image* image,
1650                    float posx,
1651                    float posy,
1652                    float posz,
1653                    float value_outside /*= 0.f */)
1654 {
1655   const std::size_t dimx = image->xdim;
1656   const std::size_t dimy = image->ydim;
1657   const std::size_t dimz = image->zdim;
1658   const std::size_t dimxy = dimx*dimy;
1659 
1660   if(posx < 0.f || posy < 0.f || posz < 0.f )
1661     return value_outside;
1662 
1663   posx = static_cast<float>(posx /(image->vx));
1664   posy = static_cast<float>(posy /(image->vy));
1665   posz = static_cast<float>(posz /(image->vz));
1666 
1667   //patch suggested by J.Cugnoni to prevent integer overflow
1668   if(posz >= float(dimz-1) || posy >= float(dimy-1) || posx >= float(dimx-1))
1669     return value_outside;
1670 
1671   const int i1 = (int)(posz);
1672   const int j1 = (int)(posy);
1673   const int k1 = (int)(posx);
1674 
1675   const int i2 = i1 + 1;
1676   const int j2 = j1 + 1;
1677   const int k2 = k1 + 1;
1678 
1679   const float KI2 = float(i2)-posz;
1680   const float KI1 = posz-float(i1);
1681   const float KJ2 = float(j2)-posy;
1682   const float KJ1 = posy-float(j1);
1683 
1684   CGAL_IMAGE_IO_CASE
1685     (image,
1686      Word *array = (Word *) image->data;
1687      return (((float)array[i1 * dimxy + j1 * dimx + k1] * KI2 +
1688               (float)array[i2 * dimxy + j1 * dimx + k1] * KI1) * KJ2 +
1689              ((float)array[i1 * dimxy + j2 * dimx + k1] * KI2 +
1690               (float)array[i2 * dimxy + j2 * dimx + k1] * KI1) * KJ1) * (float(k2)-posx)+
1691      (((float)array[i1 * dimxy + j1 * dimx + k2] * KI2 +
1692        (float)array[i2 * dimxy + j1 * dimx + k2] * KI1) * KJ2 +
1693       ((float)array[i1 * dimxy + j2 * dimx + k2] * KI2 +
1694        (float)array[i2 * dimxy + j2 * dimx + k2] * KI1) * KJ1) * (posx-float(k1));
1695      );
1696   return 0.f;
1697 }
1698 
1699 // Gives the value of the image at pixel (i,j,k), converted in float.
1700 CGAL_INLINE_FUNCTION
evaluate(const _image * image,const std::size_t i,const std::size_t j,const std::size_t k)1701 float evaluate(const _image* image,
1702                const std::size_t i,
1703                const std::size_t j,
1704                const std::size_t k)
1705 {
1706   using CGAL::IMAGEIO::static_evaluate;
1707 
1708   CGAL_IMAGE_IO_CASE(image, return (float)static_evaluate<Word>(image, i, j, k); );
1709 
1710   return 0.f;
1711 }
1712 
1713 /** convert the data of the image to float
1714 */
1715 CGAL_INLINE_FUNCTION
convertImageTypeToFloat(_image * image)1716 void convertImageTypeToFloat(_image* image){
1717   if(image->wordKind == WK_FLOAT && image->wdim == 4)
1718     return;
1719 
1720   const std::size_t dimx = image->xdim;
1721   const std::size_t dimy = image->ydim;
1722   const std::size_t dimz = image->zdim;
1723 
1724   float * array = (float*)ImageIO_alloc (dimx * dimy * dimz *sizeof(float));
1725   if (array == nullptr ) {
1726     fprintf ( stderr, "allocation error\n" );
1727     return;
1728   }
1729 
1730   CGAL_IMAGE_IO_CASE
1731     (image,
1732      Word * typedArray  = (Word *)(image->data);
1733      for(unsigned int i = 0; i<dimx * dimy * dimz;++i)
1734        array[i] = (float)(typedArray[i]);
1735      );
1736 
1737   ImageIO_free ( image->data );
1738   image->data = array;
1739 
1740   image->wordKind = WK_FLOAT;
1741   image->wdim = 4;
1742 }
1743 
1744