/src/graphicsmagick/coders/wpg.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 | | % W W PPPP GGGG % |
13 | | % W W P P G % |
14 | | % W W W PPPP G GGG % |
15 | | % WW WW P G G % |
16 | | % W W P GGG % |
17 | | % % |
18 | | % % |
19 | | % Read WordPerfect Image Format. % |
20 | | % % |
21 | | % % |
22 | | % Software Design % |
23 | | % Jaroslav Fojtik % |
24 | | % June 2000 - 2023 % |
25 | | % Rework for GraphicsMagick % |
26 | | % Bob Friesenhahn % |
27 | | % Feb-May 2003 % |
28 | | % % |
29 | | % % |
30 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
31 | | % |
32 | | % |
33 | | */ |
34 | | |
35 | | /* |
36 | | Include declarations. |
37 | | */ |
38 | | #include "magick/studio.h" |
39 | | #include "magick/blob.h" |
40 | | #include "magick/colormap.h" |
41 | | #include "magick/constitute.h" |
42 | | #include "magick/log.h" |
43 | | #include "magick/magic.h" |
44 | | #include "magick/magick.h" |
45 | | #include "magick/pixel_cache.h" |
46 | | #include "magick/shear.h" |
47 | | #include "magick/tempfile.h" |
48 | | #include "magick/transform.h" |
49 | | #include "magick/quantize.h" |
50 | | #include "magick/utility.h" |
51 | | #include "magick/static.h" |
52 | | |
53 | | |
54 | | typedef struct |
55 | | { |
56 | | unsigned char Red; |
57 | | unsigned char Blue; |
58 | | unsigned char Green; |
59 | | } RGB_Record; |
60 | | |
61 | | /* Default palette for WPG level 1 */ |
62 | | static const RGB_Record WPG1_Palette[256] = |
63 | | { |
64 | | { 0, 0, 0}, { 0, 0,168}, |
65 | | { 0,168, 0}, { 0,168,168}, |
66 | | {168, 0, 0}, {168, 0,168}, |
67 | | {168, 84, 0}, {168,168,168}, |
68 | | { 84, 84, 84}, { 84, 84,252}, |
69 | | { 84,252, 84}, { 84,252,252}, |
70 | | {252, 84, 84}, {252, 84,252}, |
71 | | {252,252, 84}, {252,252,252}, /*16*/ |
72 | | { 0, 0, 0}, { 20, 20, 20}, |
73 | | { 32, 32, 32}, { 44, 44, 44}, |
74 | | { 56, 56, 56}, { 68, 68, 68}, |
75 | | { 80, 80, 80}, { 96, 96, 96}, |
76 | | {112,112,112}, {128,128,128}, |
77 | | {144,144,144}, {160,160,160}, |
78 | | {180,180,180}, {200,200,200}, |
79 | | {224,224,224}, {252,252,252}, /*32*/ |
80 | | { 0, 0,252}, { 64, 0,252}, |
81 | | {124, 0,252}, {188, 0,252}, |
82 | | {252, 0,252}, {252, 0,188}, |
83 | | {252, 0,124}, {252, 0, 64}, |
84 | | {252, 0, 0}, {252, 64, 0}, |
85 | | {252,124, 0}, {252,188, 0}, |
86 | | {252,252, 0}, {188,252, 0}, |
87 | | {124,252, 0}, { 64,252, 0}, /*48*/ |
88 | | { 0,252, 0}, { 0,252, 64}, |
89 | | { 0,252,124}, { 0,252,188}, |
90 | | { 0,252,252}, { 0,188,252}, |
91 | | { 0,124,252}, { 0, 64,252}, |
92 | | {124,124,252}, {156,124,252}, |
93 | | {188,124,252}, {220,124,252}, |
94 | | {252,124,252}, {252,124,220}, |
95 | | {252,124,188}, {252,124,156}, /*64*/ |
96 | | {252,124,124}, {252,156,124}, |
97 | | {252,188,124}, {252,220,124}, |
98 | | {252,252,124}, {220,252,124}, |
99 | | {188,252,124}, {156,252,124}, |
100 | | {124,252,124}, {124,252,156}, |
101 | | {124,252,188}, {124,252,220}, |
102 | | {124,252,252}, {124,220,252}, |
103 | | {124,188,252}, {124,156,252}, /*80*/ |
104 | | {180,180,252}, {196,180,252}, |
105 | | {216,180,252}, {232,180,252}, |
106 | | {252,180,252}, {252,180,232}, |
107 | | {252,180,216}, {252,180,196}, |
108 | | {252,180,180}, {252,196,180}, |
109 | | {252,216,180}, {252,232,180}, |
110 | | {252,252,180}, {232,252,180}, |
111 | | {216,252,180}, {196,252,180}, /*96*/ |
112 | | {180,220,180}, {180,252,196}, |
113 | | {180,252,216}, {180,252,232}, |
114 | | {180,252,252}, {180,232,252}, |
115 | | {180,216,252}, {180,196,252}, |
116 | | {0,0,112}, {28,0,112}, |
117 | | {56,0,112}, {84,0,112}, |
118 | | {112,0,112}, {112,0,84}, |
119 | | {112,0,56}, {112,0,28}, /*112*/ |
120 | | {112,0,0}, {112,28,0}, |
121 | | {112,56,0}, {112,84,0}, |
122 | | {112,112,0}, {84,112,0}, |
123 | | {56,112,0}, {28,112,0}, |
124 | | {0,112,0}, {0,112,28}, |
125 | | {0,112,56}, {0,112,84}, |
126 | | {0,112,112}, {0,84,112}, |
127 | | {0,56,112}, {0,28,112}, /*128*/ |
128 | | {56,56,112}, {68,56,112}, |
129 | | {84,56,112}, {96,56,112}, |
130 | | {112,56,112}, {112,56,96}, |
131 | | {112,56,84}, {112,56,68}, |
132 | | {112,56,56}, {112,68,56}, |
133 | | {112,84,56}, {112,96,56}, |
134 | | {112,112,56}, {96,112,56}, |
135 | | {84,112,56}, {68,112,56}, /*144*/ |
136 | | {56,112,56}, {56,112,69}, |
137 | | {56,112,84}, {56,112,96}, |
138 | | {56,112,112}, {56,96,112}, |
139 | | {56,84,112}, {56,68,112}, |
140 | | {80,80,112}, {88,80,112}, |
141 | | {96,80,112}, {104,80,112}, |
142 | | {112,80,112}, {112,80,104}, |
143 | | {112,80,96}, {112,80,88}, /*160*/ |
144 | | {112,80,80}, {112,88,80}, |
145 | | {112,96,80}, {112,104,80}, |
146 | | {112,112,80}, {104,112,80}, |
147 | | {96,112,80}, {88,112,80}, |
148 | | {80,112,80}, {80,112,88}, |
149 | | {80,112,96}, {80,112,104}, |
150 | | {80,112,112}, {80,114,112}, |
151 | | {80,96,112}, {80,88,112}, /*176*/ |
152 | | {0,0,64}, {16,0,64}, |
153 | | {32,0,64}, {48,0,64}, |
154 | | {64,0,64}, {64,0,48}, |
155 | | {64,0,32}, {64,0,16}, |
156 | | {64,0,0}, {64,16,0}, |
157 | | {64,32,0}, {64,48,0}, |
158 | | {64,64,0}, {48,64,0}, |
159 | | {32,64,0}, {16,64,0}, /*192*/ |
160 | | {0,64,0}, {0,64,16}, |
161 | | {0,64,32}, {0,64,48}, |
162 | | {0,64,64}, {0,48,64}, |
163 | | {0,32,64}, {0,16,64}, |
164 | | {32,32,64}, {40,32,64}, |
165 | | {48,32,64}, {56,32,64}, |
166 | | {64,32,64}, {64,32,56}, |
167 | | {64,32,48}, {64,32,40}, /*208*/ |
168 | | {64,32,32}, {64,40,32}, |
169 | | {64,48,32}, {64,56,32}, |
170 | | {64,64,32}, {56,64,32}, |
171 | | {48,64,32}, {40,64,32}, |
172 | | {32,64,32}, {32,64,40}, |
173 | | {32,64,48}, {32,64,56}, |
174 | | {32,64,64}, {32,56,64}, |
175 | | {32,48,64}, {32,40,64}, /*224*/ |
176 | | {44,44,64}, {48,44,64}, |
177 | | {52,44,64}, {60,44,64}, |
178 | | {64,44,64}, {64,44,60}, |
179 | | {64,44,52}, {64,44,48}, |
180 | | {64,44,44}, {64,48,44}, |
181 | | {64,52,44}, {64,60,44}, |
182 | | {64,64,44}, {60,64,44}, |
183 | | {52,64,44}, {48,64,44}, /*240*/ |
184 | | {44,64,44}, {44,64,48}, |
185 | | {44,64,52}, {44,64,60}, |
186 | | {44,64,64}, {44,60,64}, |
187 | | {44,55,64}, {44,48,64}, |
188 | | {0,0,0}, {0,0,0}, |
189 | | {0,0,0}, {0,0,0}, |
190 | | {0,0,0}, {0,0,0}, |
191 | | {0,0,0}, {0,0,0} /*256*/ |
192 | | }; |
193 | | |
194 | | |
195 | | static int ApproveFormatForWPG(const char *Format, ExceptionInfo *exception) |
196 | 4.99M | { |
197 | 4.99M | const MagickInfo * |
198 | 4.99M | magick_info; |
199 | | |
200 | 4.99M | if (!strcmp(Format,"PFB")) return 0; |
201 | | |
202 | | /*if (!strcmp(Format,"8BIMTEXT")) return 0; This test is no longer needed, META module includes this case. */ |
203 | 4.99M | magick_info = GetMagickInfo(Format,exception); |
204 | 4.99M | if (magick_info != (const MagickInfo *)NULL) |
205 | 4.97M | { |
206 | 4.97M | if (strcmp(magick_info->module, "META") == 0) return 0; |
207 | 4.97M | } |
208 | | |
209 | 4.98M | return 1; |
210 | 4.99M | } |
211 | | |
212 | | |
213 | | |
214 | | /* |
215 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
216 | | % % |
217 | | % % |
218 | | % % |
219 | | % I s W P G % |
220 | | % % |
221 | | % % |
222 | | % % |
223 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
224 | | % |
225 | | % IsWPG() returns True if the image format type, identified by the magick |
226 | | % string, is WPG. |
227 | | % |
228 | | % The format of the IsWPG method is: |
229 | | % |
230 | | % unsigned int IsWPG(const unsigned char *magick,const size_t length) |
231 | | % |
232 | | % A description of each parameter follows: |
233 | | % |
234 | | % o status: Method IsWPG returns True if the image format type is WPG. |
235 | | % |
236 | | % o magick: This string is generally the first few bytes of an image file |
237 | | % or blob. |
238 | | % |
239 | | % o length: Specifies the length of the magick string. |
240 | | % |
241 | | % |
242 | | */ |
243 | | static unsigned int IsWPG(const unsigned char *magick,const size_t length) |
244 | 0 | { |
245 | 0 | if (length < 4) |
246 | 0 | return(False); |
247 | 0 | if (memcmp(magick,"\377WPC",4) == 0) |
248 | 0 | return(True); |
249 | 0 | return(False); |
250 | 0 | } |
251 | | |
252 | | static int Rd_WP_DWORD(Image *image, magick_uint32_t *d) |
253 | 179M | { |
254 | 179M | unsigned char |
255 | 179M | b; |
256 | | |
257 | 179M | b = ReadBlobByte(image); |
258 | 179M | *d = b; |
259 | 179M | if (b < 0xFFU) |
260 | 177M | return 1; |
261 | 1.38M | b = ReadBlobByte(image); |
262 | 1.38M | *d = (unsigned long) b; |
263 | 1.38M | b = ReadBlobByte(image); |
264 | 1.38M | *d+=(unsigned long) b*256l; |
265 | 1.38M | if (*d < 0x8000) |
266 | 1.22M | return 3; |
267 | 160k | *d=(*d & 0x7FFF) << 16; |
268 | 160k | b = ReadBlobByte(image); |
269 | 160k | *d += (unsigned long) b; |
270 | 160k | b=ReadBlobByte(image); |
271 | 160k | *d += (unsigned long) b*256l; |
272 | 160k | return 5; |
273 | 1.38M | } |
274 | | |
275 | | |
276 | | static MagickPassFail InsertRow(unsigned char *p,unsigned long y, Image *image, int bpp) |
277 | 1.08M | { |
278 | 1.08M | unsigned long |
279 | 1.08M | x; |
280 | | |
281 | 1.08M | register PixelPacket |
282 | 1.08M | *q; |
283 | | |
284 | 1.08M | MagickPassFail |
285 | 1.08M | RetVal = MagickFail; |
286 | | |
287 | 1.08M | IndexPacket |
288 | 1.08M | index; |
289 | | |
290 | 1.08M | IndexPacket * |
291 | 1.08M | indexes; |
292 | | |
293 | 1.08M | if (image->logging) |
294 | 1.08M | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
295 | 1.08M | "Insert row %ld of %lu...", y, image->rows); |
296 | | |
297 | 1.08M | q = SetImagePixels(image,0,y,image->columns,1); |
298 | 1.08M | if (q == (PixelPacket *) NULL) |
299 | 19.0k | return MagickFail; |
300 | | |
301 | 1.06M | switch (bpp) |
302 | 1.06M | { |
303 | 1.04M | case 1: /* Convert bitmap scanline. WP seems to ignore palette even if it is present. */ |
304 | 1.04M | RetVal = ImportImagePixelArea(image,GrayQuantum,bpp,p,NULL,0); |
305 | 1.04M | break; |
306 | | |
307 | 7.53k | case 4: /* Convert PseudoColor scanline. */ |
308 | 10.3k | case 8: /* Convert PseudoColor scanline. */ |
309 | 10.3k | RetVal = ImportImagePixelArea(image,IndexQuantum,bpp,p,NULL,0); |
310 | 10.3k | break; |
311 | | |
312 | 13.2k | case 2: /* Convert PseudoColor scanline. */ |
313 | 13.2k | { |
314 | 13.2k | indexes=AccessMutableIndexes(image); |
315 | 13.2k | if ((image->storage_class != PseudoClass) || |
316 | 13.2k | (indexes == (IndexPacket *) NULL)) |
317 | 0 | { |
318 | 0 | if (image->logging) |
319 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
320 | 0 | "Image has no colormap, skipping..."); |
321 | 0 | return MagickFail; |
322 | 0 | } |
323 | 13.2k | x = 0; |
324 | 165k | while (x+3 < image->columns) |
325 | 151k | { |
326 | 151k | index = (IndexPacket)((*p >> 6) & 0x3); |
327 | 151k | VerifyColormapIndex(image,index); |
328 | 151k | indexes[x++]=index; |
329 | 151k | *q++=image->colormap[index]; |
330 | 151k | index = (IndexPacket)((*p >> 4) & 0x3); |
331 | 151k | VerifyColormapIndex(image,index); |
332 | 151k | indexes[x++]=index; |
333 | 151k | *q++=image->colormap[index]; |
334 | 151k | index = (IndexPacket)((*p >> 2) & 0x3); |
335 | 151k | VerifyColormapIndex(image,index); |
336 | 151k | indexes[x++]=index; |
337 | 151k | *q++ = image->colormap[index]; |
338 | 151k | index = (IndexPacket)((*p) & 0x3); |
339 | 151k | VerifyColormapIndex(image,index); |
340 | 151k | indexes[x++]=index; |
341 | 151k | *q++ = image->colormap[index]; |
342 | 151k | p++; |
343 | 151k | } |
344 | 13.2k | if (x < image->columns) |
345 | 12.3k | { |
346 | 12.3k | index = (IndexPacket) ((*p >> 6) & 0x3); |
347 | 12.3k | VerifyColormapIndex(image,index); |
348 | 12.3k | indexes[x++] = index; |
349 | 12.3k | *q++=image->colormap[index]; |
350 | 12.3k | if (x < image->columns) |
351 | 3.54k | { |
352 | 3.54k | index = (IndexPacket) ((*p >> 4) & 0x3); |
353 | 3.54k | VerifyColormapIndex(image,index); |
354 | 3.54k | indexes[x++] = index; |
355 | 3.54k | *q++=image->colormap[index]; |
356 | 3.54k | if (x < image->columns) |
357 | 1.06k | { |
358 | 1.06k | index = (IndexPacket)((*p >> 2) & 0x3); |
359 | 1.06k | VerifyColormapIndex(image,index); |
360 | 1.06k | indexes[x] = index; |
361 | 1.06k | *q++=image->colormap[index]; |
362 | 1.06k | } |
363 | 3.54k | } |
364 | | /* p++; */ |
365 | 12.3k | } |
366 | 13.2k | RetVal = MagickPass; |
367 | 13.2k | break; |
368 | 13.2k | } |
369 | | |
370 | 3.37k | case 24: /* Convert DirectColor scanline. */ |
371 | 3.37k | RetVal = ImportImagePixelArea(image,RGBQuantum,8,p,NULL,0); |
372 | 3.37k | break; |
373 | | |
374 | 3 | default: |
375 | 3 | if (image->logging) |
376 | 3 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
377 | 3 | "Unsupported bits per pixel %u",bpp); |
378 | | |
379 | 3 | return MagickFail; /* emit some error here */ |
380 | 1.06M | } |
381 | | |
382 | | |
383 | 1.06M | if (RetVal==MagickFail) |
384 | 0 | { |
385 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"ImportImagePixelArea failed for row: %lu, bpp: %d", y, bpp); |
386 | 0 | return MagickFail; |
387 | 0 | } |
388 | | |
389 | 1.06M | if (!SyncImagePixels(image)) |
390 | 0 | { |
391 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(),"SyncImagePixels failed for row: %ld, bpp: %d", y, bpp); |
392 | 0 | return MagickFail; |
393 | 0 | } |
394 | | |
395 | 1.06M | return RetVal; |
396 | 1.06M | } |
397 | | |
398 | | |
399 | | /* Helper for WPG1 raster reader. */ |
400 | | #define InsertByte(b) \ |
401 | 322k | { \ |
402 | 322k | BImgBuff[x]=b; \ |
403 | 322k | x++; \ |
404 | 322k | if ((long) x>=ldblk) \ |
405 | 322k | { \ |
406 | 19.6k | if (InsertRow(BImgBuff,y,image,bpp)==MagickFail) \ |
407 | 19.6k | { \ |
408 | 3.52k | RetVal=-6; \ |
409 | 3.52k | goto unpack_wpg_raser_error; \ |
410 | 3.52k | } \ |
411 | 19.6k | x=0; \ |
412 | 16.1k | y++; \ |
413 | 16.1k | if (y>=image->rows) break; \ |
414 | 16.1k | } \ |
415 | 322k | } |
416 | | |
417 | | |
418 | | /** Call this function to ensure that all data matrix is filled with something. This function |
419 | | * is used only to error recovery. */ |
420 | | static MagickPassFail ZeroFillMissingData(unsigned char *BImgBuff, |
421 | | unsigned long x, |
422 | | unsigned long y, |
423 | | Image *image, |
424 | | int bpp, |
425 | | long ldblk) |
426 | 347 | { |
427 | 347 | MagickPassFail |
428 | 347 | status = MagickPass; |
429 | | |
430 | 1.62k | while (y<image->rows && image->exception.severity!=UndefinedException) |
431 | 1.28k | { |
432 | 1.28k | if ((long) x<ldblk) |
433 | 14 | { |
434 | 14 | memset(BImgBuff+x, 0, (size_t)ldblk-(size_t)x); |
435 | 14 | if (x == 0) |
436 | 6 | x = ldblk; /* Do not memset any more */ |
437 | 8 | else |
438 | 8 | x = 0; /* Next pass will need to clear whole row */ |
439 | 14 | } |
440 | 1.28k | if (InsertRow(BImgBuff,y,image,bpp) == MagickFail) |
441 | 10 | { |
442 | 10 | status = MagickFail; |
443 | 10 | break; |
444 | 10 | } |
445 | 1.27k | y++; |
446 | 1.27k | } |
447 | 347 | return status; |
448 | 347 | } |
449 | | |
450 | | |
451 | | /* WPG1 raster reader. |
452 | | * @return 0 - OK; -2 - allocation failure; -3 unaligned column; -4 - image row overflowl |
453 | | -5 - blob read error; -6 - row insert problem */ |
454 | | static int UnpackWPGRaster(Image *image,int bpp) |
455 | 4.93k | { |
456 | 4.93k | unsigned long |
457 | 4.93k | x = 0, |
458 | 4.93k | y = 0; |
459 | | |
460 | 4.93k | int |
461 | 4.93k | i; |
462 | | |
463 | 4.93k | int RetVal |
464 | 4.93k | = 0; |
465 | | |
466 | 4.93k | unsigned char |
467 | 4.93k | bbuf, |
468 | 4.93k | *BImgBuff, |
469 | 4.93k | RunCount; |
470 | | |
471 | 4.93k | long |
472 | 4.93k | ldblk; |
473 | | |
474 | 4.93k | ldblk = (long)((bpp*image->columns+7)/8); |
475 | 4.93k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
476 | 4.93k | "Raster allocation size: %ld byte%s", |
477 | 4.93k | ldblk, (ldblk > 1 ? "s" : "")); |
478 | 4.93k | BImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk); |
479 | 4.93k | if (BImgBuff==NULL) |
480 | 433 | return(-2); |
481 | 4.50k | (void) memset(BImgBuff,0,(size_t) ldblk); |
482 | | |
483 | 12.0k | while (y<image->rows) |
484 | 11.6k | { |
485 | 11.6k | i = ReadBlobByte(image); |
486 | 11.6k | if (i==EOF) |
487 | 118 | { |
488 | 118 | ZeroFillMissingData(BImgBuff,x,y,image,bpp,ldblk); |
489 | 118 | MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff); |
490 | 118 | return(-5); |
491 | 118 | } |
492 | 11.5k | bbuf = i; |
493 | | |
494 | 11.5k | RunCount=bbuf & 0x7F; |
495 | 11.5k | if (bbuf & 0x80) |
496 | 2.90k | { |
497 | 2.90k | if (RunCount) /* repeat next byte runcount * */ |
498 | 2.18k | { |
499 | 2.18k | bbuf=ReadBlobByte(image); |
500 | 159k | for (i=0;i<(int) RunCount;i++) InsertByte(bbuf); |
501 | 1.74k | } |
502 | 712 | else { /* read next byte as RunCount; repeat 0xFF runcount* */ |
503 | 712 | RunCount=ReadBlobByte(image); |
504 | 77.8k | for (i=0;i<(int) RunCount;i++) InsertByte(0xFF); |
505 | 702 | } |
506 | 2.90k | } |
507 | 8.61k | else { |
508 | 8.61k | if (RunCount) /* next runcount byte are readd directly */ |
509 | 6.82k | { |
510 | 91.0k | for (i=0;i < (int) RunCount;i++) |
511 | 87.3k | { |
512 | 87.3k | bbuf=ReadBlobByte(image); |
513 | 87.3k | InsertByte(bbuf); |
514 | 84.1k | } |
515 | 6.82k | } |
516 | 1.78k | else { /* repeat previous line runcount* */ |
517 | 1.78k | i = ReadBlobByte(image); |
518 | 1.78k | if (i==EOF) |
519 | 222 | { |
520 | 222 | ZeroFillMissingData(BImgBuff,x,y,image,bpp,ldblk); |
521 | 222 | MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff); |
522 | 222 | return -7; |
523 | 222 | } |
524 | 1.56k | RunCount = i; |
525 | 1.56k | if (x!=0) { /* attempt to duplicate row from x position: */ |
526 | | /* I do not know what to do here */ |
527 | 69 | if (InsertRow(BImgBuff,y,image,bpp) == MagickPass) /* May be line flush can fix a situation. */ |
528 | 7 | { |
529 | 7 | x=0; |
530 | 7 | y++; |
531 | 7 | ZeroFillMissingData(BImgBuff,x,y,image,bpp,ldblk); |
532 | 7 | } |
533 | 69 | MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff); |
534 | 69 | return(-3); |
535 | 69 | } |
536 | 6.53k | for (i=0; i<(int)RunCount; i++) |
537 | 5.19k | { /* Here I need to duplicate previous row RUNCOUNT* */ |
538 | | /* when x=0; y points to a new empty line. For y=0 zero line will be populated. */ |
539 | 5.19k | if (y>=image->rows) |
540 | 9 | { |
541 | 9 | MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff); |
542 | 9 | return(-4); |
543 | 9 | } |
544 | 5.19k | if (InsertRow(BImgBuff,y,image,bpp)==MagickFail) |
545 | 144 | { |
546 | 144 | MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff); |
547 | 144 | return(-6); |
548 | 144 | } |
549 | 5.04k | y++; |
550 | 5.04k | } |
551 | 1.49k | } |
552 | 8.61k | } |
553 | 11.5k | } |
554 | 3.94k | unpack_wpg_raser_error:; |
555 | 3.94k | MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff); |
556 | 3.94k | return(RetVal); |
557 | 4.50k | } |
558 | | |
559 | | |
560 | | /* Helper for WPG2 reader. */ |
561 | | #define InsertByte6(b) \ |
562 | 27.9M | { \ |
563 | 27.9M | if (XorMe) \ |
564 | 27.9M | BImgBuff[x] = b ^ UpImgBuff[x]; \ |
565 | 27.9M | else \ |
566 | 27.9M | BImgBuff[x] = b; \ |
567 | 27.9M | x++; \ |
568 | 27.9M | if ((long) x >= ldblk) \ |
569 | 27.9M | { \ |
570 | 33.2k | if (InsertRow(BImgBuff,(long) y,image,bpp)==MagickFail) \ |
571 | 33.2k | { RetVal=-6; \ |
572 | 14.6k | goto unpack_wpg2_error; \ |
573 | 14.6k | } \ |
574 | 33.2k | x=0; \ |
575 | 18.6k | y++; \ |
576 | 18.6k | XorMe = 0; \ |
577 | 18.6k | tmpImgBuff = BImgBuff; \ |
578 | 18.6k | BImgBuff = UpImgBuff; \ |
579 | 18.6k | UpImgBuff = tmpImgBuff; \ |
580 | 18.6k | } \ |
581 | 27.9M | } |
582 | | |
583 | | #define FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff) \ |
584 | 26.3k | do \ |
585 | 26.3k | { \ |
586 | 26.3k | MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff); \ |
587 | 26.3k | MagickFreeResourceLimitedMemory(unsigned char *,UpImgBuff); \ |
588 | 26.3k | } while (0); |
589 | | |
590 | | /* WPG2 raster reader. */ |
591 | | static int UnpackWPG2Raster(Image *image, int bpp) |
592 | 26.3k | { |
593 | 26.3k | unsigned int |
594 | 26.3k | SampleSize=1; |
595 | | |
596 | 26.3k | unsigned char |
597 | 26.3k | bbuf, |
598 | 26.3k | *BImgBuff = (unsigned char *) NULL, /* Buffer for a current line. */ |
599 | 26.3k | *UpImgBuff = (unsigned char *) NULL, /* Buffer for previous line. */ |
600 | 26.3k | *tmpImgBuff = (unsigned char *) NULL, |
601 | 26.3k | RunCount, |
602 | 26.3k | SampleBuffer[8]; |
603 | | |
604 | 26.3k | unsigned long |
605 | 26.3k | x = 0, |
606 | 26.3k | y = 0; |
607 | | |
608 | 26.3k | unsigned int |
609 | 26.3k | i; |
610 | | |
611 | 26.3k | long |
612 | 26.3k | ldblk; |
613 | | |
614 | 26.3k | int XorMe = 0; |
615 | 26.3k | int c; |
616 | 26.3k | int RetVal = 0; |
617 | | |
618 | 26.3k | ldblk=(long) ((bpp*image->columns+7)/8); |
619 | 26.3k | BImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk); |
620 | 26.3k | if (BImgBuff==NULL) |
621 | 0 | return(-2); |
622 | 26.3k | UpImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk); |
623 | 26.3k | if (UpImgBuff==NULL) |
624 | 0 | { |
625 | 0 | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
626 | 0 | return(-2); |
627 | 0 | } |
628 | 26.3k | (void) memset(UpImgBuff,0,ldblk); |
629 | 26.3k | (void) memset(SampleBuffer,0,sizeof(SampleBuffer)); |
630 | | |
631 | 335k | while ( y< image->rows) |
632 | 328k | { |
633 | 328k | bbuf=ReadBlobByte(image); |
634 | | |
635 | 328k | switch (bbuf) |
636 | 328k | { |
637 | 811 | case 0x7D: |
638 | 811 | if ((c = ReadBlobByte(image)) == EOF) /* DSZ */ |
639 | 4 | { |
640 | 4 | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
641 | 4 | return(-4); |
642 | 4 | } |
643 | 807 | SampleSize=c; |
644 | 807 | if (SampleSize>8) |
645 | 24 | { |
646 | 24 | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
647 | 24 | return(-2); |
648 | 24 | } |
649 | 783 | if (SampleSize<1) |
650 | 3 | { |
651 | 3 | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
652 | 3 | return(-2); |
653 | 3 | } |
654 | 780 | break; |
655 | 1.18k | case 0x7E: |
656 | 1.18k | if (y==0) /* XOR */ |
657 | 1.11k | (void)fprintf(stderr,"\nWPG token XOR on the first line is not supported, please report!"); |
658 | 1.18k | XorMe=!XorMe; /* or XorMe=1 ?? */ |
659 | 1.18k | break; |
660 | 12.2k | case 0x7F: |
661 | 12.2k | if ((c = ReadBlobByte(image)) == EOF) /* BLK */ |
662 | 6 | { |
663 | 6 | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
664 | 6 | return(-4); |
665 | 6 | } |
666 | 12.2k | RunCount=c; |
667 | 2.88M | for (i=0; i < SampleSize*(RunCount+1); i++) |
668 | 2.87M | { |
669 | 2.87M | InsertByte6(0); |
670 | 2.87M | } |
671 | 11.6k | break; |
672 | 88.8k | case 0xFD: |
673 | 88.8k | if ((c = ReadBlobByte(image)) == EOF) /* EXT */ |
674 | 3.00k | { |
675 | 3.00k | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
676 | 3.00k | return(-4); |
677 | 3.00k | } |
678 | 85.8k | RunCount=c; |
679 | 21.4M | for (i=0; i<= RunCount;i++) |
680 | 42.9M | for (bbuf=0; bbuf < SampleSize; bbuf++) |
681 | 21.6M | InsertByte6(SampleBuffer[bbuf]); |
682 | 84.0k | break; |
683 | 4.17k | case 0xFE: |
684 | 4.17k | if ((c = ReadBlobByte(image)) == EOF) /* RST */ |
685 | 5 | { |
686 | 5 | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
687 | 5 | return(-4); |
688 | 5 | } |
689 | 4.16k | RunCount = c; |
690 | 4.16k | if (x!=0) |
691 | 37 | { |
692 | 37 | (void) fprintf(stderr, |
693 | 37 | "\nUnsupported WPG2 unaligned token RST x=%lu, please report!\n" |
694 | 37 | ,x); |
695 | 37 | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
696 | 37 | return(-3); |
697 | 37 | } |
698 | 4.13k | { |
699 | | /* duplicate the previous row RunCount x */ |
700 | 1.03M | for (i=0;i<=RunCount;i++) |
701 | 1.02M | { |
702 | 1.02M | if (InsertRow(UpImgBuff,(long)((image->rows>y) ? y : image->rows-1),image,bpp) == MagickFail) |
703 | 58 | { |
704 | 58 | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
705 | 58 | return(-4); |
706 | 58 | } |
707 | 1.02M | y++; |
708 | 1.02M | } |
709 | 4.13k | } |
710 | 4.07k | break; |
711 | 19.4k | case 0xFF: |
712 | 19.4k | if ((c = ReadBlobByte(image)) == EOF) /* WHT */ |
713 | 580 | { |
714 | 580 | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
715 | 580 | return(-4); |
716 | 580 | } |
717 | 18.9k | RunCount=c; |
718 | 1.24M | for (i=0; i < SampleSize*(RunCount+1); i++) |
719 | 1.23M | { |
720 | 1.23M | InsertByte6(0xFF); |
721 | 1.22M | } |
722 | 13.3k | break; |
723 | 201k | default: |
724 | 201k | RunCount=bbuf & 0x7F; |
725 | | |
726 | 201k | if (bbuf & 0x80) /* REP */ |
727 | 8.94k | { |
728 | 20.1k | for (i=0; i < SampleSize; i++) |
729 | 11.1k | SampleBuffer[i]=ReadBlobByte(image); |
730 | 572k | for (i=0;i<=RunCount;i++) |
731 | 1.26M | for (bbuf=0;bbuf<SampleSize;bbuf++) |
732 | 701k | InsertByte6(SampleBuffer[bbuf]); |
733 | 8.19k | } |
734 | 192k | else { /* NRP */ |
735 | 1.59M | for (i=0; i< SampleSize*(RunCount+1);i++) |
736 | 1.40M | { |
737 | 1.40M | bbuf=ReadBlobByte(image); |
738 | 1.40M | InsertByte6(bbuf); |
739 | 1.40M | } |
740 | 192k | } |
741 | 195k | if (EOFBlob(image)) |
742 | 1.37k | { |
743 | 1.37k | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
744 | 1.37k | return(-4); |
745 | 1.37k | } |
746 | 328k | } |
747 | 328k | } |
748 | 21.2k | unpack_wpg2_error:; |
749 | 21.2k | FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff); |
750 | 21.2k | return(RetVal); |
751 | 26.3k | } |
752 | | |
753 | | |
754 | | typedef float tCTM[3][3]; |
755 | | |
756 | | static unsigned LoadWPG2Flags(Image *image, char Precision, float *Angle, tCTM *CTM) |
757 | 56.2k | { |
758 | 56.2k | const unsigned char |
759 | 56.2k | TPR=1, |
760 | 56.2k | TRN=2, |
761 | 56.2k | SKW=4, |
762 | 56.2k | SCL=8, |
763 | 56.2k | ROT=0x10, |
764 | 56.2k | OID=0x20, |
765 | 56.2k | LCK=0x80; |
766 | | |
767 | 56.2k | long |
768 | 56.2k | x; |
769 | | |
770 | 56.2k | unsigned |
771 | 56.2k | DenX; |
772 | | |
773 | 56.2k | unsigned |
774 | 56.2k | Flags; |
775 | | |
776 | 56.2k | (void) memset(*CTM,0,sizeof(*CTM)); /*CTM.erase();CTM.resize(3,3);*/ |
777 | 56.2k | (*CTM)[0][0]=1; |
778 | 56.2k | (*CTM)[1][1]=1; |
779 | 56.2k | (*CTM)[2][2]=1; |
780 | | |
781 | 56.2k | Flags=ReadBlobLSBShort(image); |
782 | 56.2k | if (Flags & LCK) /*x=*/ |
783 | 4.08k | (void)ReadBlobLSBLong(image); /*Edit lock*/ |
784 | 56.2k | if (Flags & OID) |
785 | 9.73k | { |
786 | 9.73k | if (Precision==0) |
787 | 4.98k | { |
788 | 4.98k | x = ReadBlobLSBShort(image); |
789 | 4.98k | if (x >= 0x8000) |
790 | 1.46k | { |
791 | 1.46k | Precision = 1; /* Double precision Switched on. */ |
792 | 1.46k | (void) ReadBlobLSBShort(image); |
793 | | /* ObjectId = ((xW & 0x7FFF)<<16) | DenX; */ |
794 | 1.46k | } |
795 | 4.98k | } /*ObjectID*/ |
796 | 4.75k | else |
797 | 4.75k | {/*x=*/ (void) ReadBlobLSBLong(image);} /*ObjectID native (Double precision)*/ |
798 | 9.73k | } |
799 | 56.2k | if (Flags & ROT) |
800 | 25.9k | { |
801 | 25.9k | x=ReadBlobLSBLong(image); /*Rot Angle*/ |
802 | 25.9k | if (Angle) |
803 | 0 | *Angle=(float) (x/65536.0); |
804 | 25.9k | } |
805 | 56.2k | if (Flags & (ROT|SCL)) |
806 | 30.5k | { |
807 | 30.5k | x=ReadBlobLSBLong(image); /*Sx*cos()*/ |
808 | 30.5k | (*CTM)[0][0] = (float)x/0x10000; |
809 | 30.5k | x=ReadBlobLSBLong(image); /*Sy*cos()*/ |
810 | 30.5k | (*CTM)[1][1] = (float)x/0x10000; |
811 | 30.5k | } |
812 | 56.2k | if (Flags & (ROT|SKW)) |
813 | 30.5k | { |
814 | 30.5k | x=ReadBlobLSBLong(image); /*Kx*sin()*/ |
815 | 30.5k | (*CTM)[1][0] = (float)x/0x10000; |
816 | 30.5k | x=ReadBlobLSBLong(image); /*Ky*sin()*/ |
817 | 30.5k | (*CTM)[0][1] = (float)x/0x10000; |
818 | 30.5k | } |
819 | 56.2k | if (Flags & TRN) |
820 | 24.0k | { |
821 | 24.0k | DenX=ReadBlobLSBShort(image); x=ReadBlobLSBLong(image); /*Tx*/ |
822 | 24.0k | (*CTM)[0][2] = (double)x + (float)DenX/0x10000; |
823 | 24.0k | DenX=ReadBlobLSBShort(image); x=ReadBlobLSBLong(image); /*Ty*/ |
824 | 24.0k | (*CTM)[1][2] = (double)x + (float)DenX/0x10000; |
825 | 24.0k | } |
826 | 56.2k | if (Flags & TPR) |
827 | 26.5k | { |
828 | 26.5k | x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Px*/ |
829 | 26.5k | (*CTM)[2][0] = x + (float)DenX/0x10000;; |
830 | 26.5k | x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Py*/ |
831 | 26.5k | (*CTM)[2][1] = x + (float)DenX/0x10000; |
832 | 26.5k | } |
833 | 56.2k | return (Flags); |
834 | 56.2k | } |
835 | | |
836 | | |
837 | | static Image *ExtractPostscript(Image *image,const ImageInfo *image_info, |
838 | | ExtendedSignedIntegralType PS_Offset, |
839 | | size_t PS_Size,ExceptionInfo *exception) |
840 | 6.42M | { |
841 | 6.42M | ImageInfo |
842 | 6.42M | *clone_info; |
843 | | |
844 | 6.42M | Image |
845 | 6.42M | *image2; |
846 | | |
847 | 6.42M | unsigned char |
848 | 6.42M | header_magick[2*MaxTextExtent]; |
849 | | |
850 | 6.42M | void |
851 | 6.42M | *ps_data, |
852 | 6.42M | *ps_data_alloc = (unsigned char *) NULL; |
853 | | |
854 | 6.42M | char |
855 | 6.42M | format[MaxTextExtent]; |
856 | | |
857 | 6.42M | size_t |
858 | 6.42M | header_magick_size; |
859 | | |
860 | 6.42M | magick_off_t |
861 | 6.42M | filesize; |
862 | | |
863 | 6.42M | if (image->logging) |
864 | 6.42M | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
865 | 6.42M | "ExtractPostscript(): PS_Offset=%" MAGICK_OFF_F "d, PS_Size=%" MAGICK_SIZE_T_F "u", |
866 | 6.42M | (magick_off_t) PS_Offset, (MAGICK_SIZE_T) PS_Size); |
867 | | |
868 | | /* |
869 | | Validate that claimed subordinate image data is contained in file size |
870 | | */ |
871 | 6.42M | filesize = GetBlobSize(image); |
872 | 6.42M | if ((PS_Offset > filesize) || ((size_t) (filesize - PS_Offset) < PS_Size)) |
873 | 1.48k | { |
874 | 1.48k | if (image->logging) |
875 | 1.48k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
876 | 1.48k | "ExtractPostscript(): Failed to seek to PS_Offset=%" MAGICK_OFF_F "d", |
877 | 1.48k | (magick_off_t) PS_Offset); |
878 | 1.48k | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename); |
879 | 1.48k | return image; |
880 | 1.48k | } |
881 | | |
882 | | /* |
883 | | Get subordinate file header magick and use it to identify file format |
884 | | */ |
885 | 6.42M | if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset) |
886 | 0 | { |
887 | 0 | if (image->logging) |
888 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
889 | 0 | "ExtractPostscript(): Failed to seek to PS_Offset=%" MAGICK_OFF_F "d", |
890 | 0 | (magick_off_t) PS_Offset); |
891 | 0 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename); |
892 | 0 | return image; |
893 | 0 | } |
894 | 6.42M | header_magick_size = ReadBlob(image, Min(sizeof(header_magick),PS_Size), header_magick); |
895 | 6.42M | format[0]='\0'; |
896 | | /* |
897 | | MagickExport MagickPassFail |
898 | | GetMagickFileFormat(const unsigned char *header, const size_t header_length, |
899 | | char *format, const size_t format_length, |
900 | | ExceptionInfo *exception) |
901 | | */ |
902 | 6.42M | if (GetMagickFileFormat(header_magick,header_magick_size,format, |
903 | 6.42M | sizeof(format),exception) == MagickFail) |
904 | 1.43M | { |
905 | 1.43M | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
906 | 1.43M | "Failed to identify embedded file type!"); |
907 | 1.43M | ThrowException(exception,CorruptImageError,UnableToReadImageHeader,image->filename); |
908 | 1.43M | return image; |
909 | 1.43M | } |
910 | | |
911 | | /* |
912 | | Verify if this is an allowed subordinate image format |
913 | | */ |
914 | 4.99M | if (!ApproveFormatForWPG(format,exception)) |
915 | 8.73k | { |
916 | 8.73k | (void) LogMagickEvent(CoderEvent, GetMagickModule(), |
917 | 8.73k | "Format \"%s\" cannot be embedded inside WPG.", format); |
918 | 8.73k | ThrowException(exception,CorruptImageError,UnableToReadImageHeader,image->filename); |
919 | 8.73k | return image; |
920 | 8.73k | } |
921 | | |
922 | | /* |
923 | | Restore seek offset after reading header |
924 | | */ |
925 | 4.98M | if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset) |
926 | 0 | { |
927 | 0 | if (image->logging) |
928 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
929 | 0 | "ExtractPostscript(): Failed to seek to PS_Offset=%" MAGICK_OFF_F "d", |
930 | 0 | (magick_off_t) PS_Offset); |
931 | 0 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename); |
932 | 0 | return image; |
933 | 0 | } |
934 | | /* |
935 | | Allocate buffer if zero-copy read is not possible. |
936 | | */ |
937 | 4.98M | if (GetBlobStreamData(image) == (unsigned char *) NULL) |
938 | 0 | { |
939 | 0 | ps_data_alloc=MagickAllocateResourceLimitedMemory(unsigned char *, PS_Size); |
940 | 0 | if (ps_data_alloc == (unsigned char *) NULL) |
941 | 0 | { |
942 | 0 | if (image->logging) |
943 | 0 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
944 | 0 | "ExtractPostscript(): Failed to allocate " |
945 | 0 | "%" MAGICK_SIZE_T_F "u bytes of memory", |
946 | 0 | (MAGICK_SIZE_T) PS_Size); |
947 | 0 | ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,image->filename); |
948 | 0 | return image; |
949 | 0 | } |
950 | 0 | } |
951 | | /* |
952 | | Use a zero-copy read when possible to access data |
953 | | */ |
954 | 4.98M | ps_data=ps_data_alloc; |
955 | 4.98M | if (ReadBlobZC(image,PS_Size,&ps_data) != PS_Size) |
956 | 22 | { |
957 | 22 | MagickFreeResourceLimitedMemory(unsigned char *,ps_data_alloc); |
958 | 22 | if (image->logging) |
959 | 22 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
960 | 22 | "ExtractPostscript(): Failed to read %" MAGICK_SIZE_T_F "u bytes of data at" |
961 | 22 | " offset=%" MAGICK_OFF_F "d", |
962 | 22 | (MAGICK_SIZE_T) PS_Size, (magick_off_t) PS_Offset); |
963 | 22 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename); |
964 | 22 | return image; /* return (Image *) NULL; */ |
965 | 22 | } |
966 | 4.98M | if (ps_data_alloc != ps_data) |
967 | 4.98M | { |
968 | 4.98M | if (image->logging) |
969 | 4.98M | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
970 | 4.98M | "ExtractPostscript(): Zero copy read."); |
971 | 4.98M | } |
972 | | #if 0 |
973 | | /* |
974 | | Write in-memory blob to file for test purposes. |
975 | | */ |
976 | | { |
977 | | char file_name[MaxTextExtent]; |
978 | | FILE *file; |
979 | | |
980 | | FormatString(file_name,"wpg-blob.%s",format); |
981 | | if ((file=fopen(file_name,"w")) != (FILE *) NULL) |
982 | | { |
983 | | if (image->logging) |
984 | | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
985 | | "Writing %s...", file_name); |
986 | | (void) fwrite(ps_data, 1, PS_Size, file); |
987 | | (void) fclose(file); |
988 | | } |
989 | | SeekBlob(image,PS_Offset,SEEK_SET); |
990 | | } |
991 | | #endif |
992 | | /* |
993 | | Read nested image from blob, forcing read as Postscript format |
994 | | */ |
995 | 4.98M | if ((clone_info=CloneImageInfo(image_info)) == NULL) |
996 | 0 | { |
997 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,ps_data_alloc); |
998 | 0 | return(image); |
999 | 0 | } |
1000 | 4.98M | clone_info->blob=(_BlobInfoPtr_) NULL; |
1001 | | /* clone_info->length=0; */ |
1002 | 4.98M | (void) strlcpy(clone_info->magick, format, sizeof(clone_info->magick)); |
1003 | 4.98M | (void) strlcpy(clone_info->filename, "", sizeof(clone_info->filename)); |
1004 | 4.98M | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1005 | 4.98M | "Reading embedded \"%s\" content from blob...", clone_info->magick); |
1006 | 4.98M | image2 = BlobToImage(clone_info, ps_data, PS_Size, &image->exception ); |
1007 | 4.98M | MagickFreeResourceLimitedMemory(unsigned char *,ps_data_alloc); |
1008 | 4.98M | if (!image2) |
1009 | 4.97M | { |
1010 | 4.97M | goto FINISH_UNL; |
1011 | 4.97M | } |
1012 | 12.9k | if (exception->severity >= ErrorException) /* When exception is raised, destroy image2 read. */ |
1013 | 2.82k | { |
1014 | 2.82k | if (image->logging) |
1015 | 2.82k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Exception raised during embedded image reading."); |
1016 | 2.82k | CloseBlob(image2); |
1017 | 2.82k | DestroyImageList(image2); |
1018 | 2.82k | goto FINISH_UNL; |
1019 | 2.82k | } |
1020 | 10.1k | if (!GetPixelCachePresent(image2)) |
1021 | 250 | { |
1022 | 250 | if (image->logging) |
1023 | 250 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), "Pixel cache is missing for embedded image."); |
1024 | 250 | CloseBlob(image2); |
1025 | 250 | DestroyImageList(image2); |
1026 | 250 | goto FINISH_UNL; |
1027 | 250 | } |
1028 | | |
1029 | | /* |
1030 | | Replace current image with new image while copying base image |
1031 | | attributes. |
1032 | | */ |
1033 | 9.91k | { |
1034 | 9.91k | Image *p; |
1035 | 9.91k | p = image2; |
1036 | 9.91k | do |
1037 | 9.91k | { |
1038 | 9.91k | (void) strlcpy(p->filename,image->filename,MaxTextExtent); |
1039 | 9.91k | (void) strlcpy(p->magick_filename,image->magick_filename,MaxTextExtent); |
1040 | 9.91k | (void) strlcpy(p->magick,image->magick,MaxTextExtent); |
1041 | | /*image2->depth=image->depth;*/ /* !!!! The image2 depth should not be modified here. Image2 is completely different. */ |
1042 | 9.91k | DestroyBlob(p); |
1043 | | |
1044 | 9.91k | if (p->rows==0 || p->columns==0) |
1045 | 0 | { |
1046 | 0 | DeleteImageFromList(&p); |
1047 | 0 | if (p==NULL) |
1048 | 0 | { |
1049 | 0 | image2 = NULL; |
1050 | 0 | goto FINISH_UNL; /* Nothing to add, skip. */ |
1051 | 0 | } |
1052 | 0 | } |
1053 | 9.91k | else |
1054 | 9.91k | { |
1055 | 9.91k | p->blob = ReferenceBlob(image->blob); |
1056 | 9.91k | p = p->next; |
1057 | 9.91k | } |
1058 | 9.91k | } while (p!=NULL); |
1059 | 9.91k | } |
1060 | | |
1061 | 9.91k | if ((image->rows==0 || image->columns==0) && (image->previous!=NULL || image->next!=NULL)) |
1062 | 344 | { |
1063 | 344 | DeleteImageFromList(&image); |
1064 | 344 | } |
1065 | | |
1066 | 9.91k | AppendImageToList(&image,image2); /* This should append list 'image2' to the list 'image', image2 accepts NULL. */ |
1067 | 9.91k | while (image->next != NULL) |
1068 | 0 | image = image->next; /* Rewind the cursor to the end. */ |
1069 | | |
1070 | 4.98M | FINISH_UNL: |
1071 | 4.98M | DestroyImageInfo(clone_info); |
1072 | 4.98M | return(image); |
1073 | 9.91k | } |
1074 | | |
1075 | | static int EnsureNextImage(const ImageInfo *image_info, Image **pp_image) |
1076 | 409 | { |
1077 | 409 | if (pp_image==NULL) |
1078 | 0 | return -1; |
1079 | 409 | if (*pp_image==NULL) |
1080 | 0 | return -2; |
1081 | 409 | if (image_info==NULL) |
1082 | 0 | return -3; |
1083 | 409 | AllocateNextImage(image_info,*pp_image); |
1084 | 409 | if ((*pp_image)->next == (Image *) NULL) |
1085 | 0 | return -4; |
1086 | 409 | *pp_image = SyncNextImageInList(*pp_image); |
1087 | 409 | (*pp_image)->columns = (*pp_image)->rows = 0; |
1088 | 409 | (*pp_image)->colors = 0; |
1089 | 409 | return 0; |
1090 | 409 | } |
1091 | | |
1092 | | |
1093 | | #define LogHeaderWPG(_WPG_HEADER) \ |
1094 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(), \ |
1095 | 0 | "WPG Header Id=%Xh:\n" \ |
1096 | 0 | " DataOffset=%u\n" \ |
1097 | 0 | " ProductType=%u\n" \ |
1098 | 0 | " FileType=%u\n" \ |
1099 | 0 | " Version=%u.%u\n" \ |
1100 | 0 | " EncryptKey=%u\n" \ |
1101 | 0 | " Reserved=%u", \ |
1102 | 0 | (unsigned int) _WPG_HEADER.FileId, \ |
1103 | 0 | (unsigned int) _WPG_HEADER.DataOffset, \ |
1104 | 0 | (unsigned int) _WPG_HEADER.ProductType, \ |
1105 | 0 | (unsigned int) _WPG_HEADER.FileType, \ |
1106 | 0 | (unsigned int) _WPG_HEADER.MajorVersion, \ |
1107 | 0 | (unsigned int) _WPG_HEADER.MinorVersion, \ |
1108 | 0 | (unsigned int) _WPG_HEADER.EncryptKey, \ |
1109 | 0 | (unsigned int) _WPG_HEADER.Reserved) |
1110 | | |
1111 | | #define LogWPGBitmapType1(_WPG_BITMAP_TYPE1) \ |
1112 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(), \ |
1113 | 0 | "WPG Bitmap1 Header:\n" \ |
1114 | 0 | " Width=%u\n" \ |
1115 | 0 | " Height=%u\n" \ |
1116 | 0 | " Depth=%u\n" \ |
1117 | 0 | " HorzRes=%u\n" \ |
1118 | 0 | " VertRes=%u", \ |
1119 | 0 | (unsigned int) _WPG_BITMAP_TYPE1.Width, \ |
1120 | 0 | (unsigned int) _WPG_BITMAP_TYPE1.Height, \ |
1121 | 0 | (unsigned int) _WPG_BITMAP_TYPE1.Depth, \ |
1122 | 0 | (unsigned int) _WPG_BITMAP_TYPE1.HorzRes, \ |
1123 | 0 | (unsigned int) _WPG_BITMAP_TYPE1.VertRes) |
1124 | | |
1125 | | #define LogWPGBitmapType2(_WPG_BITMAP_TYPE2) \ |
1126 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(), \ |
1127 | 0 | "WPG Bitmap2 Header:\n" \ |
1128 | 0 | " RotAngle=%u\n" \ |
1129 | 0 | " LowLeftX=%u\n" \ |
1130 | 0 | " LowLeftY=%u\n" \ |
1131 | 0 | " UpRightX=%u\n" \ |
1132 | 0 | " UpRightY=%u\n" \ |
1133 | 0 | " Width=%u\n" \ |
1134 | 0 | " Height=%u\n" \ |
1135 | 0 | " Depth=%u\n" \ |
1136 | 0 | " HorzRes=%u\n" \ |
1137 | 0 | " VertRes=%u", \ |
1138 | 0 | (unsigned int) _WPG_BITMAP_TYPE2.RotAngle, \ |
1139 | 0 | (unsigned int) _WPG_BITMAP_TYPE2.LowLeftX, \ |
1140 | 0 | (unsigned int) _WPG_BITMAP_TYPE2.LowLeftY, \ |
1141 | 0 | (unsigned int) _WPG_BITMAP_TYPE2.UpRightX, \ |
1142 | 0 | (unsigned int) _WPG_BITMAP_TYPE2.UpRightY, \ |
1143 | 0 | (unsigned int) _WPG_BITMAP_TYPE2.Width, \ |
1144 | 0 | (unsigned int) _WPG_BITMAP_TYPE2.Height, \ |
1145 | 0 | (unsigned int) _WPG_BITMAP_TYPE2.Depth, \ |
1146 | 0 | (unsigned int) _WPG_BITMAP_TYPE2.HorzRes, \ |
1147 | 0 | (unsigned int) _WPG_BITMAP_TYPE2.VertRes) |
1148 | | |
1149 | | |
1150 | | typedef struct |
1151 | | { |
1152 | | magick_uint16_t StartIndex; |
1153 | | magick_uint16_t NumOfEntries; |
1154 | | } WPGColorMapRec; |
1155 | | |
1156 | | |
1157 | | static void LoadPaletteRec(Image *image, WPGColorMapRec *pWPG_Palette, const int logging) |
1158 | 30.1k | { |
1159 | 30.1k | pWPG_Palette->StartIndex=ReadBlobLSBShort(image); |
1160 | 30.1k | pWPG_Palette->NumOfEntries=ReadBlobLSBShort(image); |
1161 | 30.1k | if (logging) |
1162 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
1163 | 0 | "WPG Color palette:\n" |
1164 | 0 | " StartIndex=%u\n" |
1165 | 0 | " NumOfEntries=%u\n", |
1166 | 0 | (unsigned) pWPG_Palette->StartIndex, |
1167 | 0 | (unsigned) pWPG_Palette->NumOfEntries); |
1168 | | |
1169 | 30.1k | } |
1170 | | |
1171 | | |
1172 | | /* |
1173 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1174 | | % % |
1175 | | % % |
1176 | | % % |
1177 | | % R e a d W P G I m a g e % |
1178 | | % % |
1179 | | % % |
1180 | | % % |
1181 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1182 | | % |
1183 | | % Method ReadWPGImage reads an WPG X image file and returns it. It |
1184 | | % allocates the memory necessary for the new Image structure and returns a |
1185 | | % pointer to the new image. |
1186 | | % |
1187 | | % The format of the ReadWPGImage method is: |
1188 | | % |
1189 | | % Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception) |
1190 | | % |
1191 | | % A description of each parameter follows: |
1192 | | % |
1193 | | % o image: Method ReadWPGImage returns a pointer to the image after |
1194 | | % reading. A null image is returned if there is a memory shortage or if |
1195 | | % the image cannot be read. |
1196 | | % |
1197 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
1198 | | % |
1199 | | % o exception: return any errors or warnings in this structure. |
1200 | | % |
1201 | | */ |
1202 | | static Image *ReadWPGImage(const ImageInfo *image_info, |
1203 | | ExceptionInfo *exception) |
1204 | 173k | { |
1205 | 173k | typedef struct |
1206 | 173k | { |
1207 | 173k | unsigned long FileId; |
1208 | 173k | ExtendedSignedIntegralType DataOffset; /* magick_uint32_t */ |
1209 | 173k | unsigned char ProductType; |
1210 | 173k | unsigned char FileType; |
1211 | 173k | unsigned char MajorVersion; |
1212 | 173k | unsigned char MinorVersion; |
1213 | 173k | unsigned int EncryptKey; |
1214 | 173k | unsigned int Reserved; |
1215 | 173k | } WPGHeader; |
1216 | | |
1217 | 173k | typedef struct |
1218 | 173k | { |
1219 | 173k | unsigned char RecType; |
1220 | 173k | magick_uint32_t RecordLength; |
1221 | 173k | } WPGRecord; |
1222 | | |
1223 | 173k | typedef struct |
1224 | 173k | { |
1225 | 173k | unsigned char Class; |
1226 | 173k | unsigned char RecType; |
1227 | 173k | magick_uint32_t Extension; |
1228 | 173k | magick_uint32_t RecordLength; |
1229 | 173k | } WPG2Record; |
1230 | | |
1231 | 173k | typedef struct |
1232 | 173k | { |
1233 | 173k | unsigned HorizontalUnits; |
1234 | 173k | unsigned VerticalUnits; |
1235 | 173k | unsigned char PosSizePrecision; |
1236 | 173k | } WPG2Start; |
1237 | | |
1238 | 173k | typedef struct |
1239 | 173k | { |
1240 | 173k | unsigned int Width; |
1241 | 173k | unsigned int Height; |
1242 | 173k | unsigned int Depth; |
1243 | 173k | unsigned int HorzRes; |
1244 | 173k | unsigned int VertRes; |
1245 | 173k | } WPGBitmapType1; |
1246 | | |
1247 | 173k | typedef struct |
1248 | 173k | { |
1249 | 173k | unsigned int Width; |
1250 | 173k | unsigned int Height; |
1251 | 173k | unsigned char Depth; |
1252 | 173k | unsigned char Compression; |
1253 | 173k | } WPG2BitmapType1; |
1254 | | |
1255 | 173k | typedef struct |
1256 | 173k | { |
1257 | 173k | unsigned int RotAngle; |
1258 | 173k | unsigned int LowLeftX; |
1259 | 173k | unsigned int LowLeftY; |
1260 | 173k | unsigned int UpRightX; |
1261 | 173k | unsigned int UpRightY; |
1262 | 173k | unsigned int Width; |
1263 | 173k | unsigned int Height; |
1264 | 173k | unsigned int Depth; |
1265 | 173k | unsigned int HorzRes; |
1266 | 173k | unsigned int VertRes; |
1267 | 173k | } WPGBitmapType2; |
1268 | | |
1269 | | /* |
1270 | | typedef struct { |
1271 | | unsigned long PS_unknown1; |
1272 | | unsigned int PS_unknown2; |
1273 | | unsigned int PS_unknown3; |
1274 | | } WPGPSl1Record; |
1275 | | */ |
1276 | | |
1277 | 173k | Image |
1278 | 173k | *image, |
1279 | 173k | *rotated_image; |
1280 | | |
1281 | 173k | unsigned int |
1282 | 173k | status; |
1283 | | |
1284 | 173k | WPGHeader |
1285 | 173k | Header; |
1286 | | |
1287 | 173k | WPGRecord |
1288 | 173k | Rec; |
1289 | | |
1290 | 173k | WPG2Record |
1291 | 173k | Rec2; |
1292 | | |
1293 | 173k | WPG2Start StartWPG; |
1294 | | |
1295 | 173k | WPGBitmapType1 |
1296 | 173k | BitmapHeader1; |
1297 | | |
1298 | 173k | WPG2BitmapType1 |
1299 | 173k | Bitmap2Header1; |
1300 | | |
1301 | 173k | WPGBitmapType2 |
1302 | 173k | BitmapHeader2; |
1303 | | |
1304 | 173k | WPGColorMapRec |
1305 | 173k | WPG_Palette; |
1306 | | |
1307 | 173k | int |
1308 | 173k | i, |
1309 | 173k | bpp; |
1310 | | |
1311 | 173k | int logging; |
1312 | | |
1313 | 173k | long |
1314 | 173k | ldblk; |
1315 | | |
1316 | 173k | unsigned char |
1317 | 173k | *BImgBuff; |
1318 | | |
1319 | 173k | BlobInfo |
1320 | 173k | *TmpBlob; |
1321 | | |
1322 | 173k | magick_off_t |
1323 | 173k | FilePos, |
1324 | 173k | filesize; |
1325 | | |
1326 | 173k | unsigned char * |
1327 | 173k | pPalette = NULL; |
1328 | | |
1329 | 173k | magick_uint16_t |
1330 | 173k | PaletteItems = 0; |
1331 | | |
1332 | 173k | magick_uint32_t |
1333 | 173k | PaletteAllocBytes = 0; |
1334 | | |
1335 | 173k | tCTM |
1336 | 173k | CTM; /*current transform matrix*/ |
1337 | | |
1338 | | /* |
1339 | | Open image file. |
1340 | | */ |
1341 | 173k | assert(image_info != (const ImageInfo *) NULL); |
1342 | 173k | assert(image_info->signature == MagickSignature); |
1343 | 173k | assert(exception != (ExceptionInfo *) NULL); |
1344 | 173k | assert(exception->signature == MagickSignature); |
1345 | | |
1346 | 173k | logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter"); |
1347 | | |
1348 | 173k | image=AllocateImage(image_info); |
1349 | 173k | image->rows=0; |
1350 | 173k | image->columns=0; |
1351 | 173k | image->depth=8; |
1352 | 173k | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
1353 | 173k | if (status == False) |
1354 | 173k | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
1355 | | |
1356 | | /* |
1357 | | Read WPG image. |
1358 | | */ |
1359 | 173k | Header.FileId=ReadBlobLSBLong(image); |
1360 | 173k | Header.DataOffset=(ExtendedSignedIntegralType) ReadBlobLSBLong(image); |
1361 | 173k | Header.ProductType=ReadBlobByte(image); |
1362 | 173k | Header.FileType=ReadBlobByte(image); |
1363 | 173k | Header.MajorVersion=ReadBlobByte(image); |
1364 | 173k | Header.MinorVersion=ReadBlobByte(image); |
1365 | 173k | Header.EncryptKey=ReadBlobLSBShort(image); |
1366 | 173k | Header.Reserved=ReadBlobLSBShort(image); |
1367 | 173k | if (logging) LogHeaderWPG(Header); |
1368 | | |
1369 | 173k | if (Header.FileId!=0x435057FF || Header.FileType!=0x16) |
1370 | 158k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
1371 | 158k | if (Header.EncryptKey!=0) |
1372 | 131k | ThrowReaderException(CoderError,EncryptedWPGImageFileNotSupported,image); |
1373 | | |
1374 | 131k | image->colors = 0; |
1375 | 131k | image->storage_class = DirectClass; |
1376 | 131k | bpp=0; |
1377 | | |
1378 | 131k | if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
1379 | 0 | "File type: %d", Header.FileType); |
1380 | | |
1381 | | /* Determine file size. */ |
1382 | 131k | filesize = GetBlobSize(image); /* zero is returned if the size cannot be determined. */ |
1383 | 131k | if (filesize>0 && BlobIsSeekable(image)) |
1384 | 131k | { |
1385 | 131k | if (filesize > (magick_off_t)0xFFFFFFFF) |
1386 | 0 | filesize = (magick_off_t)0xFFFFFFFF; /* More than 4GiB are not supported in WPG! */ |
1387 | 131k | } |
1388 | 0 | else |
1389 | 0 | { |
1390 | 0 | filesize = (magick_off_t)0xFFFFFFFF; |
1391 | 0 | if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
1392 | 0 | "Blob is not seekable, WPG reader could fail."); |
1393 | 0 | ThrowReaderException(CorruptImageError,AnErrorHasOccurredReadingFromFile,image); |
1394 | 0 | } |
1395 | | |
1396 | 131k | switch (Header.MajorVersion) |
1397 | 131k | { |
1398 | 58.8k | case 1: /* WPG level 1 */ |
1399 | 58.8k | BitmapHeader2.RotAngle = 0; |
1400 | 58.8k | FilePos = Header.DataOffset; |
1401 | 143M | while (!EOFBlob(image)) /* object parser loop */ |
1402 | 143M | { |
1403 | 143M | if (SeekBlob(image,FilePos,SEEK_SET) != FilePos) |
1404 | 0 | break; |
1405 | | |
1406 | 143M | Rec.RecType = 0; |
1407 | 143M | i=ReadBlobByte(image); /* unsigned char RecType, EOF =-1 !!! */ |
1408 | 143M | if (i==EOF) |
1409 | 4.48k | break; |
1410 | 143M | Rec.RecType = (unsigned char) i; |
1411 | 143M | FilePos += 1; |
1412 | | |
1413 | 143M | FilePos += Rd_WP_DWORD(image,&Rec.RecordLength); |
1414 | 143M | if ((magick_off_t)Rec.RecordLength > filesize) |
1415 | 11.1k | { |
1416 | 11.1k | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1417 | 11.1k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
1418 | 0 | } |
1419 | 143M | if (EOFBlob(image)) |
1420 | 0 | break; |
1421 | | |
1422 | 143M | FilePos += (magick_off_t)Rec.RecordLength; |
1423 | 143M | if (FilePos>filesize || FilePos<Header.DataOffset) |
1424 | 28.4k | { |
1425 | 28.4k | if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
1426 | 0 | "Invalid record length: %X", (unsigned)Rec.RecType); |
1427 | 28.4k | break; |
1428 | 28.4k | } |
1429 | 143M | Header.DataOffset = FilePos; |
1430 | | |
1431 | 143M | if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
1432 | 0 | "Parsing object: %X", Rec.RecType); |
1433 | | /* printf("\nParsing object: %u:%X", (unsigned)FilePos, Rec.RecType); */ |
1434 | | |
1435 | 143M | switch (Rec.RecType) |
1436 | 143M | { |
1437 | 1.23k | case 0x0B: /* bitmap type 1 */ |
1438 | 1.23k | BitmapHeader1.Width=ReadBlobLSBShort(image); |
1439 | 1.23k | BitmapHeader1.Height=ReadBlobLSBShort(image); |
1440 | 1.23k | if ((BitmapHeader1.Width == 0) || (BitmapHeader1.Height == 0)) |
1441 | 762 | { |
1442 | 762 | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1443 | 762 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
1444 | 0 | } |
1445 | 470 | BitmapHeader1.Depth=ReadBlobLSBShort(image); |
1446 | 470 | BitmapHeader1.HorzRes=ReadBlobLSBShort(image); |
1447 | 470 | BitmapHeader1.VertRes=ReadBlobLSBShort(image); |
1448 | 470 | if (logging) LogWPGBitmapType1(BitmapHeader1); |
1449 | | |
1450 | 470 | if (image->rows!=0 && image->columns!=0) |
1451 | 11 | { /* Allocate next image structure. */ |
1452 | 11 | if (EnsureNextImage(image_info, &image) < 0) |
1453 | 0 | goto Finish; |
1454 | 11 | } |
1455 | | |
1456 | 470 | if (BitmapHeader1.HorzRes && BitmapHeader1.VertRes) |
1457 | 344 | { |
1458 | 344 | image->units=PixelsPerCentimeterResolution; |
1459 | 344 | image->x_resolution=BitmapHeader1.HorzRes/470.0; |
1460 | 344 | image->y_resolution=BitmapHeader1.VertRes/470.0; |
1461 | 344 | } |
1462 | 470 | image->columns=BitmapHeader1.Width; |
1463 | 470 | image->rows=BitmapHeader1.Height; |
1464 | 470 | bpp=BitmapHeader1.Depth; |
1465 | 470 | if (image->logging) |
1466 | 470 | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1467 | 470 | "Image dimensions %lux%lu, bpp=%u", image->columns, image->rows, bpp); |
1468 | | /* Whole palette is useless for bilevel image. */ |
1469 | 470 | if (bpp==1) |
1470 | 28 | { |
1471 | 28 | image->storage_class = PseudoClass; |
1472 | 28 | image->colors = 2; |
1473 | 28 | if (!AllocateImageColormap(image,2)) goto NoMemory; |
1474 | 28 | image->colormap[0].red = image->colormap[0].green = image->colormap[0].blue = 0; |
1475 | 28 | image->colormap[1].red = image->colormap[1].green = image->colormap[1].blue = MaxRGB; |
1476 | 28 | image->colormap[0].opacity = image->colormap[1].opacity = OpaqueOpacity; |
1477 | 28 | goto UnpackRaster1bpp; /* bypass cached palette for 1bpp. */ |
1478 | 28 | } |
1479 | 442 | goto UnpackRaster; |
1480 | | |
1481 | 28.5k | case 0x0E: /*Color palette */ |
1482 | 28.5k | LoadPaletteRec(image,&WPG_Palette,logging); |
1483 | 28.5k | PaletteItems = WPG_Palette.NumOfEntries; |
1484 | 28.5k | if ((magick_uint32_t)PaletteItems + WPG_Palette.StartIndex > 256) |
1485 | 756 | { |
1486 | 756 | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1487 | 756 | ThrowReaderException(CorruptImageError,ColormapExceedsColorsLimit,image); |
1488 | 0 | } |
1489 | 27.8k | if (pPalette==NULL) |
1490 | 2.64k | { |
1491 | 2.64k | PaletteAllocBytes = 3*256; |
1492 | 2.64k | pPalette = MagickAllocateResourceLimitedMemory(unsigned char *,(size_t)PaletteAllocBytes); |
1493 | 2.64k | if (pPalette==NULL) |
1494 | 2.64k | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
1495 | 679k | for (i=0; i<=255; i++) |
1496 | 676k | { |
1497 | 676k | pPalette[3*i] = WPG1_Palette[i].Red; |
1498 | 676k | pPalette[3*i+1] = WPG1_Palette[i].Green; |
1499 | 676k | pPalette[3*i+2] = WPG1_Palette[i].Blue; |
1500 | 676k | } |
1501 | 2.64k | } |
1502 | 27.8k | if (ReadBlob(image,(size_t) PaletteItems*3,pPalette+((size_t)3*WPG_Palette.StartIndex)) != (size_t) PaletteItems*3) |
1503 | 27 | { |
1504 | 27 | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1505 | 27 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
1506 | 0 | } |
1507 | 27.8k | break; |
1508 | | |
1509 | 4.84M | case 0x11: /* Start PS l1 */ |
1510 | 4.84M | if (Rec.RecordLength > 8) |
1511 | 4.42M | image=ExtractPostscript(image,image_info, |
1512 | 4.42M | TellBlob(image)+8, /* skip PS header in the wpg */ |
1513 | 4.42M | (size_t) (Rec.RecordLength-8),exception); |
1514 | 4.84M | break; |
1515 | | |
1516 | 11.2k | case 0x14: /* bitmap type 2 */ |
1517 | 11.2k | BitmapHeader2.RotAngle=ReadBlobLSBShort(image); |
1518 | 11.2k | BitmapHeader2.LowLeftX=ReadBlobLSBShort(image); |
1519 | 11.2k | BitmapHeader2.LowLeftY=ReadBlobLSBShort(image); |
1520 | 11.2k | BitmapHeader2.UpRightX=ReadBlobLSBShort(image); |
1521 | 11.2k | BitmapHeader2.UpRightY=ReadBlobLSBShort(image); |
1522 | 11.2k | BitmapHeader2.Width=ReadBlobLSBShort(image); |
1523 | 11.2k | BitmapHeader2.Height=ReadBlobLSBShort(image); |
1524 | 11.2k | if ((BitmapHeader2.Width == 0) || (BitmapHeader2.Height == 0)) |
1525 | 754 | { |
1526 | 754 | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1527 | 754 | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
1528 | 0 | } |
1529 | 10.4k | BitmapHeader2.Depth=ReadBlobLSBShort(image); |
1530 | 10.4k | BitmapHeader2.HorzRes=ReadBlobLSBShort(image); |
1531 | 10.4k | BitmapHeader2.VertRes=ReadBlobLSBShort(image); |
1532 | 10.4k | if (logging) LogWPGBitmapType2(BitmapHeader2); |
1533 | | |
1534 | 10.4k | if (image->rows!=0 && image->columns!=0) |
1535 | 10 | { /* Allocate next image structure. */ |
1536 | 10 | if (EnsureNextImage(image_info, &image) < 0) |
1537 | 0 | goto Finish; |
1538 | 10 | } |
1539 | | |
1540 | 10.4k | image->units=PixelsPerCentimeterResolution; |
1541 | 10.4k | image->page.width=(unsigned int) |
1542 | 10.4k | ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0); |
1543 | 10.4k | image->page.height=(unsigned int) |
1544 | 10.4k | ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0); |
1545 | 10.4k | image->page.x=(int) (BitmapHeader2.LowLeftX/470.0); |
1546 | 10.4k | image->page.y=(int) (BitmapHeader2.LowLeftX/470.0); |
1547 | 10.4k | if (BitmapHeader2.HorzRes && BitmapHeader2.VertRes) |
1548 | 6.74k | { |
1549 | 6.74k | image->x_resolution=BitmapHeader2.HorzRes/470.0; |
1550 | 6.74k | image->y_resolution=BitmapHeader2.VertRes/470.0; |
1551 | 6.74k | } |
1552 | 10.4k | image->columns=BitmapHeader2.Width; |
1553 | 10.4k | image->rows=BitmapHeader2.Height; |
1554 | 10.4k | bpp=BitmapHeader2.Depth; |
1555 | 10.4k | if (image->logging) |
1556 | 10.4k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1557 | 10.4k | "Image dimensions %lux%lu, bpp=%u", |
1558 | 10.4k | image->columns, image->rows, bpp); |
1559 | | |
1560 | 10.9k | UnpackRaster: |
1561 | 10.9k | if (bpp>24) |
1562 | 4.45k | { |
1563 | 4.45k | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1564 | 4.45k | ThrowReaderException(CoderError,ColorTypeNotSupported,image); |
1565 | 0 | } |
1566 | | |
1567 | 6.45k | if (pPalette!=NULL && PaletteItems>0) |
1568 | 48 | { |
1569 | 48 | if (bpp>=16 || PaletteItems<(1<<bpp)) |
1570 | 19 | image->colors = PaletteItems; /*WPG_Palette.NumOfEntries;*/ |
1571 | 29 | else |
1572 | 29 | image->colors = 1 << bpp; |
1573 | 48 | if (!AllocateImageColormap(image,image->colors)) |
1574 | 0 | goto NoMemory; |
1575 | 48 | image->storage_class = PseudoClass; |
1576 | 464 | for (i=0; i<(int)image->colors; i++) |
1577 | 416 | { |
1578 | 416 | image->colormap[i].red = ScaleCharToQuantum(pPalette[3*i]); |
1579 | 416 | image->colormap[i].green=ScaleCharToQuantum(pPalette[3*i+1]); |
1580 | 416 | image->colormap[i].blue=ScaleCharToQuantum(pPalette[3*i+2]); |
1581 | 416 | image->colormap[i].opacity = OpaqueOpacity; |
1582 | 416 | } |
1583 | 48 | } |
1584 | | |
1585 | 6.48k | UnpackRaster1bpp: |
1586 | 6.48k | image->depth = bpp; |
1587 | | |
1588 | 6.48k | if ((image->storage_class != PseudoClass) && (bpp != 24) && bpp!=1) |
1589 | 2.51k | { |
1590 | 2.51k | image->colors=1 << bpp; |
1591 | 2.51k | if (!AllocateImageColormap(image,image->colors)) |
1592 | 1.54k | { |
1593 | 1.54k | NoMemory: |
1594 | 1.54k | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1595 | 1.54k | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
1596 | 0 | } |
1597 | 968 | image->storage_class = PseudoClass; |
1598 | | /* printf("Load default colormap \n"); */ |
1599 | 20.1k | for (i=0; (i < (int) image->colors) && (i < 256); i++) |
1600 | 19.1k | { |
1601 | 19.1k | image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red); |
1602 | 19.1k | image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green); |
1603 | 19.1k | image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue); |
1604 | 19.1k | image->colormap[i].opacity = OpaqueOpacity; |
1605 | 19.1k | } |
1606 | 968 | } |
1607 | 3.97k | else |
1608 | 3.97k | { |
1609 | 3.97k | if (bpp < 24) |
1610 | 3.93k | if ((image->colors != (1UL<<bpp)) && (bpp != 24)) |
1611 | 3.87k | if (!ReallocateImageColormap(image,1U<<bpp)) |
1612 | 5 | goto NoMemory; |
1613 | 3.97k | } |
1614 | | |
1615 | 4.93k | if (bpp == 1) |
1616 | 3.90k | { |
1617 | 3.90k | if (image->colors<=0) |
1618 | 0 | { |
1619 | 0 | image->colormap[0].red = |
1620 | 0 | image->colormap[0].green = |
1621 | 0 | image->colormap[0].blue = 0; |
1622 | 0 | image->colormap[0].opacity = OpaqueOpacity; |
1623 | 0 | } |
1624 | 3.90k | if (image->colors<=1 || /* Realloc has been enforced and value [1] remains uninitialised, or .. */ |
1625 | 3.90k | (image->colormap[0].red==0 && image->colormap[0].green==0 && image->colormap[0].blue==0 && |
1626 | 3.89k | image->colormap[1].red==0 && image->colormap[1].green==0 && image->colormap[1].blue==0)) |
1627 | 3.85k | { /* fix crippled monochrome palette */ |
1628 | 3.85k | image->colormap[1].red = |
1629 | 3.85k | image->colormap[1].green = |
1630 | 3.85k | image->colormap[1].blue = MaxRGB; |
1631 | 3.85k | image->colormap[1].opacity = OpaqueOpacity; |
1632 | 3.85k | } |
1633 | 3.90k | } |
1634 | | |
1635 | 4.93k | if (!image_info->ping) |
1636 | 4.93k | if (UnpackWPGRaster(image,bpp) < 0) |
1637 | 4.52k | { /* The raster cannot be unpacked */ |
1638 | 25.3k | DecompressionFailed: |
1639 | 25.3k | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1640 | 25.3k | ThrowReaderException(CoderError,UnableToDecompressImage,image) |
1641 | 25.3k | } |
1642 | | |
1643 | 411 | if (Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping) |
1644 | 387 | { |
1645 | | /* flop command */ |
1646 | 387 | if (BitmapHeader2.RotAngle & 0x8000) |
1647 | 124 | { |
1648 | 124 | rotated_image = FlopImage(image, exception); |
1649 | 124 | if (rotated_image != (Image *)NULL) |
1650 | 124 | { |
1651 | 124 | TmpBlob = rotated_image->blob; |
1652 | 124 | rotated_image->blob = image->blob; |
1653 | 124 | image->blob = TmpBlob; |
1654 | 124 | ReplaceImageInList(&image,rotated_image); |
1655 | 124 | } |
1656 | 124 | } |
1657 | | /* flip command */ |
1658 | 387 | if (BitmapHeader2.RotAngle & 0x2000) |
1659 | 126 | { |
1660 | 126 | rotated_image = FlipImage(image, exception); |
1661 | 126 | if (rotated_image != (Image *) NULL) |
1662 | 126 | { |
1663 | 126 | TmpBlob = rotated_image->blob; |
1664 | 126 | rotated_image->blob = image->blob; |
1665 | 126 | image->blob = TmpBlob; |
1666 | 126 | ReplaceImageInList(&image,rotated_image); |
1667 | 126 | } |
1668 | 126 | } |
1669 | | |
1670 | | /* rotate command */ |
1671 | 387 | if (BitmapHeader2.RotAngle & 0x0FFF) |
1672 | 382 | { |
1673 | 382 | rotated_image = RotateImage(image, |
1674 | 382 | (BitmapHeader2.RotAngle & 0x0FFF), |
1675 | 382 | exception); |
1676 | 382 | if (rotated_image != (Image *) NULL) |
1677 | 371 | { |
1678 | 371 | TmpBlob = rotated_image->blob; |
1679 | 371 | rotated_image->blob = image->blob; |
1680 | 371 | image->blob = TmpBlob; |
1681 | 371 | ReplaceImageInList(&image,rotated_image); |
1682 | 371 | } |
1683 | 382 | } |
1684 | 387 | } |
1685 | | |
1686 | 411 | StopTimer(&image->timer); |
1687 | | |
1688 | 411 | if (image_info->subrange != 0) |
1689 | 411 | if (image->scene >= (image_info->subimage+image_info->subrange-1)) |
1690 | 411 | goto Finish; |
1691 | | |
1692 | 0 | break; |
1693 | | |
1694 | 1.21M | case 0x1B: /* Postscript l2 */ |
1695 | 1.21M | if (Rec.RecordLength>0x3C) |
1696 | 968k | image=ExtractPostscript(image,image_info, |
1697 | 968k | TellBlob(image)+0x3C, /* skip PS l2 header in the wpg */ |
1698 | 968k | (size_t) (Rec.RecordLength-0x3C),exception); |
1699 | 1.21M | break; |
1700 | 143M | } |
1701 | 143M | } |
1702 | 34.4k | break; |
1703 | | |
1704 | 69.4k | case 2: /* WPG level 2 */ |
1705 | 69.4k | (void) memset(CTM,0,sizeof(CTM)); |
1706 | 69.4k | StartWPG.PosSizePrecision = 0; |
1707 | 17.7M | while (!EOFBlob(image)) /* object parser loop */ |
1708 | 17.7M | { |
1709 | 17.7M | if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset) |
1710 | 0 | break; |
1711 | 17.7M | if (EOFBlob(image)) |
1712 | 0 | break; |
1713 | | |
1714 | 17.7M | Rec2.Class=(i=ReadBlobByte(image)); |
1715 | 17.7M | if (i==EOF) |
1716 | 23.7k | break; |
1717 | 17.7M | Rec2.RecType=(i=ReadBlobByte(image)); |
1718 | 17.7M | if (i==EOF) |
1719 | 1.41k | break; |
1720 | 17.7M | Rd_WP_DWORD(image,&Rec2.Extension); |
1721 | 17.7M | Rd_WP_DWORD(image,&Rec2.RecordLength); |
1722 | 17.7M | if (EOFBlob(image)) |
1723 | 9.05k | break; |
1724 | | |
1725 | 17.7M | Header.DataOffset=TellBlob(image)+Rec2.RecordLength; |
1726 | | |
1727 | 17.7M | if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(), |
1728 | 0 | "Parsing object: %X", Rec2.RecType); |
1729 | | |
1730 | 17.7M | switch (Rec2.RecType) |
1731 | 17.7M | { |
1732 | 542k | case 1: |
1733 | 542k | StartWPG.HorizontalUnits=ReadBlobLSBShort(image); |
1734 | 542k | StartWPG.VerticalUnits=ReadBlobLSBShort(image); |
1735 | 542k | StartWPG.PosSizePrecision=ReadBlobByte(image); |
1736 | 542k | break; |
1737 | | |
1738 | 1.54k | case 0x0C: /* Color palette */ |
1739 | 1.54k | LoadPaletteRec(image,&WPG_Palette,logging); |
1740 | | |
1741 | | /* Sanity check for amount of palette entries. */ |
1742 | 1.54k | if (WPG_Palette.NumOfEntries == 0) |
1743 | 432 | { |
1744 | 432 | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1745 | 432 | ThrowReaderException(CorruptImageError,UnrecognizedNumberOfColors,image); |
1746 | 0 | } |
1747 | 1.11k | if ((unsigned) (WPG_Palette.NumOfEntries-1) > MaxMap) |
1748 | 0 | { |
1749 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1750 | 0 | ThrowReaderException(CorruptImageError,ColormapExceedsColorsLimit,image); |
1751 | 0 | } |
1752 | | |
1753 | 1.11k | if ((WPG_Palette.StartIndex > WPG_Palette.NumOfEntries) || |
1754 | 639 | ((((magick_int32_t)WPG_Palette.NumOfEntries-(magick_int32_t)WPG_Palette.StartIndex) > |
1755 | 639 | (((magick_int32_t)Rec2.RecordLength-2-2) / 4)))) |
1756 | 785 | { |
1757 | 785 | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1758 | 785 | ThrowReaderException(CorruptImageError,InvalidColormapIndex,image); |
1759 | 0 | } |
1760 | | |
1761 | | /* Assure that buffer is allocated and the current size */ |
1762 | 326 | if (PaletteAllocBytes != Max(4*(WPG_Palette.StartIndex+WPG_Palette.NumOfEntries),4*256)) |
1763 | 159 | { |
1764 | 159 | unsigned char *new_pPalette; |
1765 | 159 | PaletteAllocBytes = Max(4*(WPG_Palette.StartIndex+WPG_Palette.NumOfEntries),4*256); |
1766 | 159 | new_pPalette=MagickReallocateResourceLimitedMemory(unsigned char *,pPalette,PaletteAllocBytes); |
1767 | 159 | if (new_pPalette == (unsigned char *) NULL) |
1768 | 0 | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1769 | 159 | pPalette=new_pPalette; |
1770 | 159 | } |
1771 | 326 | if (pPalette==NULL) |
1772 | 326 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
1773 | | |
1774 | 326 | PaletteItems = WPG_Palette.NumOfEntries; |
1775 | 83.7k | for (i=0; i<=255; i++) |
1776 | 83.4k | { |
1777 | 83.4k | pPalette[4*i] = WPG1_Palette[i].Red; |
1778 | 83.4k | pPalette[4*i+1] = WPG1_Palette[i].Green; |
1779 | 83.4k | pPalette[4*i+2] = WPG1_Palette[i].Blue; |
1780 | 83.4k | pPalette[4*i+3] = OpaqueOpacity; |
1781 | 83.4k | } |
1782 | 326 | if (ReadBlob(image,(size_t) PaletteItems*4,pPalette+((size_t)4*WPG_Palette.StartIndex)) != (size_t) PaletteItems*4) |
1783 | 105 | { |
1784 | 105 | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1785 | 105 | ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
1786 | 0 | } |
1787 | 221 | break; |
1788 | | |
1789 | 61.6k | case 0x0E: |
1790 | 61.6k | Bitmap2Header1.Width=ReadBlobLSBShort(image); |
1791 | 61.6k | Bitmap2Header1.Height=ReadBlobLSBShort(image); |
1792 | 61.6k | Bitmap2Header1.Depth=ReadBlobByte(image); |
1793 | 61.6k | Bitmap2Header1.Compression=ReadBlobByte(image); |
1794 | | |
1795 | 61.6k | if ((Bitmap2Header1.Width == 0) || (Bitmap2Header1.Height == 0)) |
1796 | 2.70k | { |
1797 | 2.70k | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1798 | 2.70k | ThrowReaderException(CorruptImageError,ImproperImageHeader,image); |
1799 | 0 | } |
1800 | | |
1801 | 58.9k | if (image->rows!=0 && image->columns!=0) |
1802 | 388 | { /* Allocate next image structure. */ |
1803 | 388 | if (EnsureNextImage(image_info, &image) < 0) |
1804 | 0 | goto Finish; |
1805 | 388 | } |
1806 | | |
1807 | 58.9k | if (Bitmap2Header1.Compression > 1) |
1808 | 15.9k | continue; /*Unknown compression method */ |
1809 | 43.0k | switch (Bitmap2Header1.Depth) |
1810 | 43.0k | { |
1811 | 13.5k | case 1: bpp=1; |
1812 | 13.5k | break; |
1813 | 721 | case 2: bpp=2; |
1814 | 721 | break; |
1815 | 1.52k | case 3: bpp=4; |
1816 | 1.52k | break; |
1817 | 10.6k | case 4: bpp=8; |
1818 | 10.6k | break; |
1819 | 1.91k | case 8: bpp=24; |
1820 | 1.91k | break; |
1821 | 14.6k | default: |
1822 | 14.6k | continue; /*Ignore raster with unknown depth*/ |
1823 | 43.0k | } |
1824 | 28.3k | image->columns=Bitmap2Header1.Width; |
1825 | 28.3k | image->rows=Bitmap2Header1.Height; |
1826 | 28.3k | if (image->logging) |
1827 | 28.3k | (void) LogMagickEvent(CoderEvent,GetMagickModule(), |
1828 | 28.3k | "Image dimensions %lux%lu, bpp=%u", |
1829 | 28.3k | image->columns, image->rows, bpp); |
1830 | | |
1831 | 28.3k | if (pPalette!=NULL && PaletteItems>0) |
1832 | 7 | { |
1833 | 7 | if (bpp>=16 || PaletteItems<(1<<bpp)) |
1834 | 3 | image->colors = PaletteItems; /*WPG_Palette.NumOfEntries;*/ |
1835 | 4 | else |
1836 | 4 | image->colors = 1 << bpp; |
1837 | 7 | if (!AllocateImageColormap(image,image->colors)) |
1838 | 0 | goto NoMemory; |
1839 | 7 | image->storage_class = PseudoClass; |
1840 | 34 | for (i=0; i<(int)image->colors; i++) |
1841 | 27 | { |
1842 | 27 | image->colormap[i].red = ScaleCharToQuantum(pPalette[4*i]); |
1843 | 27 | image->colormap[i].green = ScaleCharToQuantum(pPalette[4*i+1]); |
1844 | 27 | image->colormap[i].blue = ScaleCharToQuantum(pPalette[4*i+2]); |
1845 | 27 | image->colormap[i].opacity = ScaleCharToQuantum(pPalette[4*i+3]); |
1846 | 27 | } |
1847 | 7 | } |
1848 | | |
1849 | 28.3k | if ((image->colors == 0) && (bpp != 24)) |
1850 | 26.4k | { |
1851 | 26.4k | image->colors=1 << bpp; |
1852 | 26.4k | if (!AllocateImageColormap(image,image->colors)) |
1853 | 0 | goto NoMemory; |
1854 | 26.4k | image->storage_class = PseudoClass; |
1855 | 26.4k | } |
1856 | 1.92k | else |
1857 | 1.92k | { |
1858 | 1.92k | if (bpp < 24) |
1859 | 6 | if (image->colors!=(1UL<<bpp) && bpp!=24) |
1860 | 2 | if (!ReallocateImageColormap(image,1U<<bpp)) |
1861 | 0 | goto NoMemory; |
1862 | 1.92k | } |
1863 | | |
1864 | 28.3k | switch (Bitmap2Header1.Compression) |
1865 | 28.3k | { |
1866 | 2.04k | case 0: /*Uncompressed raster*/ |
1867 | 2.04k | { |
1868 | 2.04k | ldblk=(long) ((bpp*image->columns+7)/8); |
1869 | 2.04k | BImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk); |
1870 | 2.04k | if (BImgBuff == (unsigned char *) NULL) |
1871 | 0 | goto NoMemory; |
1872 | | |
1873 | 3.09k | for (i=0; i< (long) image->rows; i++) |
1874 | 2.14k | { |
1875 | 2.14k | if (ReadBlob(image,ldblk,(char *) BImgBuff) != (size_t) ldblk) |
1876 | 498 | { |
1877 | 498 | MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff); |
1878 | 498 | ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename); |
1879 | 498 | goto DecompressionFailed; |
1880 | 498 | } |
1881 | 1.64k | if (InsertRow(BImgBuff,i,image,bpp) == MagickFail) |
1882 | 597 | { |
1883 | 597 | MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff); |
1884 | 597 | goto DecompressionFailed; |
1885 | 597 | } |
1886 | 1.64k | } |
1887 | | |
1888 | 953 | MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff); |
1889 | 953 | break; |
1890 | 2.04k | } |
1891 | 26.3k | case 1: /*RLE for WPG2 */ |
1892 | 26.3k | { |
1893 | 26.3k | if ( UnpackWPG2Raster(image,bpp) < 0) |
1894 | 19.7k | goto DecompressionFailed; |
1895 | 6.61k | break; |
1896 | 26.3k | } |
1897 | 28.3k | } |
1898 | | |
1899 | | |
1900 | 7.56k | if (CTM[0][0]<0 && !image_info->ping) |
1901 | 0 | { /*?? RotAngle=360-RotAngle;*/ |
1902 | 0 | rotated_image = FlopImage(image, exception); |
1903 | 0 | if (rotated_image != (Image *) NULL) |
1904 | 0 | { |
1905 | 0 | TmpBlob = rotated_image->blob; |
1906 | 0 | rotated_image->blob = image->blob; |
1907 | 0 | image->blob = TmpBlob; |
1908 | 0 | ReplaceImageInList(&image,rotated_image); |
1909 | 0 | } |
1910 | | /* Try to change CTM according to Flip - I am not sure, must be checked. |
1911 | | Tx(0,0)=-1; Tx(1,0)=0; Tx(2,0)=0; |
1912 | | Tx(0,1)= 0; Tx(1,1)=1; Tx(2,1)=0; |
1913 | | Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll); |
1914 | | Tx(1,2)=0; Tx(2,2)=1; */ |
1915 | 0 | } |
1916 | 7.56k | if (CTM[1][1]<0 && !image_info->ping) |
1917 | 0 | { /*?? RotAngle=360-RotAngle;*/ |
1918 | 0 | rotated_image = FlipImage(image, exception); |
1919 | 0 | if (rotated_image != (Image *) NULL) |
1920 | 0 | { |
1921 | 0 | TmpBlob = rotated_image->blob; |
1922 | 0 | rotated_image->blob = image->blob; |
1923 | 0 | image->blob = TmpBlob; |
1924 | 0 | ReplaceImageInList(&image,rotated_image); |
1925 | 0 | } |
1926 | | /* Try to change CTM according to Flip - I am not sure, must be checked. |
1927 | | float_matrix Tx(3,3); |
1928 | | Tx(0,0)= 1; Tx(1,0)= 0; Tx(2,0)=0; |
1929 | | Tx(0,1)= 0; Tx(1,1)=-1; Tx(2,1)=0; |
1930 | | Tx(0,2)= 0; Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll); |
1931 | | Tx(2,2)=1; */ |
1932 | 0 | } |
1933 | | |
1934 | 7.56k | StopTimer(&image->timer); |
1935 | | |
1936 | 7.56k | if (image_info->subrange != 0) |
1937 | 7.56k | if (image->scene >= (image_info->subimage+image_info->subrange-1)) |
1938 | 7.56k | goto Finish; |
1939 | | |
1940 | 0 | break; |
1941 | | |
1942 | 1.38M | case 0x12: /* Postscript WPG2*/ |
1943 | 1.38M | i=ReadBlobLSBShort(image); |
1944 | 1.38M | if (Rec2.RecordLength > ((unsigned long) i+2)) |
1945 | 1.03M | image=ExtractPostscript(image,image_info, |
1946 | 1.03M | TellBlob(image)+i, /*skip PS header in the wpg2*/ |
1947 | 1.03M | (size_t)Rec2.RecordLength-i-2,exception); |
1948 | 1.38M | break; |
1949 | | |
1950 | 56.2k | case 0x1B: /*bitmap rectangle*/ |
1951 | 56.2k | (void) LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM); /* WPG2Flags */ |
1952 | 56.2k | break; |
1953 | 17.7M | } |
1954 | 17.7M | } |
1955 | | |
1956 | 37.0k | break; |
1957 | | |
1958 | 37.0k | default: |
1959 | 3.46k | { |
1960 | 3.46k | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1961 | 3.46k | ThrowReaderException(CoderError,DataEncodingSchemeIsNotSupported,image); |
1962 | 0 | } |
1963 | 131k | } |
1964 | | |
1965 | 79.4k | Finish: |
1966 | 79.4k | CloseBlob(image); |
1967 | 79.4k | MagickFreeResourceLimitedMemory(unsigned char *,pPalette); |
1968 | | |
1969 | 79.4k | { |
1970 | 79.4k | Image |
1971 | 79.4k | *p; |
1972 | | |
1973 | 79.4k | long |
1974 | 79.4k | scene=0; |
1975 | | |
1976 | | /* |
1977 | | Rewind list, removing any empty images while rewinding. |
1978 | | */ |
1979 | 79.4k | p=image; /* reverted GetFirstImageInList(image); */ |
1980 | 79.4k | image=NULL; |
1981 | 167k | while (p != (Image *) NULL) |
1982 | 88.1k | { |
1983 | 88.1k | Image *tmp=p; |
1984 | 88.1k | if ((p->rows == 0) || (p->columns == 0)) |
1985 | 71.5k | { |
1986 | 71.5k | p=p->previous; |
1987 | 71.5k | DeleteImageFromList(&tmp); |
1988 | 71.5k | } |
1989 | 16.6k | else |
1990 | 16.6k | { |
1991 | 16.6k | image=p; |
1992 | 16.6k | p=p->previous; |
1993 | 16.6k | } |
1994 | 88.1k | } |
1995 | | |
1996 | | /* |
1997 | | Fix scene numbers |
1998 | | */ |
1999 | 96.1k | for (p=image; p != (Image *) NULL; p=p->next) |
2000 | 16.6k | p->scene=scene++; |
2001 | 79.4k | } |
2002 | | |
2003 | 79.4k | if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),"return"); |
2004 | 79.4k | if (image==NULL) |
2005 | 69.7k | ThrowReaderException(CorruptImageError,ImageFileDoesNotContainAnyImageData,image); |
2006 | 9.68k | return(image); |
2007 | 79.4k | } |
2008 | | |
2009 | | |
2010 | | /* RLE helper structure. */ |
2011 | | typedef struct |
2012 | | { |
2013 | | unsigned char count; |
2014 | | unsigned char pos; |
2015 | | unsigned char buf[254]; |
2016 | | } WPG_RLE_packer; |
2017 | | |
2018 | | /* FILE *DebugRLE = NULL; */ |
2019 | | |
2020 | | static void WPG_RLE_Flush(WPG_RLE_packer *WPG_RLE, Image *image, unsigned char n) |
2021 | 309k | { |
2022 | 309k | if (n>WPG_RLE->pos) |
2023 | 29.3k | n=WPG_RLE->pos; |
2024 | 309k | if (n>0x7F) |
2025 | 0 | n=0x7F; |
2026 | 309k | if (n>0) |
2027 | 93.1k | { |
2028 | | /* if (DebugRLE) fprintf(DebugRLE," size=%X",n); */ |
2029 | 93.1k | WriteBlobByte(image,n); |
2030 | 93.1k | WriteBlob(image, n, WPG_RLE->buf); |
2031 | 93.1k | WPG_RLE->pos -= n; |
2032 | 93.1k | if (WPG_RLE->pos>0) |
2033 | 78.4k | memcpy(WPG_RLE->buf, WPG_RLE->buf+n, n); |
2034 | 14.7k | else |
2035 | 14.7k | WPG_RLE->count = 0; |
2036 | 93.1k | } |
2037 | 309k | } |
2038 | | |
2039 | | |
2040 | | static void WPG_RLE_AddCharacter(WPG_RLE_packer *WPG_RLE, unsigned char b, Image *image) |
2041 | 13.3M | { |
2042 | 13.3M | WPG_RLE->buf[WPG_RLE->pos++] = b; |
2043 | | |
2044 | | /* if (DebugRLE) |
2045 | | { |
2046 | | fprintf(DebugRLE,"\n%u",b); |
2047 | | if (WPG_RLE->pos>=0x7E) |
2048 | | fprintf(DebugRLE," *%u %X", WPG_RLE->pos, WPG_RLE->pos); |
2049 | | } */ |
2050 | | |
2051 | 13.3M | if (WPG_RLE->pos>1) |
2052 | 13.3M | { |
2053 | 13.3M | if (WPG_RLE->count==0x7E || WPG_RLE->buf[WPG_RLE->pos-2]!=b) |
2054 | 568k | { |
2055 | 568k | if (WPG_RLE->count>=1) |
2056 | 199k | { |
2057 | 199k | WPG_RLE->count++; /* True number of repeated BYTEs. */ |
2058 | 199k | WPG_RLE_Flush(WPG_RLE, image, WPG_RLE->pos-1-WPG_RLE->count); |
2059 | 199k | WriteBlobByte(image, WPG_RLE->count|0x80); |
2060 | 199k | WriteBlobByte(image, WPG_RLE->buf[0]); |
2061 | | /* if (DebugRLE) fprintf(DebugRLE," count=%X, val=%X",WPG_RLE->count,WPG_RLE->buf[0]); */ |
2062 | 199k | WPG_RLE->pos = 1; |
2063 | 199k | WPG_RLE->buf[0] = b; |
2064 | 199k | } |
2065 | 568k | WPG_RLE->count = 0; |
2066 | 568k | } |
2067 | 12.7M | else |
2068 | 12.7M | WPG_RLE->count++; |
2069 | 13.3M | } |
2070 | | |
2071 | 13.3M | if (WPG_RLE->pos-WPG_RLE->count>0x7E) /* We have uncompressible block with size 0x7F. */ |
2072 | 104 | { |
2073 | 104 | WPG_RLE_Flush(WPG_RLE, image, 0x7F); |
2074 | 104 | return; |
2075 | 104 | } |
2076 | 13.3M | if (WPG_RLE->pos>0x7E && WPG_RLE->count>=1) |
2077 | 80.1k | { |
2078 | 80.1k | WPG_RLE_Flush(WPG_RLE, image, WPG_RLE->pos-1-WPG_RLE->count); |
2079 | 80.1k | return; |
2080 | 80.1k | } |
2081 | 13.3M | } |
2082 | | |
2083 | | |
2084 | | static void WPG_RLE_FinalFlush(WPG_RLE_packer *WPG_RLE, Image *image) |
2085 | 57.3k | { |
2086 | 57.3k | if (WPG_RLE->count>1) |
2087 | 42.6k | { |
2088 | 42.6k | WPG_RLE_AddCharacter(WPG_RLE, WPG_RLE->buf[WPG_RLE->pos-1]^0xFF, image); /* Add a fake BYTE. */ |
2089 | 42.6k | WPG_RLE->pos = 0; /* Take a last fake BYTE away. */ |
2090 | 42.6k | } |
2091 | 14.6k | else |
2092 | 14.6k | { |
2093 | 14.6k | WPG_RLE_Flush(WPG_RLE,image,0x7F); |
2094 | 14.6k | WPG_RLE_Flush(WPG_RLE,image,0x7F); |
2095 | 14.6k | WPG_RLE->count = 0; |
2096 | 14.6k | } |
2097 | 57.3k | } |
2098 | | |
2099 | | |
2100 | | static void WPG_RLE_AddBlock(WPG_RLE_packer *WPG_RLE, Image *image, const unsigned char *blk, magick_uint16_t size) |
2101 | 57.3k | { |
2102 | 13.4M | while (size-- > 0) |
2103 | 13.3M | { |
2104 | 13.3M | WPG_RLE_AddCharacter(WPG_RLE, *blk, image); |
2105 | 13.3M | blk++; |
2106 | 13.3M | } |
2107 | 57.3k | } |
2108 | | |
2109 | | |
2110 | | static void WPG_RLE_Init(WPG_RLE_packer *WPG_RLE) |
2111 | 889 | { |
2112 | 889 | WPG_RLE->pos = WPG_RLE->count = 0; |
2113 | 889 | } |
2114 | | |
2115 | | |
2116 | | /* |
2117 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2118 | | % % |
2119 | | % % |
2120 | | % % |
2121 | | % W r i t e W P G I m a g e % |
2122 | | % % |
2123 | | % % |
2124 | | % % |
2125 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2126 | | % |
2127 | | % Function WriteWPGImage writes an WPG image to a file. |
2128 | | % |
2129 | | % The format of the WriteWPGImage method is: |
2130 | | % |
2131 | | % unsigned int WriteWPGImage(const ImageInfo *image_info,Image *image) |
2132 | | % |
2133 | | % A description of each parameter follows. |
2134 | | % |
2135 | | % o status: Function WriteWPGImage return True if the image is written. |
2136 | | % False is returned is there is a memory shortage or if the image file |
2137 | | % fails to write. |
2138 | | % |
2139 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
2140 | | % |
2141 | | % o image: A pointer to an Image structure. |
2142 | | */ |
2143 | | static MagickPassFail WriteWPGImage(const ImageInfo *image_info, Image *image) |
2144 | 889 | { |
2145 | 889 | long |
2146 | 889 | y; |
2147 | | |
2148 | 889 | unsigned int |
2149 | 889 | status; |
2150 | | |
2151 | 889 | int |
2152 | 889 | logging; |
2153 | | |
2154 | 889 | unsigned char |
2155 | 889 | StoredPlanes; |
2156 | | |
2157 | 889 | unsigned |
2158 | 889 | ldblk; |
2159 | | |
2160 | 889 | magick_off_t |
2161 | 889 | NumericOffs, |
2162 | 889 | CurrOffs; |
2163 | | |
2164 | 889 | QuantizeInfo |
2165 | 889 | quantize_info; |
2166 | | |
2167 | 889 | WPG_RLE_packer |
2168 | 889 | PackRLE; |
2169 | | |
2170 | 889 | unsigned char |
2171 | 889 | *pixels; |
2172 | | |
2173 | | /* |
2174 | | Open output image file. |
2175 | | */ |
2176 | 889 | assert(image_info != (const ImageInfo *) NULL); |
2177 | 889 | assert(image_info->signature == MagickSignature); |
2178 | 889 | assert(image != (Image *) NULL); |
2179 | 889 | assert(image->signature == MagickSignature); |
2180 | 889 | logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter WPG"); |
2181 | 889 | status = OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception); |
2182 | 889 | if (status == MagickFail) |
2183 | 889 | ThrowWriterException(FileOpenError,UnableToOpenFile,image); |
2184 | 889 | WPG_RLE_Init(&PackRLE); |
2185 | | |
2186 | 889 | (void)TransformColorspace(image,RGBColorspace); |
2187 | | |
2188 | 889 | if ((image->storage_class == DirectClass) || |
2189 | 136 | ((image->storage_class == PseudoClass) && (image->colors<=0 || image->colors>256))) |
2190 | 755 | { |
2191 | 755 | GetQuantizeInfo(&quantize_info); |
2192 | 755 | quantize_info.dither = image_info->dither; |
2193 | 755 | quantize_info.number_colors = 256; |
2194 | 755 | status = QuantizeImage(&quantize_info,image); |
2195 | 755 | if (status==MagickFail || image->colors==0) |
2196 | 0 | goto ImageFailure; |
2197 | 755 | } |
2198 | 889 | if (image->colors <= 2) |
2199 | 456 | { |
2200 | 456 | StoredPlanes=1; |
2201 | 456 | ldblk = (image->columns+7)/8; |
2202 | 456 | } else if (image->colors <= 16) |
2203 | 127 | { |
2204 | 127 | StoredPlanes=4; |
2205 | 127 | ldblk = (image->columns+1)/2; |
2206 | 127 | } else |
2207 | 306 | { |
2208 | 306 | StoredPlanes = 8; |
2209 | 306 | ldblk = image->columns; |
2210 | 306 | } |
2211 | | |
2212 | 889 | pixels = MagickAllocateResourceLimitedMemory(unsigned char *,(size_t)(ldblk)); |
2213 | 889 | if (pixels == (unsigned char *) NULL) |
2214 | 889 | ThrowWriterException(ResourceLimitError,MemoryAllocationFailed,image); |
2215 | | |
2216 | | /* Write WPG header. */ |
2217 | 889 | WriteBlobLSBLong(image,0x435057FF); /* DWORD FileId */ |
2218 | 889 | WriteBlobLSBLong(image,16); /* DWORD DataOffset; */ |
2219 | 889 | WriteBlobByte(image,1); /* BYTE Product Type */ |
2220 | 889 | WriteBlobByte(image,0x16); /* BYTE FileType; */ |
2221 | 889 | WriteBlobByte(image,1); /* BYTE MajorVersion; */ |
2222 | 889 | WriteBlobByte(image,0); /* BYTE MinorVersion; */ |
2223 | 889 | WriteBlobLSBShort(image,0); /* WORD EncryptKey; */ |
2224 | 889 | WriteBlobLSBShort(image,0); /* WORD Reserved; */ |
2225 | | |
2226 | | /* Start WPG l1 */ |
2227 | 889 | WriteBlobByte(image,0xF); |
2228 | 889 | WriteBlobByte(image,0x6); |
2229 | 889 | WriteBlobByte(image,1); /* BYTE Version number */ |
2230 | 889 | WriteBlobByte(image,0); /* BYTE Flags (bit 0 PostScript, maybe bitmap, bit 1 PostScript, no bitmap */ |
2231 | 889 | WriteBlobLSBShort(image,image->columns); /* WORD Width of image (arbitrary units) */ |
2232 | 889 | WriteBlobLSBShort(image,image->rows); /* WORD Height of image (arbitrary units) */ |
2233 | | |
2234 | | /* Palette */ |
2235 | 889 | if (StoredPlanes>1) |
2236 | 433 | { |
2237 | 433 | magick_uint16_t i; |
2238 | 433 | WriteBlobByte(image,0xE); |
2239 | 433 | i = 4+3*(1<<StoredPlanes); |
2240 | 433 | if (i<0xFF) |
2241 | 127 | WriteBlobByte(image,i); |
2242 | 306 | else |
2243 | 306 | { |
2244 | 306 | WriteBlobByte(image,0xFF); |
2245 | 306 | WriteBlobLSBShort(image,i); |
2246 | 306 | } |
2247 | 433 | WriteBlobLSBShort(image,0); /* Start index */ |
2248 | 433 | WriteBlobLSBShort(image,1<<StoredPlanes); /* Num entries */ |
2249 | | |
2250 | 80.8k | for (i=0; i<(1<<StoredPlanes); i++) |
2251 | 80.3k | { |
2252 | 80.3k | if (i>=image->colors || image->colormap==NULL) |
2253 | 28.4k | { |
2254 | 28.4k | WriteBlobByte(image,i); |
2255 | 28.4k | WriteBlobByte(image,i); |
2256 | 28.4k | WriteBlobByte(image,i); |
2257 | 28.4k | } |
2258 | 51.8k | else |
2259 | 51.8k | { |
2260 | 51.8k | WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].red)); |
2261 | 51.8k | WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].green)); |
2262 | 51.8k | WriteBlobByte(image,ScaleQuantumToChar(image->colormap[i].blue)); |
2263 | 51.8k | } |
2264 | 80.3k | } |
2265 | 433 | } |
2266 | | |
2267 | | /* Bitmap 1 header */ |
2268 | 889 | WriteBlobByte(image,0xB); |
2269 | 889 | WriteBlobByte(image,0xFF); |
2270 | 889 | NumericOffs = TellBlob(image); |
2271 | 889 | WriteBlobLSBShort(image,0x8000); |
2272 | 889 | WriteBlobLSBShort(image,0); |
2273 | | |
2274 | 889 | WriteBlobLSBShort(image,image->columns); /* WORD Width */ |
2275 | 889 | WriteBlobLSBShort(image,image->rows); /* WORD Height */ |
2276 | 889 | WriteBlobLSBShort(image,StoredPlanes); /* WORD Depth; */ |
2277 | 889 | WriteBlobLSBShort(image,75); /* WORD HorzRes; */ |
2278 | 889 | WriteBlobLSBShort(image,75); /* WORD VertRes; */ |
2279 | | |
2280 | | /* |
2281 | | Store image data. |
2282 | | */ |
2283 | 58.2k | for (y=0; y<(long)image->rows; y++) |
2284 | 57.3k | { |
2285 | | /* if (y==1310 && DebugRLE==NULL) DebugRLE=fopen("o:\\temp\\14\\debug.txt","wb"); */ |
2286 | | /* if (y>1310 && DebugRLE) {fclose(DebugRLE);DebugRLE=NULL;} */ |
2287 | | |
2288 | 57.3k | if (AcquireImagePixels(image,0,y,image->columns,1,&image->exception) == (const PixelPacket *)NULL) |
2289 | 0 | { |
2290 | 0 | status = MagickFail; |
2291 | 0 | break; |
2292 | 0 | } |
2293 | 57.3k | if (ExportImagePixelArea(image, (StoredPlanes==1)?GrayQuantum:IndexQuantum, StoredPlanes,pixels,0,0) != MagickPass) |
2294 | 0 | { |
2295 | 0 | status = MagickFail; |
2296 | 0 | break; |
2297 | 0 | } |
2298 | 57.3k | WPG_RLE_AddBlock(&PackRLE,image,pixels,ldblk); |
2299 | 57.3k | WPG_RLE_FinalFlush(&PackRLE,image); |
2300 | 57.3k | } |
2301 | | |
2302 | 889 | CurrOffs = TellBlob(image); |
2303 | 889 | SeekBlob(image,NumericOffs,SEEK_SET); |
2304 | 889 | NumericOffs = CurrOffs - NumericOffs - 4; |
2305 | 889 | WriteBlobLSBShort(image, 0x8000|(NumericOffs>>16)); |
2306 | 889 | WriteBlobLSBShort(image, NumericOffs&0xFFFF); |
2307 | 889 | SeekBlob(image,CurrOffs,SEEK_SET); |
2308 | | |
2309 | | /* End of WPG data */ |
2310 | 889 | WriteBlobByte(image,0x10); |
2311 | 889 | WriteBlobByte(image,0); |
2312 | | |
2313 | 889 | MagickFreeResourceLimitedMemory(unsigned char *,pixels); |
2314 | 889 | ImageFailure: |
2315 | 889 | status &= CloseBlob(image); |
2316 | | |
2317 | | |
2318 | 889 | if (logging) |
2319 | 0 | (void)LogMagickEvent(CoderEvent,GetMagickModule(),"return WPG"); |
2320 | | |
2321 | 889 | return(status); |
2322 | 889 | } |
2323 | | |
2324 | | |
2325 | | /* |
2326 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2327 | | % % |
2328 | | % % |
2329 | | % % |
2330 | | % R e g i s t e r W P G I m a g e % |
2331 | | % % |
2332 | | % % |
2333 | | % % |
2334 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2335 | | % |
2336 | | % Method RegisterWPGImage adds attributes for the WPG image format to |
2337 | | % the list of supported formats. The attributes include the image format |
2338 | | % tag, a method to read and/or write the format, whether the format |
2339 | | % supports the saving of more than one frame to the same file or blob, |
2340 | | % whether the format supports native in-memory I/O, and a brief |
2341 | | % description of the format. |
2342 | | % |
2343 | | % The format of the RegisterWPGImage method is: |
2344 | | % |
2345 | | % RegisterWPGImage(void) |
2346 | | % |
2347 | | */ |
2348 | | ModuleExport void RegisterWPGImage(void) |
2349 | 4 | { |
2350 | 4 | MagickInfo |
2351 | 4 | *entry; |
2352 | | |
2353 | 4 | entry=SetMagickInfo("WPG"); |
2354 | 4 | entry->decoder=(DecoderHandler) ReadWPGImage; |
2355 | 4 | entry->encoder = (EncoderHandler)WriteWPGImage; |
2356 | 4 | entry->magick=(MagickHandler) IsWPG; |
2357 | 4 | entry->description="Word Perfect Graphics"; |
2358 | 4 | entry->module="WPG"; |
2359 | 4 | entry->seekable_stream=True; |
2360 | 4 | entry->adjoin=MagickFalse; |
2361 | 4 | entry->coder_class=UnstableCoderClass; |
2362 | 4 | (void) RegisterMagickInfo(entry); |
2363 | 4 | } |
2364 | | |
2365 | | /* |
2366 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2367 | | % % |
2368 | | % % |
2369 | | % % |
2370 | | % U n r e g i s t e r W P G I m a g e % |
2371 | | % % |
2372 | | % % |
2373 | | % % |
2374 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2375 | | % |
2376 | | % Method UnregisterWPGImage removes format registrations made by the |
2377 | | % WPG module from the list of supported formats. |
2378 | | % |
2379 | | % The format of the UnregisterWPGImage method is: |
2380 | | % |
2381 | | % UnregisterWPGImage(void) |
2382 | | % |
2383 | | */ |
2384 | | ModuleExport void UnregisterWPGImage(void) |
2385 | 0 | { |
2386 | 0 | (void) UnregisterMagickInfo("WPG"); |
2387 | 0 | } |