/src/graphicsmagick/coders/otb.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2025 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 | 452 | { |
84 | 452 | #define GetBit(a,i) (((a) >> (i)) & 1L) |
85 | | |
86 | 452 | Image |
87 | 452 | *image; |
88 | | |
89 | 452 | int |
90 | 452 | byte; |
91 | | |
92 | 452 | long |
93 | 452 | y; |
94 | | |
95 | 452 | register IndexPacket |
96 | 452 | *indexes; |
97 | | |
98 | 452 | register long |
99 | 452 | x; |
100 | | |
101 | 452 | register PixelPacket |
102 | 452 | *q; |
103 | | |
104 | 452 | unsigned char |
105 | 452 | bit, |
106 | 452 | info, |
107 | 452 | depth; |
108 | | |
109 | 452 | unsigned int |
110 | 452 | status; |
111 | | |
112 | | /* |
113 | | Open image file. |
114 | | */ |
115 | 452 | assert(image_info != (const ImageInfo *) NULL); |
116 | 452 | assert(image_info->signature == MagickSignature); |
117 | 452 | assert(exception != (ExceptionInfo *) NULL); |
118 | 452 | assert(exception->signature == MagickSignature); |
119 | 452 | image=AllocateImage(image_info); |
120 | 452 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
121 | 452 | if (status == False) |
122 | 452 | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
123 | | /* |
124 | | Initialize image structure. |
125 | | */ |
126 | 452 | info=ReadBlobByte(image); |
127 | 452 | if (GetBit(info,4) == 0) |
128 | 226 | { |
129 | 226 | image->columns=ReadBlobByte(image); |
130 | 226 | image->rows=ReadBlobByte(image); |
131 | 226 | } |
132 | 226 | else |
133 | 226 | { |
134 | 226 | image->columns=ReadBlobMSBShort(image); |
135 | 226 | image->rows=ReadBlobMSBShort(image); |
136 | 226 | } |
137 | 452 | if ((image->columns == 0) || (image->rows == 0)) |
138 | 439 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
139 | 439 | depth=ReadBlobByte(image); |
140 | 439 | if (depth != 1) |
141 | 399 | ThrowReaderException(CoderError,OnlyLevelZerofilesSupported,image); |
142 | 399 | if (!AllocateImageColormap(image,2)) |
143 | 399 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
144 | 399 | if (image_info->ping) |
145 | 0 | { |
146 | 0 | CloseBlob(image); |
147 | 0 | StopTimer(&image->timer); |
148 | 0 | return(image); |
149 | 0 | } |
150 | | |
151 | 399 | if (CheckImagePixelLimits(image, exception) != MagickPass) |
152 | 374 | ThrowReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
153 | | |
154 | | /* |
155 | | Convert bi-level image to pixel packets. |
156 | | */ |
157 | 133k | for (y=0; y < (long) image->rows; y++) |
158 | 133k | { |
159 | 133k | q=SetImagePixelsEx(image,0,y,image->columns,1,exception); |
160 | 133k | if (q == (PixelPacket *) NULL) |
161 | 0 | break; |
162 | 133k | indexes=AccessMutableIndexes(image); |
163 | 133k | bit=0; |
164 | 133k | byte=0; |
165 | 74.4M | for (x=0; x < (long) image->columns; x++) |
166 | 74.3M | { |
167 | 74.3M | if (bit == 0) |
168 | 9.33M | { |
169 | 9.33M | byte=ReadBlobByte(image); |
170 | 9.33M | if (byte == EOF) |
171 | 9.33M | ThrowReaderException(CorruptImageError,CorruptImage,image); |
172 | 9.33M | } |
173 | 74.3M | indexes[x]=(byte & (0x01 << (7-bit))) ? 0x01 : 0x00; |
174 | 74.3M | bit++; |
175 | 74.3M | if (bit == 8) |
176 | 9.23M | bit=0; |
177 | 74.3M | } |
178 | 133k | if (!SyncImagePixelsEx(image,exception)) |
179 | 0 | break; |
180 | 133k | if (QuantumTick(y,image->rows)) |
181 | 19.0k | if (!MagickMonitorFormatted(y,image->rows,exception,LoadImageText, |
182 | 19.0k | image->filename, |
183 | 19.0k | image->columns,image->rows)) |
184 | 0 | break; |
185 | 133k | } |
186 | 212 | (void) SyncImage(image); |
187 | 212 | if (EOFBlob(image)) |
188 | 0 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile, |
189 | 212 | image->filename); |
190 | 212 | CloseBlob(image); |
191 | 212 | StopTimer(&image->timer); |
192 | 212 | return(image); |
193 | 374 | } |
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 | 212 | { |
288 | 212 | #define SetBit(a,i,set) \ |
289 | 289 | a=(unsigned char) ((set) ? (a) | (1L << (i)) : (a) & ~(1L << (i))) |
290 | | |
291 | 212 | long |
292 | 212 | y; |
293 | | |
294 | 212 | register const PixelPacket |
295 | 212 | *p; |
296 | | |
297 | 212 | register const IndexPacket |
298 | 212 | *indexes; |
299 | | |
300 | 212 | register long |
301 | 212 | x; |
302 | | |
303 | 212 | unsigned char |
304 | 212 | bit, |
305 | 212 | byte, |
306 | 212 | info, |
307 | 212 | polarity; |
308 | | |
309 | 212 | unsigned int |
310 | 212 | status; |
311 | | |
312 | | /* |
313 | | Open output image file. |
314 | | */ |
315 | 212 | assert(image_info != (const ImageInfo *) NULL); |
316 | 212 | assert(image_info->signature == MagickSignature); |
317 | 212 | assert(image != (Image *) NULL); |
318 | 212 | assert(image->signature == MagickSignature); |
319 | 212 | status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
320 | 212 | if (status == False) |
321 | 212 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
322 | 212 | (void) TransformColorspace(image,RGBColorspace); |
323 | | /* |
324 | | Convert image to a bi-level image. |
325 | | */ |
326 | 212 | (void) SetImageType(image,BilevelType); |
327 | 212 | polarity=PixelIntensityToQuantum(&image->colormap[0]) < (MaxRGB/2); |
328 | 212 | if (image->colors == 2) |
329 | 212 | polarity=PixelIntensityToQuantum(&image->colormap[0]) < |
330 | 212 | PixelIntensityToQuantum(&image->colormap[1]); |
331 | 212 | info=0; |
332 | 212 | if ((image->columns >= 256) || (image->rows >= 256)) |
333 | 77 | SetBit(info,4,1); |
334 | 212 | (void) WriteBlobByte(image,info); |
335 | 212 | if ((image->columns >= 256) || (image->rows >= 256)) |
336 | 77 | { |
337 | 77 | (void) WriteBlobMSBShort(image,image->columns); |
338 | 77 | (void) WriteBlobMSBShort(image,image->rows); |
339 | 77 | } |
340 | 135 | else |
341 | 135 | { |
342 | 135 | (void) WriteBlobByte(image,(long) image->columns); |
343 | 135 | (void) WriteBlobByte(image,(long) image->rows); |
344 | 135 | } |
345 | 212 | (void) WriteBlobByte(image,1); /* depth */ |
346 | 87.9k | for (y=0; y < (long) image->rows; y++) |
347 | 87.6k | { |
348 | 87.6k | p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception); |
349 | 87.6k | if (p == (const PixelPacket *) NULL) |
350 | 0 | break; |
351 | 87.6k | indexes=AccessImmutableIndexes(image); |
352 | 87.6k | bit=0; |
353 | 87.6k | byte=0; |
354 | 31.4M | for (x=0; x < (long) image->columns; x++) |
355 | 31.3M | { |
356 | 31.3M | if (indexes[x] == polarity) |
357 | 11.3M | byte|=0x1 << (7-bit); |
358 | 31.3M | bit++; |
359 | 31.3M | if (bit == 8) |
360 | 3.89M | { |
361 | 3.89M | (void) WriteBlobByte(image,byte); |
362 | 3.89M | bit=0; |
363 | 3.89M | byte=0; |
364 | 3.89M | } |
365 | 31.3M | } |
366 | 87.6k | if (bit != 0) |
367 | 64.2k | (void) WriteBlobByte(image,byte); |
368 | 87.6k | if (QuantumTick(y,image->rows)) |
369 | 15.7k | if (!MagickMonitorFormatted(y,image->rows,&image->exception, |
370 | 15.7k | SaveImageText,image->filename, |
371 | 15.7k | image->columns,image->rows)) |
372 | 0 | break; |
373 | 87.6k | } |
374 | 212 | status &= CloseBlob(image); |
375 | 212 | return(status); |
376 | 212 | } |