Coverage Report

Created: 2026-06-30 07:12

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