2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10 % CCCC A A LLLLL SSSSS %
13 % Read/Write CALS Raster Group 1 Image Format %
20 % Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 % The CALS raster format is a standard developed by the Computer Aided
37 % Acquisition and Logistics Support (CALS) office of the United States
38 % Department of Defense to standardize graphics data interchange for
39 % electronic publishing, especially in the areas of technical graphics,
40 % CAD/CAM, and image processing applications.
47 #include "magick/studio.h"
48 #include "magick/blob.h"
49 #include "magick/blob-private.h"
50 #include "magick/cache.h"
51 #include "magick/colorspace.h"
52 #include "magick/exception.h"
53 #include "magick/exception-private.h"
54 #include "magick/geometry.h"
55 #include "magick/image.h"
56 #include "magick/image-private.h"
57 #include "magick/list.h"
58 #include "magick/magick.h"
59 #include "magick/memory_.h"
60 #include "magick/monitor.h"
61 #include "magick/monitor-private.h"
62 #include "magick/option.h"
63 #include "magick/quantum-private.h"
64 #include "magick/resource_.h"
65 #include "magick/static.h"
66 #include "magick/string_.h"
67 #include "magick/module.h"
68 #if defined(MAGICKCORE_TIFF_DELEGATE)
69 #if defined(MAGICKCORE_HAVE_TIFFCONF_H)
73 #define CCITTParam "-1"
75 #define CCITTParam "0"
81 static MagickBooleanType
82 WriteCALSImage(const ImageInfo *,Image *);
85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
95 % IsCALS() returns MagickTrue if the image format type, identified by the
96 % magick string, is CALS Raster Group 1.
98 % The format of the IsCALS method is:
100 % MagickBooleanType IsCALS(const unsigned char *magick,const size_t length)
102 % A description of each parameter follows:
104 % o magick: compare image format pattern against these bytes.
106 % o length: Specifies the length of the magick string.
109 static MagickBooleanType IsCALS(const unsigned char *magick,const size_t length)
113 if (LocaleNCompare((const char *) magick,"version: MIL-STD-1840",21) == 0)
115 if (LocaleNCompare((const char *) magick,"srcdocid:",9) == 0)
117 if (LocaleNCompare((const char *) magick,"rorient:",8) == 0)
123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
127 % R e a d C A L S I m a g e %
131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133 % ReadCALSImage() reads an CALS Raster Group 1 image format image file and
134 % returns it. It allocates the memory necessary for the new Image structure
135 % and returns a pointer to the new image.
137 % The format of the ReadCALSImage method is:
139 % Image *ReadCALSImage(const ImageInfo *image_info,
140 % ExceptionInfo *exception)
142 % A description of each parameter follows:
144 % o image_info: the image info.
146 % o exception: return any errors or warnings in this structure.
150 static inline size_t WriteCALSLSBLong(FILE *file,const unsigned int value)
155 buffer[0]=(unsigned char) value;
156 buffer[1]=(unsigned char) (value >> 8);
157 buffer[2]=(unsigned char) (value >> 16);
158 buffer[3]=(unsigned char) (value >> 24);
159 return(fwrite(buffer,1,4,file));
162 #if defined(MAGICKCORE_TIFF_DELEGATE)
163 static Image *Huffman2DDecodeImage(const ImageInfo *image_info,Image *image,
164 ExceptionInfo *exception)
167 filename[MaxTextExtent];
190 Write CALS facsimile document wrapped as a TIFF image file.
193 unique_file=AcquireUniqueFileResource(filename);
194 if (unique_file != -1)
195 file=fdopen(unique_file,"wb");
196 if ((unique_file == -1) || (file == (FILE *) NULL))
197 ThrowImageException(FileOpenError,"UnableToCreateTemporaryFile");
198 length=fwrite("\111\111\052\000\010\000\000\000\016\000",1,10,file);
199 length=fwrite("\376\000\003\000\001\000\000\000\000\000\000\000",1,12,file);
200 length=fwrite("\000\001\004\000\001\000\000\000",1,8,file);
201 length=WriteCALSLSBLong(file,image->columns);
202 length=fwrite("\001\001\004\000\001\000\000\000",1,8,file);
203 length=WriteCALSLSBLong(file,image->rows);
204 length=fwrite("\002\001\003\000\001\000\000\000\001\000\000\000",1,12,file);
205 length=fwrite("\003\001\003\000\001\000\000\000\004\000\000\000",1,12,file);
206 length=fwrite("\006\001\003\000\001\000\000\000\000\000\000\000",1,12,file);
207 length=fwrite("\021\001\003\000\001\000\000\000",1,8,file);
208 strip_offset=10+(12*14)+4+8;
209 length=WriteCALSLSBLong(file,(unsigned long) strip_offset);
210 length=fwrite("\022\001\003\000\001\000\000\000",1,8,file);
211 length=WriteCALSLSBLong(file,(unsigned long) image->orientation);
212 length=fwrite("\025\001\003\000\001\000\000\000\001\000\000\000",1,12,file);
213 length=fwrite("\026\001\004\000\001\000\000\000",1,8,file);
214 length=WriteCALSLSBLong(file,image->columns);
215 length=fwrite("\027\001\004\000\001\000\000\000\000\000\000\000",1,12,file);
216 offset=(ssize_t) ftell(file)-4;
217 length=fwrite("\032\001\005\000\001\000\000\000",1,8,file);
218 length=WriteCALSLSBLong(file,(unsigned long) (strip_offset-8));
219 length=fwrite("\033\001\005\000\001\000\000\000",1,8,file);
220 length=WriteCALSLSBLong(file,(unsigned long) (strip_offset-8));
221 length=fwrite("\050\001\003\000\001\000\000\000\002\000\000\000",1,12,file);
222 length=fwrite("\000\000\000\000",1,4,file);
223 length=WriteCALSLSBLong(file,image->x_resolution);
224 length=WriteCALSLSBLong(file,1);
225 for (length=0; (c=ReadBlobByte(image)) != EOF; length++)
226 (void) fputc(c,file);
227 (void) CloseBlob(image);
228 offset=(ssize_t) fseek(file,(long) offset,SEEK_SET);
229 length=WriteCALSLSBLong(file,(unsigned int) length);
234 read_info=CloneImageInfo(image_info);
235 SetImageInfoBlob(read_info,(void *) NULL,0);
236 (void) FormatMagickString(read_info->filename,MaxTextExtent,"tiff:%.1024s",
238 huffman_image=ReadImage(read_info,exception);
239 if (huffman_image != (Image *) NULL)
241 (void) CopyMagickString(huffman_image->filename,image_info->filename,
243 (void) CopyMagickString(huffman_image->magick_filename,
244 image_info->filename,MaxTextExtent);
245 (void) CopyMagickString(huffman_image->magick,"CALS",MaxTextExtent);
247 read_info=DestroyImageInfo(read_info);
248 (void) RelinquishUniqueFileResource(filename);
249 return(huffman_image);
252 static Image *Huffman2DDecodeImage(const ImageInfo *magick_unused(image_info),
253 Image *image,ExceptionInfo *exception)
255 assert(image != (Image *) NULL);
256 assert(image->signature == MagickSignature);
257 (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError,
258 "DelegateLibrarySupportNotBuiltIn","`%s' (TIFF)",image->filename);
259 return((Image *) NULL);
263 static Image *ReadCALSImage(const ImageInfo *image_info,
264 ExceptionInfo *exception)
291 assert(image_info != (const ImageInfo *) NULL);
292 assert(image_info->signature == MagickSignature);
293 if (image_info->debug != MagickFalse)
294 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
295 image_info->filename);
296 assert(exception != (ExceptionInfo *) NULL);
297 assert(exception->signature == MagickSignature);
298 image=AcquireImage(image_info);
299 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
300 if (status == MagickFalse)
302 image=DestroyImageList(image);
303 return((Image *) NULL);
308 (void) ResetMagickMemory(header,0,sizeof(header));
316 for (i=0; i < 16; i++)
318 if (ReadBlob(image,128,(unsigned char *) header) != 128)
325 if (LocaleNCompare(header,"rdensty:",8) == 0)
327 (void) sscanf(header+8,"%lu",&density);
330 if (LocaleNCompare(header,"rpelcnt:",8) == 0)
332 (void) sscanf(header+8,"%lu,%lu",&width,&height);
335 if (LocaleNCompare(header,"rorient:",8) == 0)
337 (void) sscanf(header+8,"%lu,%lu",&pel_path,&direction);
350 if (LocaleNCompare(header,"rtype:",6) == 0)
352 (void) sscanf(header+6,"%lu",&type);
359 if ((width == 0) || (height == 0) || (type == 0))
360 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
361 image->columns=width;
363 image->x_resolution=(double) density;
364 image->y_resolution=(double) density;
365 image->orientation=(OrientationType) orientation;
366 huffman_image=Huffman2DDecodeImage(image_info,image,exception);
367 image=DestroyImage(image);
368 (void) CloseBlob(huffman_image);
369 if (huffman_image == (Image *) NULL)
370 return(huffman_image);
371 return(GetFirstImageInList(huffman_image));
375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379 % R e g i s t e r C A L S I m a g e %
383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385 % RegisterCALSImage() adds attributes for the CALS Raster Group 1 image file
386 % image format to the list of supported formats. The attributes include the
387 % image format tag, a method to read and/or write the format, whether the
388 % format supports the saving of more than one frame to the same file or blob,
389 % whether the format supports native in-memory I/O, and a brief description
392 % The format of the RegisterCALSImage method is:
394 % unsigned long RegisterCALSImage(void)
397 ModuleExport unsigned long RegisterCALSImage(void)
405 "Continuous Acquisition and Life-cycle Support Type 1 Image"
409 "Specified in MIL-R-28002 and MIL-PRF-28002"
412 entry=SetMagickInfo("CAL");
413 entry->decoder=(DecodeImageHandler *) ReadCALSImage;
414 #if defined(MAGICKCORE_TIFF_DELEGATE)
415 entry->encoder=(EncodeImageHandler *) WriteCALSImage;
417 entry->adjoin=MagickFalse;
418 entry->magick=(IsImageFormatHandler *) IsCALS;
419 entry->description=ConstantString(CALSDescription);
420 entry->note=ConstantString(CALSNote);
421 entry->module=ConstantString("CALS");
422 (void) RegisterMagickInfo(entry);
423 entry=SetMagickInfo("CALS");
424 entry->decoder=(DecodeImageHandler *) ReadCALSImage;
425 #if defined(MAGICKCORE_TIFF_DELEGATE)
426 entry->encoder=(EncodeImageHandler *) WriteCALSImage;
428 entry->adjoin=MagickFalse;
429 entry->magick=(IsImageFormatHandler *) IsCALS;
430 entry->description=ConstantString(CALSDescription);
431 entry->note=ConstantString(CALSNote);
432 entry->module=ConstantString("CALS");
433 (void) RegisterMagickInfo(entry);
434 return(MagickImageCoderSignature);
438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
442 % U n r e g i s t e r C A L S I m a g e %
446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448 % UnregisterCALSImage() removes format registrations made by the
449 % CALS module from the list of supported formats.
451 % The format of the UnregisterCALSImage method is:
453 % UnregisterCALSImage(void)
456 ModuleExport void UnregisterCALSImage(void)
458 (void) UnregisterMagickInfo("CAL");
459 (void) UnregisterMagickInfo("CALS");
463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
467 % W r i t e C A L S I m a g e %
471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473 % WriteCALSImage() writes an image to a file in CALS Raster Group 1 image
476 % The format of the WriteCALSImage method is:
478 % MagickBooleanType WriteCALSImage(const ImageInfo *image_info,
481 % A description of each parameter follows.
483 % o image_info: the image info.
485 % o image: The image.
489 #if defined(MAGICKCORE_TIFF_DELEGATE)
490 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
491 Image *image,Image *inject_image)
494 filename[MaxTextExtent];
531 Write image as CCITTFax4 TIFF image to a temporary file.
533 assert(image_info != (const ImageInfo *) NULL);
534 assert(image_info->signature == MagickSignature);
535 assert(image != (Image *) NULL);
536 assert(image->signature == MagickSignature);
537 if (image->debug != MagickFalse)
538 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
539 assert(inject_image != (Image *) NULL);
540 assert(inject_image->signature == MagickSignature);
541 huffman_image=CloneImage(inject_image,0,0,MagickTrue,&image->exception);
542 if (huffman_image == (Image *) NULL)
545 unique_file=AcquireUniqueFileResource(filename);
546 if (unique_file != -1)
547 file=fdopen(unique_file,"wb");
548 if ((unique_file == -1) || (file == (FILE *) NULL))
550 ThrowFileException(&image->exception,FileOpenError,
551 "UnableToCreateTemporaryFile",filename);
554 (void) FormatMagickString(huffman_image->filename,MaxTextExtent,"tiff:%s",
556 write_info=CloneImageInfo(image_info);
557 SetImageInfoFile(write_info,file);
558 write_info->compression=Group4Compression;
559 write_info->type=BilevelType;
560 (void) SetImageOption(write_info,"quantum:polarity","min-is-white");
561 status=WriteImage(write_info,huffman_image);
563 write_info=DestroyImageInfo(write_info);
564 if (status == MagickFalse)
566 tiff=TIFFOpen(filename,"rb");
567 if (tiff == (TIFF *) NULL)
569 huffman_image=DestroyImage(huffman_image);
571 (void) RelinquishUniqueFileResource(filename);
572 ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
573 image_info->filename);
577 Allocate raw strip buffer.
580 (void) TIFFGetField(tiff,TIFFTAG_STRIPBYTECOUNTS,&byte_count);
581 strip_size=byte_count[0];
582 for (i=1; i < (long) TIFFNumberOfStrips(tiff); i++)
583 if (byte_count[i] > strip_size)
584 strip_size=byte_count[i];
585 buffer=(unsigned char *) AcquireQuantumMemory((size_t) strip_size,
587 if (buffer == (unsigned char *) NULL)
590 huffman_image=DestroyImage(huffman_image);
592 (void) RelinquishUniqueFileResource(filename);
593 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
594 image_info->filename);
597 Compress runlength encoded to 2D Huffman pixels.
599 fillorder=FILLORDER_LSB2MSB;
600 (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&fillorder);
601 for (i=0; i < (long) TIFFNumberOfStrips(tiff); i++)
603 count=(ssize_t) TIFFReadRawStrip(tiff,(uint32) i,buffer,(long)
605 if (fillorder == FILLORDER_LSB2MSB)
606 TIFFReverseBits(buffer,(unsigned long) count);
607 (void) WriteBlob(image,(size_t) count,buffer);
609 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
611 huffman_image=DestroyImage(huffman_image);
613 (void) RelinquishUniqueFileResource(filename);
617 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
618 Image *image,Image *inject_image)
620 assert(image_info != (const ImageInfo *) NULL);
621 assert(image_info->signature == MagickSignature);
622 assert(image != (Image *) NULL);
623 assert(image->signature == MagickSignature);
624 if (image->debug != MagickFalse)
625 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
626 assert(inject_image != (Image *) NULL);
627 assert(inject_image->signature == MagickSignature);
628 (void) ThrowMagickException(&image->exception,GetMagickModule(),
629 MissingDelegateError,"DelegateLibrarySupportNotBuiltIn","`%s' (TIFF)",
635 static ssize_t WriteCALSRecord(Image *image,const char *data)
650 if (data != (const char *) NULL)
653 for (i=0; (i < 128) && (p[i] != '\0'); i++);
654 count=WriteBlob(image,(size_t) i,(const unsigned char *) data);
659 (void) ResetMagickMemory(pad,' ',(const size_t) i);
660 count=WriteBlob(image,(size_t) i,(const unsigned char *) pad);
665 static MagickBooleanType WriteCALSImage(const ImageInfo *image_info,
686 Open output image file.
688 assert(image_info != (const ImageInfo *) NULL);
689 assert(image_info->signature == MagickSignature);
690 assert(image != (Image *) NULL);
691 assert(image->signature == MagickSignature);
692 if (image->debug != MagickFalse)
693 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
694 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
695 if (status == MagickFalse)
698 Create standard CALS header.
700 count=WriteCALSRecord(image,"srcdocid: NONE");
701 count=WriteCALSRecord(image,"dstdocid: NONE");
702 count=WriteCALSRecord(image,"txtfilid: NONE");
703 count=WriteCALSRecord(image,"figid: NONE");
704 count=WriteCALSRecord(image,"srcgph: NONE");
705 count=WriteCALSRecord(image,"docls: NONE");
706 count=WriteCALSRecord(image,"rtype: 1");
709 switch (image->orientation)
711 case TopRightOrientation:
717 case BottomRightOrientation:
723 case BottomLeftOrientation:
728 case LeftTopOrientation:
733 case RightTopOrientation:
739 case RightBottomOrientation:
745 case LeftBottomOrientation:
755 (void) FormatMagickString(buffer,MaxTextExtent,"rorient: %03ld,%03ld",
757 count=WriteCALSRecord(image,buffer);
758 (void) FormatMagickString(buffer,MaxTextExtent,"rpelcnt: %06lu,%06lu",
759 image->columns,image->rows);
760 count=WriteCALSRecord(image,buffer);
762 if (image_info->density != (char *) NULL)
767 (void) ParseGeometry(image_info->density,&geometry_info);
768 density=(unsigned long) (geometry_info.rho+0.5);
770 (void) FormatMagickString(buffer,MaxTextExtent,"rdensty: %04lu",density);
771 count=WriteCALSRecord(image,buffer);
772 count=WriteCALSRecord(image,"notes: NONE");
773 (void) ResetMagickMemory(buffer,' ',128);
774 for (i=0; i < 5; i++)
775 (void) WriteBlob(image,128,(unsigned char *) buffer);
776 status=Huffman2DEncodeImage(image_info,image,image);
777 (void) CloseBlob(image);