]> granicus.if.org Git - imagemagick/blob - coders/cals.c
(no commit message)
[imagemagick] / coders / cals.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                         CCCC   AAA   L      SSSSS                           %
7 %                        C      A   A  L      SS                              %
8 %                        C      AAAAA  L       SSS                            %
9 %                        C      A   A  L         SS                           %
10 %                         CCCC  A   A  LLLLL  SSSSS                           %
11 %                                                                             %
12 %                                                                             %
13 %                 Read/Write CALS Raster Group 1 Image Format                 %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
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.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
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.
41 %
42 */
43 \f
44 /*
45   Include declarations.
46 */
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)
70 #include "tiffconf.h"
71 #endif
72 #include "tiffio.h"
73 #define CCITTParam  "-1"
74 #else
75 #define CCITTParam  "0"
76 #endif
77 \f
78 /*
79  Forward declarations.
80 */
81 static MagickBooleanType
82   WriteCALSImage(const ImageInfo *,Image *);
83 \f
84 /*
85 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86 %                                                                             %
87 %                                                                             %
88 %                                                                             %
89 %   I s C A L S                                                               %
90 %                                                                             %
91 %                                                                             %
92 %                                                                             %
93 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94 %
95 %  IsCALS() returns MagickTrue if the image format type, identified by the
96 %  magick string, is CALS Raster Group 1.
97 %
98 %  The format of the IsCALS method is:
99 %
100 %      MagickBooleanType IsCALS(const unsigned char *magick,const size_t length)
101 %
102 %  A description of each parameter follows:
103 %
104 %    o magick: compare image format pattern against these bytes.
105 %
106 %    o length: Specifies the length of the magick string.
107 %
108 */
109 static MagickBooleanType IsCALS(const unsigned char *magick,const size_t length)
110 {
111   if (length < 128)
112     return(MagickFalse);
113   if (LocaleNCompare((const char *) magick,"version: MIL-STD-1840",21) == 0)
114     return(MagickTrue);
115   if (LocaleNCompare((const char *) magick,"srcdocid:",9) == 0)
116     return(MagickTrue);
117   if (LocaleNCompare((const char *) magick,"rorient:",8) == 0)
118     return(MagickTrue);
119   return(MagickFalse);
120 }
121 \f
122 /*
123 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124 %                                                                             %
125 %                                                                             %
126 %                                                                             %
127 %   R e a d C A L S I m a g e                                                 %
128 %                                                                             %
129 %                                                                             %
130 %                                                                             %
131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132 %
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.
136 %
137 %  The format of the ReadCALSImage method is:
138 %
139 %      Image *ReadCALSImage(const ImageInfo *image_info,
140 %        ExceptionInfo *exception)
141 %
142 %  A description of each parameter follows:
143 %
144 %    o image_info: the image info.
145 %
146 %    o exception: return any errors or warnings in this structure.
147 %
148 */
149
150 static inline size_t WriteCALSLSBLong(FILE *file,const unsigned int value)
151 {
152   unsigned char
153     buffer[4];
154
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));
160 }
161
162 #if defined(MAGICKCORE_TIFF_DELEGATE)
163 static Image *Huffman2DDecodeImage(const ImageInfo *image_info,Image *image,
164   ExceptionInfo *exception)
165 {
166   char
167     filename[MaxTextExtent];
168
169   FILE
170     *file;
171
172   Image
173     *huffman_image;
174
175   ImageInfo
176     *read_info;
177
178   int
179     c,
180     unique_file;
181
182   size_t
183     length;
184
185   ssize_t
186     offset,
187     strip_offset;
188
189   /*
190     Write CALS facsimile document wrapped as a TIFF image file.
191   */
192   file=(FILE *) NULL;
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);
230   (void) fclose(file);
231   /*
232     Read TIFF image.
233   */
234   read_info=CloneImageInfo(image_info);
235   SetImageInfoBlob(read_info,(void *) NULL,0);
236   (void) FormatMagickString(read_info->filename,MaxTextExtent,"tiff:%.1024s",
237     filename);
238   huffman_image=ReadImage(read_info,exception);
239   if (huffman_image != (Image *) NULL)
240     {
241       (void) CopyMagickString(huffman_image->filename,image_info->filename,
242         MaxTextExtent);
243       (void) CopyMagickString(huffman_image->magick_filename,
244          image_info->filename,MaxTextExtent);
245       (void) CopyMagickString(huffman_image->magick,"CALS",MaxTextExtent);
246     }
247   read_info=DestroyImageInfo(read_info);
248   (void) RelinquishUniqueFileResource(filename);
249   return(huffman_image);
250 }
251 #else
252 static Image *Huffman2DDecodeImage(const ImageInfo *magick_unused(image_info),
253   Image *image,ExceptionInfo *exception)
254 {
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);
260 }
261 #endif
262
263 static Image *ReadCALSImage(const ImageInfo *image_info,
264   ExceptionInfo *exception)
265 {
266   char
267     header[129];
268
269   Image
270     *huffman_image,
271     *image;
272
273   MagickBooleanType
274     status;
275
276   register long
277     i;
278
279   unsigned long
280     density,
281     direction,
282     height,
283     orientation,
284     pel_path,
285     type,
286     width;
287
288   /*
289     Open image file.
290   */
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)
301     {
302       image=DestroyImageList(image);
303       return((Image *) NULL);
304     }
305   /*
306     Read CALS header.
307   */
308   (void) ResetMagickMemory(header,0,sizeof(header));
309   density=0;
310   direction=0;
311   orientation=1;
312   pel_path=0;
313   type=1;
314   width=0;
315   height=0;
316   for (i=0; i < 16; i++)
317   {
318     if (ReadBlob(image,128,(unsigned char *) header) != 128)
319       break;
320     switch (*header)
321     {
322       case 'R':
323       case 'r':
324       {
325         if (LocaleNCompare(header,"rdensty:",8) == 0)
326           {
327             (void) sscanf(header+8,"%lu",&density);
328             break;
329           }
330         if (LocaleNCompare(header,"rpelcnt:",8) == 0)
331           {
332             (void) sscanf(header+8,"%lu,%lu",&width,&height);
333             break;
334           }
335         if (LocaleNCompare(header,"rorient:",8) == 0)
336           {
337             (void) sscanf(header+8,"%lu,%lu",&pel_path,&direction);
338             if (pel_path == 90)
339               orientation=5;
340             else
341               if (pel_path == 90)
342                 orientation=3;
343               else
344                 if (pel_path == 270)
345                   orientation=7;
346             if (direction == 90)
347               orientation++;
348             break;
349           }
350         if (LocaleNCompare(header,"rtype:",6) == 0)
351           {
352             (void) sscanf(header+6,"%lu",&type);
353             break;
354           }
355         break;
356       }
357     }
358   }
359   if ((width == 0) || (height == 0) || (type == 0))
360     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
361   image->columns=width;
362   image->rows=height;
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));
372 }
373 \f
374 /*
375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376 %                                                                             %
377 %                                                                             %
378 %                                                                             %
379 %   R e g i s t e r C A L S I m a g e                                         %
380 %                                                                             %
381 %                                                                             %
382 %                                                                             %
383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384 %
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
390 %  of the format.
391 %
392 %  The format of the RegisterCALSImage method is:
393 %
394 %      unsigned long RegisterCALSImage(void)
395 %
396 */
397 ModuleExport unsigned long RegisterCALSImage(void)
398 {
399   MagickInfo
400     *entry;
401
402   static const char
403     *CALSDescription=
404     {
405       "Continuous Acquisition and Life-cycle Support Type 1 Image"
406     },
407     *CALSNote=
408     {
409       "Specified in MIL-R-28002 and MIL-PRF-28002"
410     };
411
412   entry=SetMagickInfo("CAL");
413   entry->decoder=(DecodeImageHandler *) ReadCALSImage;
414 #if defined(MAGICKCORE_TIFF_DELEGATE)
415   entry->encoder=(EncodeImageHandler *) WriteCALSImage;
416 #endif
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;
427 #endif
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);
435 }
436 \f
437 /*
438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439 %                                                                             %
440 %                                                                             %
441 %                                                                             %
442 %   U n r e g i s t e r C A L S I m a g e                                     %
443 %                                                                             %
444 %                                                                             %
445 %                                                                             %
446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
447 %
448 %  UnregisterCALSImage() removes format registrations made by the
449 %  CALS module from the list of supported formats.
450 %
451 %  The format of the UnregisterCALSImage method is:
452 %
453 %      UnregisterCALSImage(void)
454 %
455 */
456 ModuleExport void UnregisterCALSImage(void)
457 {
458   (void) UnregisterMagickInfo("CAL");
459   (void) UnregisterMagickInfo("CALS");
460 }
461 \f
462 /*
463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464 %                                                                             %
465 %                                                                             %
466 %                                                                             %
467 %   W r i t e C A L S I m a g e                                               %
468 %                                                                             %
469 %                                                                             %
470 %                                                                             %
471 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 %
473 %  WriteCALSImage() writes an image to a file in CALS Raster Group 1 image
474 %  format.
475 %
476 %  The format of the WriteCALSImage method is:
477 %
478 %      MagickBooleanType WriteCALSImage(const ImageInfo *image_info,
479 %        Image *image)
480 %
481 %  A description of each parameter follows.
482 %
483 %    o image_info: the image info.
484 %
485 %    o image:  The image.
486 %
487 */
488
489 #if defined(MAGICKCORE_TIFF_DELEGATE)
490 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
491   Image *image,Image *inject_image)
492 {
493   char
494     filename[MaxTextExtent];
495
496   FILE
497     *file;
498
499   Image
500     *huffman_image;
501
502   ImageInfo
503     *write_info;
504
505   int
506     unique_file;
507
508   MagickBooleanType
509     status;
510
511   register long
512     i;
513
514   ssize_t
515     count;
516
517   TIFF
518     *tiff;
519
520   uint16
521     fillorder;
522
523   uint32
524     *byte_count,
525     strip_size;
526
527   unsigned char
528     *buffer;
529
530   /*
531     Write image as CCITTFax4 TIFF image to a temporary file.
532   */
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)
543     return(MagickFalse);
544   file=(FILE *) 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))
549     {
550       ThrowFileException(&image->exception,FileOpenError,
551         "UnableToCreateTemporaryFile",filename);
552       return(MagickFalse);
553     }
554   (void) FormatMagickString(huffman_image->filename,MaxTextExtent,"tiff:%s",
555     filename);
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);
562   (void) fflush(file);
563   write_info=DestroyImageInfo(write_info);
564   if (status == MagickFalse)
565     return(MagickFalse);
566   tiff=TIFFOpen(filename,"rb");
567   if (tiff == (TIFF *) NULL)
568     {
569       huffman_image=DestroyImage(huffman_image);
570       (void) fclose(file);
571       (void) RelinquishUniqueFileResource(filename);
572       ThrowFileException(&image->exception,FileOpenError,"UnableToOpenFile",
573         image_info->filename);
574       return(MagickFalse);
575     }
576   /*
577     Allocate raw strip buffer.
578   */
579   byte_count=0;
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,
586     sizeof(*buffer));
587   if (buffer == (unsigned char *) NULL)
588     {
589       TIFFClose(tiff);
590       huffman_image=DestroyImage(huffman_image);
591       (void) fclose(file);
592       (void) RelinquishUniqueFileResource(filename);
593       ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
594         image_info->filename);
595     }
596   /*
597     Compress runlength encoded to 2D Huffman pixels.
598   */
599   fillorder=FILLORDER_LSB2MSB;
600   (void) TIFFGetFieldDefaulted(tiff,TIFFTAG_FILLORDER,&fillorder);
601   for (i=0; i < (long) TIFFNumberOfStrips(tiff); i++)
602   {
603     count=(ssize_t) TIFFReadRawStrip(tiff,(uint32) i,buffer,(long)
604       byte_count[i]);
605     if (fillorder == FILLORDER_LSB2MSB)
606       TIFFReverseBits(buffer,(unsigned long) count);
607     (void) WriteBlob(image,(size_t) count,buffer);
608   }
609   buffer=(unsigned char *) RelinquishMagickMemory(buffer);
610   TIFFClose(tiff);
611   huffman_image=DestroyImage(huffman_image);
612   (void) fclose(file);
613   (void) RelinquishUniqueFileResource(filename);
614   return(MagickTrue);
615 }
616 #else
617 static MagickBooleanType Huffman2DEncodeImage(const ImageInfo *image_info,
618   Image *image,Image *inject_image)
619 {
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)",
630     image->filename);
631   return(MagickFalse);
632 }
633 #endif
634
635 static ssize_t WriteCALSRecord(Image *image,const char *data)
636 {
637   char
638     pad[128];
639
640   ssize_t
641     count;
642
643   register const char
644     *p;
645
646   register long
647     i;
648
649   i=0;
650   if (data != (const char *) NULL)
651     {
652       p=data;
653       for (i=0; (i < 128) && (p[i] != '\0'); i++);
654       count=WriteBlob(image,(size_t) i,(const unsigned char *) data);
655     }
656   if (i < 128)
657     {
658       i=128-i;
659       (void) ResetMagickMemory(pad,' ',(const size_t) i);
660       count=WriteBlob(image,(size_t) i,(const unsigned char *) pad);
661     }
662   return(count);
663 }
664
665 static MagickBooleanType WriteCALSImage(const ImageInfo *image_info,
666   Image *image)
667 {
668   char
669     buffer[129];
670
671   MagickBooleanType
672     status;
673
674   register long
675     i;
676
677   ssize_t
678     count;
679
680   unsigned long
681     density,
682     orient_x,
683     orient_y;
684
685   /*
686     Open output image file.
687   */
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)
696     return(status);
697   /*
698     Create standard CALS header.
699   */
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");
707   orient_x=0;
708   orient_y=0;
709   switch (image->orientation)
710   {
711     case TopRightOrientation:
712     {
713       orient_x=180;
714       orient_y=270;
715       break;
716     }
717     case BottomRightOrientation:
718     {
719       orient_x=180;
720       orient_y=90;
721       break;
722     }
723     case BottomLeftOrientation:
724     {
725       orient_y=90;
726       break;
727     }
728     case LeftTopOrientation:
729     {
730       orient_x=270;
731       break;
732     }
733     case RightTopOrientation:
734     {
735       orient_x=270;
736       orient_y=180;
737       break;
738     }
739     case RightBottomOrientation:
740     {
741       orient_x=90;
742       orient_y=180;
743       break;
744     }
745     case LeftBottomOrientation:
746     {
747       orient_x=90;
748       break;
749     }
750     default:
751     {
752       orient_y=270;
753     }
754   }
755   (void) FormatMagickString(buffer,MaxTextExtent,"rorient: %03ld,%03ld",
756     orient_x,orient_y);
757   count=WriteCALSRecord(image,buffer);
758   (void) FormatMagickString(buffer,MaxTextExtent,"rpelcnt: %06lu,%06lu",
759     image->columns,image->rows);
760   count=WriteCALSRecord(image,buffer);  
761   density=200;
762   if (image_info->density != (char *) NULL)
763     {
764       GeometryInfo
765         geometry_info;
766
767       (void) ParseGeometry(image_info->density,&geometry_info);
768       density=(unsigned long) (geometry_info.rho+0.5);
769     }
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);
778   return(status);
779 }