]> granicus.if.org Git - imagemagick/blob - coders/cals.c
c3ad21c2a8d5902b186a149fe722434a8f9b7c7f
[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-2011 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 "MagickCore/studio.h"
48 #include "MagickCore/blob.h"
49 #include "MagickCore/blob-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/colorspace.h"
52 #include "MagickCore/exception.h"
53 #include "MagickCore/exception-private.h"
54 #include "MagickCore/geometry.h"
55 #include "MagickCore/image.h"
56 #include "MagickCore/image-private.h"
57 #include "MagickCore/list.h"
58 #include "MagickCore/magick.h"
59 #include "MagickCore/memory_.h"
60 #include "MagickCore/monitor.h"
61 #include "MagickCore/monitor-private.h"
62 #include "MagickCore/option.h"
63 #include "MagickCore/quantum-private.h"
64 #include "MagickCore/resource_.h"
65 #include "MagickCore/static.h"
66 #include "MagickCore/string_.h"
67 #include "MagickCore/module.h"
68 \f
69 #if defined(MAGICKCORE_TIFF_DELEGATE)
70 /*
71  Forward declarations.
72 */
73 static MagickBooleanType
74   WriteCALSImage(const ImageInfo *,Image *,ExceptionInfo *);
75 #endif
76 \f
77 /*
78 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79 %                                                                             %
80 %                                                                             %
81 %                                                                             %
82 %   I s C A L S                                                               %
83 %                                                                             %
84 %                                                                             %
85 %                                                                             %
86 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87 %
88 %  IsCALS() returns MagickTrue if the image format type, identified by the
89 %  magick string, is CALS Raster Group 1.
90 %
91 %  The format of the IsCALS method is:
92 %
93 %      MagickBooleanType IsCALS(const unsigned char *magick,const size_t length)
94 %
95 %  A description of each parameter follows:
96 %
97 %    o magick: compare image format pattern against these bytes.
98 %
99 %    o length: Specifies the length of the magick string.
100 %
101 */
102 static MagickBooleanType IsCALS(const unsigned char *magick,const size_t length)
103 {
104   if (length < 128)
105     return(MagickFalse);
106   if (LocaleNCompare((const char *) magick,"version: MIL-STD-1840",21) == 0)
107     return(MagickTrue);
108   if (LocaleNCompare((const char *) magick,"srcdocid:",9) == 0)
109     return(MagickTrue);
110   if (LocaleNCompare((const char *) magick,"rorient:",8) == 0)
111     return(MagickTrue);
112   return(MagickFalse);
113 }
114 \f
115 /*
116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117 %                                                                             %
118 %                                                                             %
119 %                                                                             %
120 %   R e a d C A L S I m a g e                                                 %
121 %                                                                             %
122 %                                                                             %
123 %                                                                             %
124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125 %
126 %  ReadCALSImage() reads an CALS Raster Group 1 image format image file and
127 %  returns it.  It allocates the memory necessary for the new Image structure
128 %  and returns a pointer to the new image.
129 %
130 %  The format of the ReadCALSImage method is:
131 %
132 %      Image *ReadCALSImage(const ImageInfo *image_info,
133 %        ExceptionInfo *exception)
134 %
135 %  A description of each parameter follows:
136 %
137 %    o image_info: the image info.
138 %
139 %    o exception: return any errors or warnings in this structure.
140 %
141 */
142 static Image *ReadCALSImage(const ImageInfo *image_info,
143   ExceptionInfo *exception)
144 {
145   char
146     filename[MaxTextExtent],
147     header[129],
148     message[MaxTextExtent];
149
150   FILE
151     *file;
152
153   Image
154     *image;
155
156   ImageInfo
157     *read_info;
158
159   int
160     c,
161     unique_file;
162
163   MagickBooleanType
164     status;
165
166   register ssize_t
167     i;
168
169   unsigned long
170     density,
171     direction,
172     height,
173     orientation,
174     pel_path,
175     type,
176     width;
177
178   /*
179     Open image file.
180   */
181   assert(image_info != (const ImageInfo *) NULL);
182   assert(image_info->signature == MagickSignature);
183   if (image_info->debug != MagickFalse)
184     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
185       image_info->filename);
186   assert(exception != (ExceptionInfo *) NULL);
187   assert(exception->signature == MagickSignature);
188   image=AcquireImage(image_info);
189   status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
190   if (status == MagickFalse)
191     {
192       image=DestroyImageList(image);
193       return((Image *) NULL);
194     }
195   /*
196     Read CALS header.
197   */
198   (void) ResetMagickMemory(header,0,sizeof(header));
199   density=0;
200   direction=0;
201   orientation=1;
202   pel_path=0;
203   type=1;
204   width=0;
205   height=0;
206   for (i=0; i < 16; i++)
207   {
208     if (ReadBlob(image,128,(unsigned char *) header) != 128)
209       break;
210     switch (*header)
211     {
212       case 'R':
213       case 'r':
214       {
215         if (LocaleNCompare(header,"rdensty:",8) == 0)
216           {
217             (void) sscanf(header+8,"%lu",&density);
218             break;
219           }
220         if (LocaleNCompare(header,"rpelcnt:",8) == 0)
221           {
222             (void) sscanf(header+8,"%lu,%lu",&width,&height);
223             break;
224           }
225         if (LocaleNCompare(header,"rorient:",8) == 0)
226           {
227             (void) sscanf(header+8,"%lu,%lu",&pel_path,&direction);
228             if (pel_path == 90)
229               orientation=5;
230             else
231               if (pel_path == 180)
232                 orientation=3;
233               else
234                 if (pel_path == 270)
235                   orientation=7;
236             if (direction == 90)
237               orientation++;
238             break;
239           }
240         if (LocaleNCompare(header,"rtype:",6) == 0)
241           {
242             (void) sscanf(header+6,"%lu",&type);
243             break;
244           }
245         break;
246       }
247     }
248   }
249   /*
250     Read CALS pixels.
251   */
252   file=(FILE *) NULL;
253   unique_file=AcquireUniqueFileResource(filename);
254   if (unique_file != -1)
255     file=fdopen(unique_file,"wb");
256   if ((unique_file == -1) || (file == (FILE *) NULL))
257     ThrowImageException(FileOpenError,"UnableToCreateTemporaryFile");
258   while ((c=ReadBlobByte(image)) != EOF)
259     (void) fputc(c,file);
260   (void) fclose(file);
261   (void) CloseBlob(image);
262   image=DestroyImage(image);
263   read_info=CloneImageInfo(image_info);
264   SetImageInfoBlob(read_info,(void *) NULL,0);
265   (void) FormatLocaleString(read_info->filename,MaxTextExtent,"group4:%s",
266     filename);
267   (void) FormatLocaleString(message,MaxTextExtent,"%lux%lu",width,height);
268   read_info->size=ConstantString(message);
269   (void) FormatLocaleString(message,MaxTextExtent,"%lu",density);
270   read_info->density=ConstantString(message);
271   read_info->orientation=(OrientationType) orientation;
272   image=ReadImage(read_info,exception);
273   if (image != (Image *) NULL)
274     {
275       (void) CopyMagickString(image->filename,image_info->filename,
276         MaxTextExtent);
277       (void) CopyMagickString(image->magick_filename,image_info->filename,
278         MaxTextExtent);
279       (void) CopyMagickString(image->magick,"CALS",MaxTextExtent);
280     }
281   read_info=DestroyImageInfo(read_info);
282   (void) RelinquishUniqueFileResource(filename);
283   return(image);
284 }
285 \f
286 /*
287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288 %                                                                             %
289 %                                                                             %
290 %                                                                             %
291 %   R e g i s t e r C A L S I m a g e                                         %
292 %                                                                             %
293 %                                                                             %
294 %                                                                             %
295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296 %
297 %  RegisterCALSImage() adds attributes for the CALS Raster Group 1 image file
298 %  image format to the list of supported formats.  The attributes include the
299 %  image format tag, a method to read and/or write the format, whether the
300 %  format supports the saving of more than one frame to the same file or blob,
301 %  whether the format supports native in-memory I/O, and a brief description
302 %  of the format.
303 %
304 %  The format of the RegisterCALSImage method is:
305 %
306 %      size_t RegisterCALSImage(void)
307 %
308 */
309 ModuleExport size_t RegisterCALSImage(void)
310 {
311   MagickInfo
312     *entry;
313
314   static const char
315     *CALSDescription=
316     {
317       "Continuous Acquisition and Life-cycle Support Type 1"
318     },
319     *CALSNote=
320     {
321       "Specified in MIL-R-28002 and MIL-PRF-28002"
322     };
323
324   entry=SetMagickInfo("CAL");
325   entry->decoder=(DecodeImageHandler *) ReadCALSImage;
326 #if defined(MAGICKCORE_TIFF_DELEGATE)
327   entry->encoder=(EncodeImageHandler *) WriteCALSImage;
328 #endif
329   entry->adjoin=MagickFalse;
330   entry->magick=(IsImageFormatHandler *) IsCALS;
331   entry->description=ConstantString(CALSDescription);
332   entry->note=ConstantString(CALSNote);
333   entry->module=ConstantString("CALS");
334   (void) RegisterMagickInfo(entry);
335   entry=SetMagickInfo("CALS");
336   entry->decoder=(DecodeImageHandler *) ReadCALSImage;
337 #if defined(MAGICKCORE_TIFF_DELEGATE)
338   entry->encoder=(EncodeImageHandler *) WriteCALSImage;
339 #endif
340   entry->adjoin=MagickFalse;
341   entry->magick=(IsImageFormatHandler *) IsCALS;
342   entry->description=ConstantString(CALSDescription);
343   entry->note=ConstantString(CALSNote);
344   entry->module=ConstantString("CALS");
345   (void) RegisterMagickInfo(entry);
346   return(MagickImageCoderSignature);
347 }
348 \f
349 /*
350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351 %                                                                             %
352 %                                                                             %
353 %                                                                             %
354 %   U n r e g i s t e r C A L S I m a g e                                     %
355 %                                                                             %
356 %                                                                             %
357 %                                                                             %
358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
359 %
360 %  UnregisterCALSImage() removes format registrations made by the
361 %  CALS module from the list of supported formats.
362 %
363 %  The format of the UnregisterCALSImage method is:
364 %
365 %      UnregisterCALSImage(void)
366 %
367 */
368 ModuleExport void UnregisterCALSImage(void)
369 {
370   (void) UnregisterMagickInfo("CAL");
371   (void) UnregisterMagickInfo("CALS");
372 }
373 \f
374 #if defined(MAGICKCORE_TIFF_DELEGATE)
375 /*
376 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377 %                                                                             %
378 %                                                                             %
379 %                                                                             %
380 %   W r i t e C A L S I m a g e                                               %
381 %                                                                             %
382 %                                                                             %
383 %                                                                             %
384 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385 %
386 %  WriteCALSImage() writes an image to a file in CALS Raster Group 1 image
387 %  format.
388 %
389 %  The format of the WriteCALSImage method is:
390 %
391 %      MagickBooleanType WriteCALSImage(const ImageInfo *image_info,
392 %        Image *image,ExceptionInfo *exception)
393 %
394 %  A description of each parameter follows.
395 %
396 %    o image_info: the image info.
397 %
398 %    o image:  The image.
399 %
400 %    o exception: return any errors or warnings in this structure.
401 %
402 */
403
404 static ssize_t WriteCALSRecord(Image *image,const char *data)
405 {
406   char
407     pad[128];
408
409   register const char
410     *p;
411
412   register ssize_t
413     i;
414
415   ssize_t
416     count;
417
418   i=0;
419   if (data != (const char *) NULL)
420     {
421       p=data;
422       for (i=0; (i < 128) && (p[i] != '\0'); i++);
423       count=WriteBlob(image,(size_t) i,(const unsigned char *) data);
424     }
425   if (i < 128)
426     {
427       i=128-i;
428       (void) ResetMagickMemory(pad,' ',(size_t) i);
429       count=WriteBlob(image,(size_t) i,(const unsigned char *) pad);
430     }
431   return(count);
432 }
433
434 static MagickBooleanType WriteCALSImage(const ImageInfo *image_info,
435   Image *image,ExceptionInfo *exception)
436 {
437   char
438     header[129];
439
440   Image
441     *group4_image;
442
443   ImageInfo
444     *write_info;
445
446   MagickBooleanType
447     status;
448
449   register ssize_t
450     i;
451
452   size_t
453     density,
454     length,
455     orient_x,
456     orient_y;
457
458   ssize_t
459     count;
460
461   unsigned char
462     *group4;
463
464   /*
465     Open output image file.
466   */
467   assert(image_info != (const ImageInfo *) NULL);
468   assert(image_info->signature == MagickSignature);
469   assert(image != (Image *) NULL);
470   assert(image->signature == MagickSignature);
471   if (image->debug != MagickFalse)
472     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
473   assert(exception != (ExceptionInfo *) NULL);
474   assert(exception->signature == MagickSignature);
475   status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
476   if (status == MagickFalse)
477     return(status);
478   /*
479     Create standard CALS header.
480   */
481   count=WriteCALSRecord(image,"srcdocid: NONE");
482   (void) count;
483   count=WriteCALSRecord(image,"dstdocid: NONE");
484   count=WriteCALSRecord(image,"txtfilid: NONE");
485   count=WriteCALSRecord(image,"figid: NONE");
486   count=WriteCALSRecord(image,"srcgph: NONE");
487   count=WriteCALSRecord(image,"docls: NONE");
488   count=WriteCALSRecord(image,"rtype: 1");
489   orient_x=0;
490   orient_y=0;
491   switch (image->orientation)
492   {
493     case TopRightOrientation:
494     {
495       orient_x=180;
496       orient_y=270;
497       break;
498     }
499     case BottomRightOrientation:
500     {
501       orient_x=180;
502       orient_y=90;
503       break;
504     }
505     case BottomLeftOrientation:
506     {
507       orient_y=90;
508       break;
509     }
510     case LeftTopOrientation:
511     {
512       orient_x=270;
513       break;
514     }
515     case RightTopOrientation:
516     {
517       orient_x=270;
518       orient_y=180;
519       break;
520     }
521     case RightBottomOrientation:
522     {
523       orient_x=90;
524       orient_y=180;
525       break;
526     }
527     case LeftBottomOrientation:
528     {
529       orient_x=90;
530       break;
531     }
532     default:
533     {
534       orient_y=270;
535     }
536   }
537   (void) FormatLocaleString(header,MaxTextExtent,"rorient: %03ld,%03ld",
538     (long) orient_x,(long) orient_y);
539   count=WriteCALSRecord(image,header);
540   (void) FormatLocaleString(header,MaxTextExtent,"rpelcnt: %06lu,%06lu",
541     (unsigned long) image->columns,(unsigned long) image->rows);
542   count=WriteCALSRecord(image,header);  
543   density=200;
544   if (image_info->density != (char *) NULL)
545     {
546       GeometryInfo
547         geometry_info;
548
549       (void) ParseGeometry(image_info->density,&geometry_info);
550       density=(size_t) floor(geometry_info.rho+0.5);
551     }
552   (void) FormatLocaleString(header,MaxTextExtent,"rdensty: %04lu",
553     (unsigned long) density);
554   count=WriteCALSRecord(image,header);
555   count=WriteCALSRecord(image,"notes: NONE");
556   (void) ResetMagickMemory(header,' ',128);
557   for (i=0; i < 5; i++)
558     (void) WriteBlob(image,128,(unsigned char *) header);
559   /*
560     Write CALS pixels.
561   */
562   write_info=CloneImageInfo(image_info);
563   (void) CopyMagickString(write_info->filename,"GROUP4:",MaxTextExtent);
564   (void) CopyMagickString(write_info->magick,"GROUP4",MaxTextExtent);
565   group4_image=CloneImage(image,0,0,MagickTrue,exception);
566   if (group4_image == (Image *) NULL)
567     {
568       (void) CloseBlob(image);
569       return(MagickFalse);
570     }
571   group4=(unsigned char *) ImageToBlob(write_info,group4_image,&length,
572     exception);
573   group4_image=DestroyImage(group4_image);
574   if (group4 == (unsigned char *) NULL)
575     {
576       (void) CloseBlob(image);
577       return(MagickFalse);
578     }
579   write_info=DestroyImageInfo(write_info);
580   if (WriteBlob(image,length,group4) != (ssize_t) length)
581     status=MagickFalse;
582   group4=(unsigned char *) RelinquishMagickMemory(group4);
583   (void) CloseBlob(image);
584   return(status);
585 }
586 #endif