1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % OOO TTTTT BBBB %
7 % O O T B B %
8 % O O T BBBB %
9 % O O T B B %
10 % OOO T BBBB %
11 % %
12 % %
13 % Read/Write On-The-Air Image Format %
14 % %
15 % Software Design %
16 % Cristy %
17 % January 2000 %
18 % %
19 % %
20 % Copyright 1999-2021 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/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 %
37 */
38 /*
39 Include declarations.
40 */
41 #include "MagickCore/studio.h"
42 #include "MagickCore/attribute.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/color-private.h"
47 #include "MagickCore/colormap.h"
48 #include "MagickCore/colorspace.h"
49 #include "MagickCore/colorspace-private.h"
50 #include "MagickCore/exception.h"
51 #include "MagickCore/exception-private.h"
52 #include "MagickCore/image.h"
53 #include "MagickCore/image-private.h"
54 #include "MagickCore/list.h"
55 #include "MagickCore/magick.h"
56 #include "MagickCore/memory_.h"
57 #include "MagickCore/monitor.h"
58 #include "MagickCore/monitor-private.h"
59 #include "MagickCore/pixel-accessor.h"
60 #include "MagickCore/quantum-private.h"
61 #include "MagickCore/static.h"
62 #include "MagickCore/string_.h"
63 #include "MagickCore/module.h"
64
65 /*
66 Forward declarations.
67 */
68 static MagickBooleanType
69 WriteOTBImage(const ImageInfo *,Image *,ExceptionInfo *);
70
71 /*
72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 % %
74 % %
75 % %
76 % R e a d O T B I m a g e %
77 % %
78 % %
79 % %
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 %
82 % ReadOTBImage() reads a on-the-air (level 0) bitmap and returns it. It
83 % allocates the memory necessary for the new Image structure and returns a
84 % pointer to the new image.
85 %
86 % The format of the ReadOTBImage method is:
87 %
88 % Image *ReadOTBImage(const ImageInfo *image_info,ExceptionInfo *exception)
89 %
90 % A description of each parameter follows:
91 %
92 % o image_info: the image info.
93 %
94 % o exception: return any errors or warnings in this structure.
95 %
96 %
97 */
ReadOTBImage(const ImageInfo * image_info,ExceptionInfo * exception)98 static Image *ReadOTBImage(const ImageInfo *image_info,ExceptionInfo *exception)
99 {
100 #define GetBit(a,i) (((a) >> (i)) & 1L)
101
102 Image
103 *image;
104
105 int
106 byte;
107
108 MagickBooleanType
109 status;
110
111 ssize_t
112 x;
113
114 Quantum
115 *q;
116
117 ssize_t
118 y;
119
120 unsigned char
121 bit,
122 info,
123 depth;
124
125 /*
126 Open image file.
127 */
128 assert(image_info != (const ImageInfo *) NULL);
129 assert(image_info->signature == MagickCoreSignature);
130 if (image_info->debug != MagickFalse)
131 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
132 image_info->filename);
133 assert(exception != (ExceptionInfo *) NULL);
134 assert(exception->signature == MagickCoreSignature);
135 image=AcquireImage(image_info,exception);
136 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
137 if (status == MagickFalse)
138 {
139 image=DestroyImageList(image);
140 return((Image *) NULL);
141 }
142 /*
143 Initialize image structure.
144 */
145 info=(unsigned char) ReadBlobByte(image);
146 if (GetBit(info,4) == 0)
147 {
148 image->columns=(size_t) ReadBlobByte(image);
149 image->rows=(size_t) ReadBlobByte(image);
150 }
151 else
152 {
153 image->columns=(size_t) ReadBlobMSBShort(image);
154 image->rows=(size_t) ReadBlobMSBShort(image);
155 }
156 if ((image->columns == 0) || (image->rows == 0))
157 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
158 depth=(unsigned char) ReadBlobByte(image);
159 if (depth != 1)
160 ThrowReaderException(CoderError,"OnlyLevelZerofilesSupported");
161 if (AcquireImageColormap(image,2,exception) == MagickFalse)
162 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
163 if (image_info->ping != MagickFalse)
164 {
165 (void) CloseBlob(image);
166 return(GetFirstImageInList(image));
167 }
168 status=SetImageExtent(image,image->columns,image->rows,exception);
169 if (status == MagickFalse)
170 return(DestroyImageList(image));
171 /*
172 Convert bi-level image to pixel packets.
173 */
174 for (y=0; y < (ssize_t) image->rows; y++)
175 {
176 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
177 if (q == (Quantum *) NULL)
178 break;
179 bit=0;
180 byte=0;
181 for (x=0; x < (ssize_t) image->columns; x++)
182 {
183 if (bit == 0)
184 {
185 byte=ReadBlobByte(image);
186 if (byte == EOF)
187 ThrowReaderException(CorruptImageError,"CorruptImage");
188 }
189 SetPixelIndex(image,(byte & (0x01 << (7-bit))) ? 0x00 : 0x01,q);
190 bit++;
191 if (bit == 8)
192 bit=0;
193 q+=GetPixelChannels(image);
194 }
195 if (SyncAuthenticPixels(image,exception) == MagickFalse)
196 break;
197 if (image->previous == (Image *) NULL)
198 {
199 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
200 image->rows);
201 if (status == MagickFalse)
202 break;
203 }
204 }
205 (void) SyncImage(image,exception);
206 if (EOFBlob(image) != MagickFalse)
207 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
208 image->filename);
209 (void) CloseBlob(image);
210 return(GetFirstImageInList(image));
211 }
212
213 /*
214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
215 % %
216 % %
217 % %
218 % R e g i s t e r O T B I m a g e %
219 % %
220 % %
221 % %
222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
223 %
224 % RegisterOTBImage() adds attributes for the OTB image format to
225 % the list of supported formats. The attributes include the image format
226 % tag, a method to read and/or write the format, whether the format
227 % supports the saving of more than one frame to the same file or blob,
228 % whether the format supports native in-memory I/O, and a brief
229 % description of the format.
230 %
231 % The format of the RegisterOTBImage method is:
232 %
233 % size_t RegisterOTBImage(void)
234 %
235 */
RegisterOTBImage(void)236 ModuleExport size_t RegisterOTBImage(void)
237 {
238 MagickInfo
239 *entry;
240
241 entry=AcquireMagickInfo("OTB","OTB","On-the-air bitmap");
242 entry->decoder=(DecodeImageHandler *) ReadOTBImage;
243 entry->encoder=(EncodeImageHandler *) WriteOTBImage;
244 entry->flags^=CoderAdjoinFlag;
245 (void) RegisterMagickInfo(entry);
246 return(MagickImageCoderSignature);
247 }
248
249 /*
250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251 % %
252 % %
253 % %
254 % U n r e g i s t e r O T B I m a g e %
255 % %
256 % %
257 % %
258 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259 %
260 % UnregisterOTBImage() removes format registrations made by the
261 % OTB module from the list of supported formats.
262 %
263 % The format of the UnregisterOTBImage method is:
264 %
265 % UnregisterOTBImage(void)
266 %
267 */
UnregisterOTBImage(void)268 ModuleExport void UnregisterOTBImage(void)
269 {
270 (void) UnregisterMagickInfo("OTB");
271 }
272
273 /*
274 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275 % %
276 % %
277 % %
278 % W r i t e O T B I m a g e %
279 % %
280 % %
281 % %
282 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283 %
284 % WriteOTBImage() writes an image to a file in the On-the-air Bitmap
285 % (level 0) image format.
286 %
287 % The format of the WriteOTBImage method is:
288 %
289 % MagickBooleanType WriteOTBImage(const ImageInfo *image_info,
290 % Image *image,ExceptionInfo *exception)
291 %
292 % A description of each parameter follows.
293 %
294 % o image_info: the image info.
295 %
296 % o image: The image.
297 %
298 % o exception: return any errors or warnings in this structure.
299 %
300 */
WriteOTBImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)301 static MagickBooleanType WriteOTBImage(const ImageInfo *image_info,Image *image,
302 ExceptionInfo *exception)
303 {
304 #define SetBit(a,i,set) \
305 a=(unsigned char) ((set) ? (a) | (1L << (i)) : (a) & ~(1L << (i)))
306
307 MagickBooleanType
308 status;
309
310 const Quantum
311 *p;
312
313 ssize_t
314 x;
315
316 ssize_t
317 y;
318
319 unsigned char
320 bit,
321 byte,
322 info;
323
324 /*
325 Open output image file.
326 */
327 assert(image_info != (const ImageInfo *) NULL);
328 assert(image_info->signature == MagickCoreSignature);
329 assert(image != (Image *) NULL);
330 assert(image->signature == MagickCoreSignature);
331 if (image->debug != MagickFalse)
332 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
333 assert(exception != (ExceptionInfo *) NULL);
334 assert(exception->signature == MagickCoreSignature);
335 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
336 if (status == MagickFalse)
337 return(status);
338 (void) TransformImageColorspace(image,sRGBColorspace,exception);
339 /*
340 Convert image to a bi-level image.
341 */
342 (void) SetImageType(image,BilevelType,exception);
343 info=0;
344 if ((image->columns >= 256) || (image->rows >= 256))
345 SetBit(info,4,1);
346 (void) WriteBlobByte(image,info);
347 if ((image->columns >= 256) || (image->rows >= 256))
348 {
349 (void) WriteBlobMSBShort(image,(unsigned short) image->columns);
350 (void) WriteBlobMSBShort(image,(unsigned short) image->rows);
351 }
352 else
353 {
354 (void) WriteBlobByte(image,(unsigned char) image->columns);
355 (void) WriteBlobByte(image,(unsigned char) image->rows);
356 }
357 (void) WriteBlobByte(image,1); /* depth */
358 for (y=0; y < (ssize_t) image->rows; y++)
359 {
360 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
361 if (p == (const Quantum *) NULL)
362 break;
363 bit=0;
364 byte=0;
365 for (x=0; x < (ssize_t) image->columns; x++)
366 {
367 if (GetPixelLuma(image,p) < (QuantumRange/2.0))
368 byte|=0x1 << (7-bit);
369 bit++;
370 if (bit == 8)
371 {
372 (void) WriteBlobByte(image,byte);
373 bit=0;
374 byte=0;
375 }
376 p+=GetPixelChannels(image);
377 }
378 if (bit != 0)
379 (void) WriteBlobByte(image,byte);
380 if (image->previous == (Image *) NULL)
381 {
382 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
383 image->rows);
384 if (status == MagickFalse)
385 break;
386 }
387 }
388 (void) CloseBlob(image);
389 return(MagickTrue);
390 }
391