Coverage Report

Created: 2026-06-16 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/coders/otb.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003-2026 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
%
5
% This program is covered by multiple licenses, which are described in
6
% Copyright.txt. You should have received a copy of Copyright.txt with this
7
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
8
%
9
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
10
%                                                                             %
11
%                                                                             %
12
%                                                                             %
13
%                              OOO   TTTTT  BBBB                              %
14
%                             O   O    T    B   B                             %
15
%                             O   O    T    BBBB                              %
16
%                             O   O    T    B   B                             %
17
%                              OOO     T    BBBB                              %
18
%                                                                             %
19
%                                                                             %
20
%                     Read/Write On-The-Air Image Format.                     %
21
%                                                                             %
22
%                                                                             %
23
%                              Software Design                                %
24
%                                John Cristy                                  %
25
%                               January 2000                                  %
26
%                                                                             %
27
%                                                                             %
28
%                                                                             %
29
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30
%
31
%
32
*/
33
/*
34
  Include declarations.
35
*/
36
#include "magick/studio.h"
37
#include "magick/blob.h"
38
#include "magick/colormap.h"
39
#include "magick/magick.h"
40
#include "magick/monitor.h"
41
#include "magick/pixel_cache.h"
42
#include "magick/utility.h"
43
#include "magick/static.h"
44

45
/*
46
  Forward declarations.
47
*/
48
static unsigned int
49
  WriteOTBImage(const ImageInfo *,Image *);
50

51
/*
52
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53
%                                                                             %
54
%                                                                             %
55
%                                                                             %
56
%   R e a d O T B I m a g e                                                   %
57
%                                                                             %
58
%                                                                             %
59
%                                                                             %
60
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61
%
62
%  Method ReadOTBImage reads a on-the-air (level 0) bitmap and returns it.  It
63
%  allocates the memory necessary for the new Image structure and returns a
64
%  pointer to the new image.
65
%
66
%  The format of the ReadOTBImage method is:
67
%
68
%      Image *ReadOTBImage(const ImageInfo *image_info,ExceptionInfo *exception)
69
%
70
%  A description of each parameter follows:
71
%
72
%    o image:  Method ReadOTBImage returns a pointer to the image after
73
%      reading.  A null image is returned if there is a memory shortage or
74
%      if the image cannot be read.
75
%
76
%    o image_info: Specifies a pointer to a ImageInfo structure.
77
%
78
%    o exception: return any errors or warnings in this structure.
79
%
80
%
81
*/
82
static Image *ReadOTBImage(const ImageInfo *image_info,ExceptionInfo *exception)
83
534
{
84
534
#define GetBit(a,i) (((a) >> (i)) & 1L)
85
86
534
  Image
87
534
    *image;
88
89
534
  int
90
534
    byte;
91
92
534
  long
93
534
    y;
94
95
534
  register IndexPacket
96
534
    *indexes;
97
98
534
  register long
99
534
    x;
100
101
534
  register PixelPacket
102
534
    *q;
103
104
534
  unsigned char
105
534
    bit,
106
534
    info,
107
534
    depth;
108
109
534
  unsigned int
110
534
    status;
111
112
  /*
113
    Open image file.
114
  */
115
534
  assert(image_info != (const ImageInfo *) NULL);
116
534
  assert(image_info->signature == MagickSignature);
117
534
  assert(exception != (ExceptionInfo *) NULL);
118
534
  assert(exception->signature == MagickSignature);
119
534
  image=AllocateImage(image_info);
120
534
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
121
534
  if (status == False)
122
534
    ThrowReaderException(FileOpenError,UnableToOpenFile,image);
123
  /*
124
    Initialize image structure.
125
  */
126
534
  info=ReadBlobByte(image);
127
534
  if (GetBit(info,4) == 0)
128
272
    {
129
272
      image->columns=ReadBlobByte(image);
130
272
      image->rows=ReadBlobByte(image);
131
272
    }
132
262
  else
133
262
    {
134
262
      image->columns=ReadBlobMSBShort(image);
135
262
      image->rows=ReadBlobMSBShort(image);
136
262
    }
137
534
  if ((image->columns == 0) || (image->rows == 0))
138
520
    ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
139
520
  depth=ReadBlobByte(image);
140
520
  if (depth != 1)
141
476
    ThrowReaderException(CoderError,OnlyLevelZerofilesSupported,image);
142
476
  if (!AllocateImageColormap(image,2))
143
476
    ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
144
476
  if (image_info->ping)
145
0
    {
146
0
      CloseBlob(image);
147
0
      StopTimer(&image->timer);
148
0
      return(image);
149
0
    }
150
151
476
  if (CheckImagePixelLimits(image, exception) != MagickPass)
152
449
    ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
153
154
  /*
155
    Convert bi-level image to pixel packets.
156
  */
157
138k
  for (y=0; y < (long) image->rows; y++)
158
138k
  {
159
138k
    q=SetImagePixelsEx(image,0,y,image->columns,1,exception);
160
138k
    if (q == (PixelPacket *) NULL)
161
0
      break;
162
138k
    indexes=AccessMutableIndexes(image);
163
138k
    bit=0;
164
138k
    byte=0;
165
71.6M
    for (x=0; x < (long) image->columns; x++)
166
71.5M
    {
167
71.5M
      if (bit == 0)
168
8.98M
        {
169
8.98M
          byte=ReadBlobByte(image);
170
8.98M
          if (byte == EOF)
171
8.98M
            ThrowReaderException(CorruptImageError,CorruptImage,image);
172
8.98M
        }
173
71.5M
      indexes[x]=(byte & (0x01 << (7-bit))) ? 0x01 : 0x00;
174
71.5M
      bit++;
175
71.5M
      if (bit == 8)
176
8.89M
        bit=0;
177
71.5M
    }
178
138k
    if (!SyncImagePixelsEx(image,exception))
179
0
      break;
180
138k
    if (QuantumTick(y,image->rows))
181
20.8k
      if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText,
182
20.8k
                                  image->filename,
183
20.8k
                                  image->columns,image->rows))
184
0
        break;
185
138k
  }
186
231
  (void) SyncImage(image);
187
231
  if (EOFBlob(image))
188
0
    ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,
189
231
      image->filename);
190
231
  CloseBlob(image);
191
231
  StopTimer(&image->timer);
192
231
  return(image);
193
449
}
194

195
/*
196
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197
%                                                                             %
198
%                                                                             %
199
%                                                                             %
200
%   R e g i s t e r O T B I m a g e                                           %
201
%                                                                             %
202
%                                                                             %
203
%                                                                             %
204
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205
%
206
%  Method RegisterOTBImage adds attributes for the OTB image format to
207
%  the list of supported formats.  The attributes include the image format
208
%  tag, a method to read and/or write the format, whether the format
209
%  supports the saving of more than one frame to the same file or blob,
210
%  whether the format supports native in-memory I/O, and a brief
211
%  description of the format.
212
%
213
%  The format of the RegisterOTBImage method is:
214
%
215
%      RegisterOTBImage(void)
216
%
217
*/
218
ModuleExport void RegisterOTBImage(void)
219
1
{
220
1
  MagickInfo
221
1
    *entry;
222
223
1
  entry=SetMagickInfo("OTB");
224
1
  entry->decoder=(DecoderHandler) ReadOTBImage;
225
1
  entry->encoder=(EncoderHandler) WriteOTBImage;
226
1
  entry->adjoin=False;
227
1
  entry->description="On-the-air bitmap";
228
1
  entry->module="OTB";
229
1
  (void) RegisterMagickInfo(entry);
230
1
}
231

232
/*
233
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
234
%                                                                             %
235
%                                                                             %
236
%                                                                             %
237
%   U n r e g i s t e r O T B I m a g e                                       %
238
%                                                                             %
239
%                                                                             %
240
%                                                                             %
241
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242
%
243
%  Method UnregisterOTBImage removes format registrations made by the
244
%  OTB module from the list of supported formats.
245
%
246
%  The format of the UnregisterOTBImage method is:
247
%
248
%      UnregisterOTBImage(void)
249
%
250
*/
251
ModuleExport void UnregisterOTBImage(void)
252
0
{
253
0
  (void) UnregisterMagickInfo("OTB");
254
0
}
255

256
/*
257
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258
%                                                                             %
259
%                                                                             %
260
%                                                                             %
261
%   W r i t e O T B I m a g e                                                 %
262
%                                                                             %
263
%                                                                             %
264
%                                                                             %
265
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
266
%
267
%  Method WriteOTBImage writes an image to a file in the On-the-air Bitmap
268
%  (level 0) image format.
269
%
270
%  The format of the WriteOTBImage method is:
271
%
272
%      unsigned int WriteOTBImage(const ImageInfo *image_info,Image *image)
273
%
274
%  A description of each parameter follows.
275
%
276
%    o status: Method WriteOTBImage return True if the image is written.
277
%      False is returned is there is a memory shortage or if the image file
278
%      fails to write.
279
%
280
%    o image_info: Specifies a pointer to a ImageInfo structure.
281
%
282
%    o image:  A pointer to an Image structure.
283
%
284
%
285
*/
286
static unsigned int WriteOTBImage(const ImageInfo *image_info,Image *image)
287
231
{
288
231
#define SetBit(a,i,set) \
289
315
  a=(unsigned char) ((set) ? (a) | (1L << (i)) : (a) & ~(1L << (i)))
290
291
231
  long
292
231
    y;
293
294
231
  register const PixelPacket
295
231
    *p;
296
297
231
  register const IndexPacket
298
231
    *indexes;
299
300
231
  register long
301
231
    x;
302
303
231
  unsigned char
304
231
    bit,
305
231
    byte,
306
231
    info,
307
231
    polarity;
308
309
231
  MagickPassFail
310
231
    status;
311
312
231
  assert(image_info != (const ImageInfo *) NULL);
313
231
  assert(image_info->signature == MagickSignature);
314
231
  assert(image != (Image *) NULL);
315
231
  assert(image->signature == MagickSignature);
316
317
  /*
318
    Convert image to a bi-level image.
319
  */
320
231
  if (TransformColorspace(image,RGBColorspace) == MagickFail)
321
0
    return MagickFail;
322
231
  if (SetImageType(image,BilevelType) == MagickFail)
323
0
    return MagickFail;
324
325
  /*
326
    Open output image file.
327
  */
328
231
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
329
231
  if (status == MagickFail)
330
231
    ThrowWriterException(FileOpenError,UnableToOpenFile,image);
331
231
  polarity=PixelIntensityToQuantum(&image->colormap[0]) < (MaxRGB/2);
332
231
  if (image->colors == 2)
333
231
    polarity=PixelIntensityToQuantum(&image->colormap[0]) <
334
231
      PixelIntensityToQuantum(&image->colormap[1]);
335
231
  info=0;
336
231
  if ((image->columns >= 256) || (image->rows >= 256))
337
84
    SetBit(info,4,1);
338
231
  (void) WriteBlobByte(image,info);
339
231
  if ((image->columns >= 256) || (image->rows >= 256))
340
84
    {
341
84
      (void) WriteBlobMSBShort(image,image->columns);
342
84
      (void) WriteBlobMSBShort(image,image->rows);
343
84
    }
344
147
  else
345
147
    {
346
147
      (void) WriteBlobByte(image,(long) image->columns);
347
147
      (void) WriteBlobByte(image,(long) image->rows);
348
147
    }
349
231
  (void) WriteBlobByte(image,1);  /* depth */
350
97.2k
  for (y=0; y < (long) image->rows; y++)
351
96.9k
  {
352
96.9k
    p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
353
96.9k
    if (p == (const PixelPacket *) NULL)
354
0
      break;
355
96.9k
    indexes=AccessImmutableIndexes(image);
356
96.9k
    bit=0;
357
96.9k
    byte=0;
358
25.5M
    for (x=0; x < (long) image->columns; x++)
359
25.4M
    {
360
25.4M
      if (indexes[x] == polarity)
361
8.68M
        byte|=0x1 << (7-bit);
362
25.4M
      bit++;
363
25.4M
      if (bit == 8)
364
3.13M
        {
365
3.13M
          (void) WriteBlobByte(image,byte);
366
3.13M
          bit=0;
367
3.13M
          byte=0;
368
3.13M
        }
369
25.4M
    }
370
96.9k
    if (bit != 0)
371
75.3k
      (void) WriteBlobByte(image,byte);
372
96.9k
    if (QuantumTick(y,image->rows))
373
16.6k
      if (!MagickMonitorFormatted(y,image->rows,&image->exception,
374
16.6k
                                  SaveImageText,image->filename,
375
16.6k
                                  image->columns,image->rows))
376
0
        break;
377
96.9k
  }
378
231
  status &= CloseBlob(image);
379
231
  return(status);
380
231
}