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