root / ImageMagick / trunk / coders / ipl.c

Revision 12035, 22.2 kB (checked in by cristy, 6 days ago)
Line 
1/*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                     IIIIIIIIII    PPPPPPPP      LL                          %
7 %                         II        PP      PP    LL                          %
8 %                         II        PP       PP   LL                          %
9 %                         II        PP      PP    LL                          %
10 %                         II        PPPPPPPP      LL                          %
11 %                         II        PP            LL                          %
12 %                         II        PP            LL                          %
13 %                     IIIIIIIIII    PP            LLLLLLLL                    %
14 %                                                                             %
15 %                                                                             %
16 %                                                                             %
17 %                   Read/Write Scanalytics IPLab Image Format                 %
18 %                                  Sean Burke                                 %
19 %                                  2008.05.07                                 %
20 %                                     v 0.9                                   %
21 %                                                                             %
22 %  Copyright 1999-2007 ImageMagick Studio LLC, a non-profit organization      %
23 %  dedicated to making software imaging solutions freely available.           %
24 %                                                                             %
25 %  You may not use this file except in compliance with the License.  You may  %
26 %  obtain a copy of the License at                                            %
27 %                                                                             %
28 %    http://www.imagemagick.org/script/license.php                            %
29 %                                                                             %
30 %  Unless required by applicable law or agreed to in writing, software        %
31 %  distributed under the License is distributed on an "AS IS" BASIS,          %
32 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
33 %  See the License for the specific language governing permissions and        %
34 %  limitations under the License.                                             %
35 %                                                                             %
36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 %
38 %
39 */
40
41/*
42 Include declarations.
43 */
44#include "magick/studio.h"
45#include "magick/blob.h"
46#include "magick/blob-private.h"
47#include "magick/colorspace.h"
48#include "magick/exception.h"
49#include "magick/exception-private.h"
50#include "magick/image.h"
51#include "magick/image-private.h"
52#include "magick/list.h"
53#include "magick/magick.h"
54#include "magick/memory_.h"
55#include "magick/monitor.h"
56#include "magick/monitor-private.h"
57#include "magick/option.h"
58#include "magick/property.h"
59#include "magick/quantum-private.h"
60#include "magick/static.h"
61#include "magick/string_.h"
62#include "magick/module.h"
63
64/*
65Tyedef declarations
66 */
67
68typedef struct _IPLInfo
69{
70  unsigned long
71  tag,
72  size,
73  time,
74  z,
75  width,
76  height,
77  colors,
78  depth,
79  byteType;
80} IPLInfo;
81
82static MagickBooleanType
83  WriteIPLImage(const ImageInfo *,Image *);
84
85void increase (void *pixel, int byteType){
86  switch(byteType){
87    case 0:(*((unsigned char *) pixel))++; break;
88    case 1:(*((signed int *) pixel))++; break;
89    case 2:(*((unsigned int *) pixel))++; break;
90    case 3:(*((signed long *) pixel))++; break;
91    default:(*((unsigned int *) pixel))++; break;
92  } 
93}
94
95/*
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97 %                                                                             %
98 %                                                                             %
99 %                                                                             %
100 %   I s I P L                                                                 %
101 %                                                                             %
102 %                                                                             %
103 %                                                                             %
104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105 %
106 %  IsIPL() returns MagickTrue if the image format type, identified by the
107 %  magick string, is IPL.
108 %
109 %  The format of the IsIPL method is:
110 %
111 %      MagickBooleanType IsIPL(const unsigned char *magick,const size_t length)
112 %
113 %  A description of each parameter follows:
114 %
115 %    o magick: This string is generally the first few bytes of an image file
116 %      or blob.
117 %
118 %    o length: Specifies the length of the magick string.
119 %
120 */
121static MagickBooleanType IsIPL(const unsigned char *magick,const size_t length)
122{
123  if (length < 4)
124    return(MagickFalse);
125  if (LocaleNCompare((char *) magick,"data",4) == 0)
126    return(MagickTrue);
127  return(MagickFalse);
128}
129
130/*
131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132 %                                                                             %
133 %                                                                             %
134 %                                                                             %
135 %    R e a d I P L I m a g e                                                  %
136 %                                                                             %
137 %                                                                             %
138 %                                                                             %
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140 %
141 %  ReadIPLImage() reads a Scanalytics IPLab image file and returns it.  It
142 %  allocates the memory necessary for the new Image structure and returns a
143 %  pointer to the new image.
144 %
145 %  According to the IPLab spec, the data is blocked out in five dimensions:
146 %  { t, z, c, y, x }.  When we return the image, the latter three are folded
147 %  into the standard "Image" structure.  The "scenes" (image_info->scene)
148 %  correspond to the order: { {t0,z0}, {t0, z1}, ..., {t1,z0}, {t1,z1}... }
149 %  The number of scenes is t*z.
150 %
151 %  The format of the ReadIPLImage method is:
152 %
153 %      Image *ReadIPLImage(const ImageInfo *image_info,ExceptionInfo *exception)
154 %
155 %  A description of each parameter follows:
156 %
157 %    o image_info: The image info.
158 %
159 %    o exception: return any errors or warnings in this structure.
160 %
161 */
162
163void SetHeaderFromIPL(Image *image, IPLInfo *ipl){
164        image->columns = ipl->width;
165        image->rows = ipl->height;
166        image->depth = ipl->depth;
167        image->x_resolution = 1;
168        image->y_resolution = 1;
169}
170
171
172static Image *ReadIPLImage(const ImageInfo *image_info,ExceptionInfo *exception)
173{
174 
175  /*
176  Declare variables
177   */
178  Image *image;
179
180  MagickBooleanType status;
181  register PixelPacket *q;
182  unsigned char magick[12], *pixels;
183  ssize_t count;
184  long y;
185  unsigned long t_count=0;
186  size_t length;
187  IPLInfo
188    ipl_info;
189  QuantumFormatType
190    quantum_format;
191  QuantumInfo
192    *quantum_info;
193  QuantumType
194    quantum_type;
195
196  /*
197   Open Image
198   */
199
200  assert(image_info != (const ImageInfo *) NULL);
201  assert(image_info->signature == MagickSignature);
202  if ( image_info->debug != MagickFalse)
203    (void) LogMagickEvent(TraceEvent, GetMagickModule(), "%s",
204                image_info->filename);
205  assert(exception != (ExceptionInfo *) NULL);
206  assert(exception->signature == MagickSignature);
207  image=AcquireImage(image_info);
208  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
209  if (status == MagickFalse)
210  {
211    image=DestroyImageList(image);
212    return((Image *) NULL);
213  }
214 
215  /*
216   Read IPL image
217   */
218
219  /*
220    Determine endianness
221   If we get back "iiii", we have LSB,"mmmm", MSB
222   */
223  count=ReadBlob(image,4,magick);
224  if((LocaleNCompare((char *) magick,"iiii",4) == 0)) 
225    image->endian=LSBEndian;
226  else{
227    if((LocaleNCompare((char *) magick,"mmmm",4) == 0))
228      image->endian=MSBEndian;
229    else{
230      ThrowReaderException(CorruptImageError, "ImproperImageHeader");
231    }
232  }
233  /* Skip o'er the next 8 bytes (garbage) */
234  count=ReadBlob(image, 8, magick);
235  /*
236   Excellent, now we read the header unimpeded.
237   */
238  count=ReadBlob(image,4,magick);
239  if((LocaleNCompare((char *) magick,"data",4) != 0)) 
240    ThrowReaderException(CorruptImageError, "ImproperImageHeader");
241  ipl_info.size=ReadBlobLong(image);
242  ipl_info.width=ReadBlobLong(image);
243  ipl_info.height=ReadBlobLong(image);
244  if((ipl_info.width == 0UL) || (ipl_info.height == 0UL))
245    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
246  ipl_info.colors=ReadBlobLong(image);
247  if(ipl_info.colors == 3){ image->colorspace=RGBColorspace;}
248  else { image->colorspace = GRAYColorspace; }
249  ipl_info.z=ReadBlobLong(image);
250  ipl_info.time=ReadBlobLong(image);
251
252  ipl_info.byteType=ReadBlobLong(image);
253
254
255  /* Initialize Quantum Info */
256
257  switch (ipl_info.byteType) {
258    case 0:
259      ipl_info.depth=8;
260      quantum_format = UnsignedQuantumFormat;
261      break;
262    case 1:
263      ipl_info.depth=16;
264      quantum_format = SignedQuantumFormat;
265      break;
266    case 2:
267      ipl_info.depth=16;
268      quantum_format = UnsignedQuantumFormat;
269      break;
270    case 3:
271      ipl_info.depth=32;
272      quantum_format = SignedQuantumFormat;
273      break;
274    case 4: ipl_info.depth=32;
275      quantum_format = FloatingPointQuantumFormat;
276      break;
277    case 5:
278      ipl_info.depth=8;
279      quantum_format = UnsignedQuantumFormat;
280      break;
281    case 6:
282      ipl_info.depth=16;
283      quantum_format = UnsignedQuantumFormat;
284      break;
285    case 10
286      ipl_info.depth=64;
287      quantum_format = FloatingPointQuantumFormat;
288      break;
289    default:
290      ipl_info.depth=16;
291      quantum_format = UnsignedQuantumFormat;
292      break;
293  }
294
295  /*
296    Set number of scenes of image
297  */
298
299  SetHeaderFromIPL(image, &ipl_info);
300
301  /* Thats all we need if we are pinging. */
302  if (image_info->ping != MagickFalse)
303  {
304    (void) CloseBlob(image);
305    return(GetFirstImageInList(image));
306  }
307  length=image->columns;
308  quantum_type=GetQuantumType(image,exception);
309 do
310  {
311    SetHeaderFromIPL(image, &ipl_info);
312
313  if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
314      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
315        break;
316  if (SetImageExtent(image,0,0) == MagickFalse)
317    {
318      InheritException(exception,&image->exception);
319      return(DestroyImageList(image));
320    }
321/*
322   printf("Length: %lu, Memory size: %lu\n", length,(unsigned long)(image->depth));
323*/
324     quantum_info=AcquireQuantumInfo(image_info,image);
325     (void) SetQuantumFormat(image,quantum_format,quantum_info);
326     pixels=GetQuantumPixels(quantum_info);
327     if(image->columns != ipl_info.width){
328/*
329                printf("Columns not set correctly!  Wanted: %lu, got: %lu\n",
330                        ipl_info.width, image->columns);
331*/
332     }
333
334    /*
335    Covert IPL binary to pixel packets
336     */
337   
338  if(ipl_info.colors == 1){
339      for(y = 0; y < (long) image->rows; y++){
340        (void) ReadBlob(image, length*image->depth/8, pixels);
341        q=SetImagePixels(image,0,y,image->columns,1);
342        if (q == (PixelPacket *) NULL)
343                break;
344        (void) ImportQuantumPixels(image,quantum_info,GrayQuantum,pixels);
345          if (SyncImagePixels(image) == MagickFalse)
346                  break;
347        }
348  }
349  else{
350      for(y = 0; y < (long) image->rows; y++){
351        (void) ReadBlob(image, length*image->depth/8, pixels);
352        q=SetImagePixels(image,0,y,image->columns,1);
353        if (q == (PixelPacket *) NULL)
354                break;
355        (void) ImportQuantumPixels(image,quantum_info,RedQuantum,pixels);       
356        if (SyncImagePixels(image) == MagickFalse)
357          break;
358      }
359      for(y = 0; y < (long) image->rows; y++){
360        (void) ReadBlob(image, length*image->depth/8, pixels);
361        q=SetImagePixels(image,0,y,image->columns,1);
362        if (q == (PixelPacket *) NULL)
363                break;
364        (void) ImportQuantumPixels(image,quantum_info,GreenQuantum,pixels);
365        if (SyncImagePixels(image) == MagickFalse)
366          break;
367      }
368      for(y = 0; y < (long) image->rows; y++){
369        (void) ReadBlob(image, length*image->depth/8, pixels);
370        q=SetImagePixels(image,0,y,image->columns,1);
371        if (q == (PixelPacket *) NULL)
372                break;
373        (void) ImportQuantumPixels(image,quantum_info,BlueQuantum,pixels);
374        if (SyncImagePixels(image) == MagickFalse)
375          break;
376      }
377   }
378   SetQuantumImageType(image,quantum_type);
379 
380    t_count++;
381  quantum_info = DestroyQuantumInfo(quantum_info);
382
383    if (EOFBlob(image) != MagickFalse)
384    {
385      ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
386                 image->filename);
387      break;
388    }
389   if(t_count < ipl_info.z * ipl_info.time){
390      /*
391       Proceed to next image.
392       */
393      AcquireNextImage(image_info, image);
394      if (GetNextImageInList(image) == (Image *) NULL)
395      {
396        image=DestroyImageList(image);
397        return((Image *) NULL);
398      }
399      image=SyncNextImageInList(image);
400      status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
401        GetBlobSize(image));
402      if (status == MagickFalse)
403        break;
404    }
405  } while (t_count < ipl_info.z*ipl_info.time);
406  CloseBlob(image);
407  return(GetFirstImageInList(image));
408}
409
410/*
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412 %                                                                             %
413 %                                                                             %
414 %                                                                             %
415 %   R e g i s t e r I P L I m a g e                                           %
416 %                                                                             %
417 %                                                                             %
418 %                                                                             %
419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
420 %
421 % RegisterIPLImage() add attributes for the Scanalytics IPL image format to the
422 % list of supported formats. 
423 %
424 %
425 */
426ModuleExport unsigned long RegisterIPLImage(void)
427{
428  MagickInfo
429    *entry;
430 
431  entry=SetMagickInfo("IPL");
432  entry->decoder=(DecodeImageHandler *) ReadIPLImage;
433  entry->encoder=(EncodeImageHandler *) WriteIPLImage;
434  entry->magick=(IsImageFormatHandler *) IsIPL;
435  entry->adjoin=MagickTrue;
436  entry->description=ConstantString("IPL Image Sequence");
437  entry->module=ConstantString("IPL");
438  entry->endian_support=MagickTrue;
439  (void) RegisterMagickInfo(entry);
440  return(MagickImageCoderSignature);
441}
442
443/*
444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
445 %                                                                             %
446 %                                                                             %
447 %                                                                             %
448 %   U n r e g i s t e r I P L I m a g e                                       %
449 %                                                                             %
450 %                                                                             %
451 %                                                                             %
452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
453 %
454 %  UnregisterIPLImage() removes format registrations made by the
455 %  IPL module from the list of supported formats.
456 %
457 %  The format of the UnregisterIPLImage method is:
458 %
459 %      UnregisterIPLImage(void)
460 %
461 */
462ModuleExport void UnregisterIPLImage(void)
463{
464  (void) UnregisterMagickInfo("IPL");
465}
466
467/*
468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469 %                                                                             %
470 %                                                                             %
471 %                                                                             %
472 %   W r i t e I P L I m a g e                                                 %
473 %                                                                             %
474 %                                                                             %
475 %                                                                             %
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477 %
478 %  WriteIPLImage() writes an image to a file in Scanalytics IPLabimage format.
479 %
480 %  The format of the WriteIPLImage method is:
481 %
482 %      MagickBooleanType WriteIPLImage(const ImageInfo *image_info,Image *image)
483 %
484 %  A description of each parameter follows.
485 %
486 %    o image_info: The image info.
487 %
488 %    o image:  The image.
489 %
490 */
491
492static MagickBooleanType WriteIPLImage(const ImageInfo *image_info,Image *image)
493{
494  MagickBooleanType
495    status;
496 
497  MagickOffsetType
498    scene;
499 
500  register const PixelPacket
501    *p;
502
503  unsigned char
504  *pixels;
505 
506  long
507    y;
508 
509  IPLInfo
510    ipl_info;
511
512  QuantumInfo
513    *quantum_info;
514
515   /*
516    Open output image file.
517  */
518  assert(image_info != (const ImageInfo *) NULL);
519  assert(image_info->signature == MagickSignature);
520  assert(image != (Image *) NULL);
521  assert(image->signature == MagickSignature);
522  if (image->debug != MagickFalse)
523    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
524  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
525  if (status == MagickFalse)
526    return(status);
527  scene=0;
528 
529
530  quantum_info=AcquireQuantumInfo(image_info, image);
531  if ((quantum_info->format == UndefinedQuantumFormat) &&
532      (IsHighDynamicRangeImage(image,&image->exception) != MagickFalse))
533    (void) SetQuantumFormat(image,FloatingPointQuantumFormat,quantum_info);
534  switch(quantum_info->depth){
535  case 8:
536    ipl_info.byteType = 0;
537    break;
538  case 16:
539    if(quantum_info->format == SignedQuantumFormat){
540      ipl_info.byteType = 2;
541    }
542    else{
543      ipl_info.byteType = 1;
544    }
545    break;
546  case 32:
547    if(quantum_info->format == FloatingPointQuantumFormat){
548      ipl_info.byteType = 3;
549    }
550    else{
551      ipl_info.byteType = 4;
552    }
553    break;
554  case 64:
555    ipl_info.byteType = 10;
556    break;
557  default:
558    ipl_info.byteType = 2;
559    break;
560   
561  }
562  ipl_info.z = GetImageListLength(image);
563  /* There is no current method for detecting whether we have T or Z stacks */
564  ipl_info.time = 1;
565  ipl_info.width = image->columns;
566  ipl_info.height = image->rows;
567 
568  if (image->colorspace != RGBColorspace)
569    (void) SetImageColorspace(image,RGBColorspace);
570 
571  if(image->colorspace == RGBColorspace) { ipl_info.colors = 3; }
572  else{ ipl_info.colors = 1; }
573 
574  ipl_info.size = 28 +
575    ((image->depth)/8)*ipl_info.height*ipl_info.width*ipl_info.colors*ipl_info.z;
576 
577  /* Ok!  Calculations are done.  Lets write this puppy down! */
578 
579  /*
580    Write IPL header.
581  */
582  /* Shockingly (maybe not if you have used IPLab),  IPLab itself CANNOT read MSBEndian
583  files!   The reader above can, but they cannot.  For compatability reasons, I will leave
584  the code in here, but it is all but useless if you want to use IPLab. */
585
586  if(image_info->endian == MSBEndian)
587    (void) WriteBlob(image, 4, (unsigned char *) "mmmm");
588  else{
589    image->endian = LSBEndian;
590    (void) WriteBlob(image, 4, (unsigned char *) "iiii");
591  }
592  (void) WriteBlobLong(image, 4);
593  (void) WriteBlob(image, 4, (unsigned char *) "100f");
594  (void) WriteBlob(image, 4, (unsigned char *) "data");
595  (void) WriteBlobLong(image, ipl_info.size);
596  (void) WriteBlobLong(image, ipl_info.width);
597  (void) WriteBlobLong(image, ipl_info.height);
598  (void) WriteBlobLong(image, ipl_info.colors);
599  if(image_info->adjoin == MagickFalse)
600  (void) WriteBlobLong(image, 1);
601  else
602  (void) WriteBlobLong(image, ipl_info.z);
603  (void) WriteBlobLong(image, ipl_info.time);
604  (void) WriteBlobLong(image, ipl_info.byteType);
605 
606
607 
608 do
609    {
610      /*
611  Convert MIFF to IPL raster pixels.
612      */
613      pixels=GetQuantumPixels(quantum_info);
614  if(ipl_info.colors == 1){
615  /* Red frame */
616  for(y = 0; y < (long) ipl_info.height; y++){
617    p=GetImagePixels(image,0,y,image->columns,1);
618    if (p == (PixelPacket *) NULL)
619      break;
620      (void) ExportQuantumPixels(image, quantum_info, GrayQuantum, pixels);
621      (void) WriteBlob(image, image->columns*image->depth/8, pixels);
622  }
623
624}
625  if(ipl_info.colors == 3){
626  /* Red frame */
627  for(y = 0; y < (long) ipl_info.height; y++){
628    p=GetImagePixels(image,0,y,image->columns,1);
629    if (p == (PixelPacket *) NULL)
630      break;
631      (void) ExportQuantumPixels(image, quantum_info, RedQuantum, pixels);
632      (void) WriteBlob(image, image->columns*image->depth/8, pixels);
633  }
634
635    /* Green frame */
636    for(y = 0; y < (long) ipl_info.height; y++){
637      p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
638      if (p == (PixelPacket *) NULL)
639        break;
640        (void) ExportQuantumPixels(image, quantum_info, GreenQuantum, pixels);
641        (void) WriteBlob(image, image->columns*image->depth/8, pixels);
642    }
643    /* Blue frame */
644    for(y = 0; y < (long) ipl_info.height; y++){
645      p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
646      if (p == (PixelPacket *) NULL)
647        break;
648      (void) ExportQuantumPixels(image, quantum_info, BlueQuantum, pixels);
649      (void) WriteBlob(image, image->columns*image->depth/8, pixels);
650      if (image->previous == (Image *) NULL)
651        {
652          status=SetImageProgress(image,SaveImageTag,y,image->rows);
653          if (status == MagickFalse)
654            break;
655        }
656    }
657  }
658  quantum_info=DestroyQuantumInfo(quantum_info);
659      if (GetNextImageInList(image) == (Image *) NULL)
660  break;
661      image=SyncNextImageInList(image);
662      status=SetImageProgress(image,SaveImagesTag,scene++,
663        GetImageListLength(image));
664      if (status == MagickFalse)
665        break;
666    }while (image_info->adjoin != MagickFalse);
667
668  (void) WriteBlob(image, 4, (unsigned char *) "fini");
669  (void) WriteBlobLong(image, 0);
670
671CloseBlob(image);
672return(MagickTrue);
673}
674
Note: See TracBrowser for help on using the browser.