1 /*
2 % Copyright (C) 2003-2020 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 - 2018 %
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/utility.h"
50
51
52 typedef struct
53 {
54 unsigned char Red;
55 unsigned char Blue;
56 unsigned char Green;
57 } RGB_Record;
58
59 /* Default palette for WPG level 1 */
60 static const RGB_Record WPG1_Palette[256]={
61 { 0, 0, 0}, { 0, 0,168},
62 { 0,168, 0}, { 0,168,168},
63 {168, 0, 0}, {168, 0,168},
64 {168, 84, 0}, {168,168,168},
65 { 84, 84, 84}, { 84, 84,252},
66 { 84,252, 84}, { 84,252,252},
67 {252, 84, 84}, {252, 84,252},
68 {252,252, 84}, {252,252,252}, /*16*/
69 { 0, 0, 0}, { 20, 20, 20},
70 { 32, 32, 32}, { 44, 44, 44},
71 { 56, 56, 56}, { 68, 68, 68},
72 { 80, 80, 80}, { 96, 96, 96},
73 {112,112,112}, {128,128,128},
74 {144,144,144}, {160,160,160},
75 {180,180,180}, {200,200,200},
76 {224,224,224}, {252,252,252}, /*32*/
77 { 0, 0,252}, { 64, 0,252},
78 {124, 0,252}, {188, 0,252},
79 {252, 0,252}, {252, 0,188},
80 {252, 0,124}, {252, 0, 64},
81 {252, 0, 0}, {252, 64, 0},
82 {252,124, 0}, {252,188, 0},
83 {252,252, 0}, {188,252, 0},
84 {124,252, 0}, { 64,252, 0}, /*48*/
85 { 0,252, 0}, { 0,252, 64},
86 { 0,252,124}, { 0,252,188},
87 { 0,252,252}, { 0,188,252},
88 { 0,124,252}, { 0, 64,252},
89 {124,124,252}, {156,124,252},
90 {188,124,252}, {220,124,252},
91 {252,124,252}, {252,124,220},
92 {252,124,188}, {252,124,156}, /*64*/
93 {252,124,124}, {252,156,124},
94 {252,188,124}, {252,220,124},
95 {252,252,124}, {220,252,124},
96 {188,252,124}, {156,252,124},
97 {124,252,124}, {124,252,156},
98 {124,252,188}, {124,252,220},
99 {124,252,252}, {124,220,252},
100 {124,188,252}, {124,156,252}, /*80*/
101 {180,180,252}, {196,180,252},
102 {216,180,252}, {232,180,252},
103 {252,180,252}, {252,180,232},
104 {252,180,216}, {252,180,196},
105 {252,180,180}, {252,196,180},
106 {252,216,180}, {252,232,180},
107 {252,252,180}, {232,252,180},
108 {216,252,180}, {196,252,180}, /*96*/
109 {180,220,180}, {180,252,196},
110 {180,252,216}, {180,252,232},
111 {180,252,252}, {180,232,252},
112 {180,216,252}, {180,196,252},
113 {0,0,112}, {28,0,112},
114 {56,0,112}, {84,0,112},
115 {112,0,112}, {112,0,84},
116 {112,0,56}, {112,0,28}, /*112*/
117 {112,0,0}, {112,28,0},
118 {112,56,0}, {112,84,0},
119 {112,112,0}, {84,112,0},
120 {56,112,0}, {28,112,0},
121 {0,112,0}, {0,112,28},
122 {0,112,56}, {0,112,84},
123 {0,112,112}, {0,84,112},
124 {0,56,112}, {0,28,112}, /*128*/
125 {56,56,112}, {68,56,112},
126 {84,56,112}, {96,56,112},
127 {112,56,112}, {112,56,96},
128 {112,56,84}, {112,56,68},
129 {112,56,56}, {112,68,56},
130 {112,84,56}, {112,96,56},
131 {112,112,56}, {96,112,56},
132 {84,112,56}, {68,112,56}, /*144*/
133 {56,112,56}, {56,112,69},
134 {56,112,84}, {56,112,96},
135 {56,112,112}, {56,96,112},
136 {56,84,112}, {56,68,112},
137 {80,80,112}, {88,80,112},
138 {96,80,112}, {104,80,112},
139 {112,80,112}, {112,80,104},
140 {112,80,96}, {112,80,88}, /*160*/
141 {112,80,80}, {112,88,80},
142 {112,96,80}, {112,104,80},
143 {112,112,80}, {104,112,80},
144 {96,112,80}, {88,112,80},
145 {80,112,80}, {80,112,88},
146 {80,112,96}, {80,112,104},
147 {80,112,112}, {80,114,112},
148 {80,96,112}, {80,88,112}, /*176*/
149 {0,0,64}, {16,0,64},
150 {32,0,64}, {48,0,64},
151 {64,0,64}, {64,0,48},
152 {64,0,32}, {64,0,16},
153 {64,0,0}, {64,16,0},
154 {64,32,0}, {64,48,0},
155 {64,64,0}, {48,64,0},
156 {32,64,0}, {16,64,0}, /*192*/
157 {0,64,0}, {0,64,16},
158 {0,64,32}, {0,64,48},
159 {0,64,64}, {0,48,64},
160 {0,32,64}, {0,16,64},
161 {32,32,64}, {40,32,64},
162 {48,32,64}, {56,32,64},
163 {64,32,64}, {64,32,56},
164 {64,32,48}, {64,32,40}, /*208*/
165 {64,32,32}, {64,40,32},
166 {64,48,32}, {64,56,32},
167 {64,64,32}, {56,64,32},
168 {48,64,32}, {40,64,32},
169 {32,64,32}, {32,64,40},
170 {32,64,48}, {32,64,56},
171 {32,64,64}, {32,56,64},
172 {32,48,64}, {32,40,64}, /*224*/
173 {44,44,64}, {48,44,64},
174 {52,44,64}, {60,44,64},
175 {64,44,64}, {64,44,60},
176 {64,44,52}, {64,44,48},
177 {64,44,44}, {64,48,44},
178 {64,52,44}, {64,60,44},
179 {64,64,44}, {60,64,44},
180 {52,64,44}, {48,64,44}, /*240*/
181 {44,64,44}, {44,64,48},
182 {44,64,52}, {44,64,60},
183 {44,64,64}, {44,60,64},
184 {44,55,64}, {44,48,64},
185 {0,0,0}, {0,0,0},
186 {0,0,0}, {0,0,0},
187 {0,0,0}, {0,0,0},
188 {0,0,0}, {0,0,0} /*256*/
189 };
190
191
ApproveFormatForWPG(const char * Format)192 static int ApproveFormatForWPG(const char *Format)
193 {
194 if(!strcmp(Format,"PFB")) return 0;
195 return 1;
196 }
197
198
199
200 /*
201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202 % %
203 % %
204 % %
205 % I s W P G %
206 % %
207 % %
208 % %
209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210 %
211 % IsWPG() returns True if the image format type, identified by the magick
212 % string, is WPG.
213 %
214 % The format of the IsWPG method is:
215 %
216 % unsigned int IsWPG(const unsigned char *magick,const size_t length)
217 %
218 % A description of each parameter follows:
219 %
220 % o status: Method IsWPG returns True if the image format type is WPG.
221 %
222 % o magick: This string is generally the first few bytes of an image file
223 % or blob.
224 %
225 % o length: Specifies the length of the magick string.
226 %
227 %
228 */
IsWPG(const unsigned char * magick,const size_t length)229 static unsigned int IsWPG(const unsigned char *magick,const size_t length)
230 {
231 if (length < 4)
232 return(False);
233 if (memcmp(magick,"\377WPC",4) == 0)
234 return(True);
235 return(False);
236 }
237
ReallocColormap(Image * image,unsigned int colors)238 static MagickPassFail ReallocColormap(Image *image,unsigned int colors)
239 {
240 PixelPacket *colormap;
241
242 /* FIXME: This implementation would be better using a true realloc */
243 colormap=MagickAllocateClearedArray(PixelPacket *,colors,sizeof(PixelPacket));
244 if (colormap != (PixelPacket *) NULL)
245 {
246 if (image->colormap != (PixelPacket *) NULL)
247 {
248 (void) memcpy(colormap,image->colormap,
249 (size_t) Min(image->colors,colors)*sizeof(PixelPacket));
250 MagickFreeMemory(image->colormap);
251 }
252 image->colormap = colormap;
253 image->colors = colors;
254 return MagickPass;
255 }
256
257 return MagickFail;
258 }
259
Rd_WP_DWORD(Image * image,unsigned long * d)260 static int Rd_WP_DWORD(Image *image, unsigned long *d)
261 {
262 unsigned char b;
263
264 b = ReadBlobByte(image);
265 *d = b;
266 if (b < 0xFFU)
267 return 1;
268 b = ReadBlobByte(image);
269 *d = (unsigned long) b;
270 b = ReadBlobByte(image);
271 *d+=(unsigned long) b*256l;
272 if (*d < 0x8000)
273 return 3;
274 *d=(*d & 0x7FFF) << 16;
275 b = ReadBlobByte(image);
276 *d += (unsigned long) b;
277 b=ReadBlobByte(image);
278 *d += (unsigned long) b*256l;
279 return 5;
280 }
281
282
InsertRow(unsigned char * p,unsigned long y,Image * image,int bpp)283 static MagickPassFail InsertRow(unsigned char *p,unsigned long y, Image *image, int bpp)
284 {
285 unsigned long
286 x;
287 register PixelPacket
288 *q;
289 MagickPassFail RetVal = MagickFail;
290 IndexPacket index;
291 IndexPacket *indexes;
292
293 if (image->logging)
294 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
295 "Insert row %ld of %lu...", y, image->rows);
296
297 q = SetImagePixels(image,0,y,image->columns,1);
298 if(q == (PixelPacket *) NULL)
299 return MagickFail;
300
301 switch (bpp)
302 {
303 case 1: /* Convert bitmap scanline. WP seems to ignore palette even if it is present. */
304 RetVal = ImportImagePixelArea(image,GrayQuantum,bpp,p,NULL,0);
305 break;
306
307 case 4: /* Convert PseudoColor scanline. */
308 case 8: /* Convert PseudoColor scanline. */
309 RetVal = ImportImagePixelArea(image,IndexQuantum,bpp,p,NULL,0);
310 break;
311
312 case 2: /* Convert PseudoColor scanline. */
313 {
314 indexes=AccessMutableIndexes(image);
315 if ((image->storage_class != PseudoClass) ||
316 (indexes == (IndexPacket *) NULL))
317 {
318 if (image->logging)
319 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
320 "Image has no colormap, skipping...");
321 return MagickFail;
322 }
323 x = 0;
324 while(x+3 < image->columns)
325 {
326 index = (IndexPacket)((*p >> 6) & 0x3);
327 VerifyColormapIndex(image,index);
328 indexes[x++]=index;
329 *q++=image->colormap[index];
330 index = (IndexPacket)((*p >> 4) & 0x3);
331 VerifyColormapIndex(image,index);
332 indexes[x++]=index;
333 *q++=image->colormap[index];
334 index = (IndexPacket)((*p >> 2) & 0x3);
335 VerifyColormapIndex(image,index);
336 indexes[x++]=index;
337 *q++ = image->colormap[index];
338 index = (IndexPacket)((*p) & 0x3);
339 VerifyColormapIndex(image,index);
340 indexes[x++]=index;
341 *q++ = image->colormap[index];
342 p++;
343 }
344 if(x < image->columns)
345 {
346 index = (IndexPacket) ((*p >> 6) & 0x3);
347 VerifyColormapIndex(image,index);
348 indexes[x++] = index;
349 *q++=image->colormap[index];
350 if(x < image->columns)
351 {
352 index = (IndexPacket) ((*p >> 4) & 0x3);
353 VerifyColormapIndex(image,index);
354 indexes[x++] = index;
355 *q++=image->colormap[index];
356 if(x < image->columns)
357 {
358 index = (IndexPacket)((*p >> 2) & 0x3);
359 VerifyColormapIndex(image,index);
360 indexes[x] = index;
361 *q++=image->colormap[index];
362 }
363 }
364 /* p++; */
365 }
366 RetVal = MagickPass;
367 break;
368 }
369
370 case 24: /* Convert DirectColor scanline. */
371 RetVal = ImportImagePixelArea(image,RGBQuantum,8,p,NULL,0);
372 break;
373
374 default:
375 if (image->logging)
376 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
377 "Unsupported bits per pixel %u",bpp);
378
379 return MagickFail; /* emit some error here */
380 }
381
382
383 if(RetVal==MagickFail)
384 {
385 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"ImportImagePixelArea failed for row: %lu, bpp: %d", y, bpp);
386 return MagickFail;
387 }
388
389 if(!SyncImagePixels(image))
390 {
391 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"SyncImagePixels failed for row: %ld, bpp: %d", y, bpp);
392 return MagickFail;
393 }
394
395 return RetVal;
396 }
397
398
399 /* Helper for WPG1 raster reader. */
400 #define InsertByte(b) \
401 { \
402 BImgBuff[x]=b; \
403 x++; \
404 if((long) x>=ldblk) \
405 { \
406 if(InsertRow(BImgBuff,y,image,bpp)==MagickFail) { RetVal=-6; goto unpack_wpg_raser_error; } \
407 x=0; \
408 y++; \
409 if(y>=image->rows) break; \
410 } \
411 }
412
413
414 /** Call this function to ensure that all data matrix is filled with something. This function
415 * is used only to error recovery. */
ZeroFillMissingData(unsigned char * BImgBuff,unsigned long x,unsigned long y,Image * image,int bpp,long ldblk)416 static MagickPassFail ZeroFillMissingData(unsigned char *BImgBuff,unsigned long x, unsigned long y, Image *image,
417 int bpp, long ldblk)
418 {
419 MagickPassFail
420 status = MagickPass;
421
422 while(y<image->rows && image->exception.severity!=UndefinedException)
423 {
424 if((long) x<ldblk)
425 {
426 memset(BImgBuff+x, 0, (size_t)ldblk-(size_t)x);
427 if(x == 0)
428 x = ldblk; /* Do not memset any more */
429 else
430 x = 0; /* Next pass will need to clear whole row */
431 }
432 if(InsertRow(BImgBuff,y,image,bpp) == MagickFail)
433 {
434 status = MagickFail;
435 break;
436 }
437 y++;
438 }
439 return status;
440 }
441
442
443 /* WPG1 raster reader.
444 * @return 0 - OK; -2 - alocation failure; -3 unaligned column; -4 - image row overflowl
445 -5 - blob read error; -6 - row insert problem */
UnpackWPGRaster(Image * image,int bpp)446 static int UnpackWPGRaster(Image *image,int bpp)
447 {
448 unsigned long
449 x,
450 y;
451
452 int
453 i;
454 int RetVal = 0;
455
456 unsigned char
457 bbuf,
458 *BImgBuff,
459 RunCount;
460
461 long
462 ldblk;
463
464 x=0;
465 y=0;
466
467 ldblk = (long)((bpp*image->columns+7)/8);
468 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
469 "Raster allocation size: %ld byte%s",
470 ldblk, (ldblk > 1 ? "s" : ""));
471 BImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk);
472 if(BImgBuff==NULL) return(-2);
473 (void) memset(BImgBuff,0,(size_t) ldblk);
474
475 while(y<image->rows)
476 {
477 i = ReadBlobByte(image);
478 if(i==EOF)
479 {
480 ZeroFillMissingData(BImgBuff,x,y,image,bpp,ldblk);
481 MagickFreeResourceLimitedMemory(BImgBuff);
482 return(-5);
483 }
484 bbuf = i;
485
486 RunCount=bbuf & 0x7F;
487 if(bbuf & 0x80)
488 {
489 if(RunCount) /* repeat next byte runcount * */
490 {
491 bbuf=ReadBlobByte(image);
492 for(i=0;i<(int) RunCount;i++) InsertByte(bbuf);
493 }
494 else { /* read next byte as RunCount; repeat 0xFF runcount* */
495 RunCount=ReadBlobByte(image);
496 for(i=0;i<(int) RunCount;i++) InsertByte(0xFF);
497 }
498 }
499 else {
500 if(RunCount) /* next runcount byte are readed directly */
501 {
502 for(i=0;i < (int) RunCount;i++)
503 {
504 bbuf=ReadBlobByte(image);
505 InsertByte(bbuf);
506 }
507 }
508 else { /* repeat previous line runcount* */
509 i = ReadBlobByte(image);
510 if(i==EOF)
511 {
512 ZeroFillMissingData(BImgBuff,x,y,image,bpp,ldblk);
513 MagickFreeResourceLimitedMemory(BImgBuff);
514 return -7;
515 }
516 RunCount = i;
517 if(x!=0) { /* attempt to duplicate row from x position: */
518 /* I do not know what to do here */
519 if (InsertRow(BImgBuff,y,image,bpp) == MagickPass) /* May be line flush can fix a situation. */
520 {
521 x=0;
522 y++;
523 ZeroFillMissingData(BImgBuff,x,y,image,bpp,ldblk);
524 }
525 MagickFreeResourceLimitedMemory(BImgBuff);
526 return(-3);
527 }
528 for(i=0; i<(int)RunCount; i++)
529 { /* Here I need to duplicate previous row RUNCOUNT* */
530 /* when x=0; y points to a new empty line. For y=0 zero line will be populated. */
531 if(y>=image->rows)
532 {
533 MagickFreeResourceLimitedMemory(BImgBuff);
534 return(-4);
535 }
536 if(InsertRow(BImgBuff,y,image,bpp)==MagickFail)
537 {
538 MagickFreeResourceLimitedMemory(BImgBuff);
539 return(-6);
540 }
541 y++;
542 }
543 }
544 }
545 }
546 unpack_wpg_raser_error:;
547 MagickFreeResourceLimitedMemory(BImgBuff);
548 return(RetVal);
549 }
550
551
552 /* Helper for WPG2 reader. */
553 #define InsertByte6(b) \
554 { \
555 if(XorMe)\
556 BImgBuff[x] = b ^ UpImgBuff[x];\
557 else\
558 BImgBuff[x] = b;\
559 x++; \
560 if((long) x >= ldblk) \
561 { \
562 if(InsertRow(BImgBuff,(long) y,image,bpp)==MagickFail) { RetVal=-6; goto unpack_wpg2_error; } \
563 x=0; \
564 y++; \
565 XorMe = 0; \
566 tmpImgBuff = BImgBuff; \
567 BImgBuff = UpImgBuff; \
568 UpImgBuff = tmpImgBuff; \
569 } \
570 }
571
572 #define FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff) \
573 do \
574 { \
575 MagickFreeResourceLimitedMemory(BImgBuff); \
576 MagickFreeResourceLimitedMemory(UpImgBuff); \
577 } while(0);
578
579 /* WPG2 raster reader. */
UnpackWPG2Raster(Image * image,int bpp)580 static int UnpackWPG2Raster(Image *image, int bpp)
581 {
582 unsigned int
583 SampleSize=1;
584
585 unsigned char
586 bbuf,
587 *BImgBuff = (unsigned char *) NULL, /* Buffer for a current line. */
588 *UpImgBuff = (unsigned char *) NULL, /* Buffer for previous line. */
589 *tmpImgBuff = (unsigned char *) NULL,
590 RunCount,
591 SampleBuffer[8];
592
593 unsigned long
594 x,
595 y;
596
597 unsigned int
598 i;
599
600 long
601 ldblk;
602
603 int XorMe = 0;
604 int c;
605 int RetVal = 0;
606
607 x=0;
608 y=0;
609 ldblk=(long) ((bpp*image->columns+7)/8);
610 BImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk);
611 if(BImgBuff==NULL)
612 return(-2);
613 UpImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk);
614 if(UpImgBuff==NULL)
615 {
616 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
617 return(-2);
618 }
619 (void) memset(UpImgBuff,0,ldblk);
620 (void) memset(SampleBuffer,0,sizeof(SampleBuffer));
621
622 while( y< image->rows)
623 {
624 bbuf=ReadBlobByte(image);
625
626 switch(bbuf)
627 {
628 case 0x7D:
629 if ((c = ReadBlobByte(image)) == EOF) /* DSZ */
630 {
631 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
632 return(-4);
633 }
634 SampleSize=c;
635 if(SampleSize>8)
636 {
637 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
638 return(-2);
639 }
640 if(SampleSize<1)
641 {
642 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
643 return(-2);
644 }
645 break;
646 case 0x7E:
647 if(y==0) /* XOR */
648 (void)fprintf(stderr,"\nWPG token XOR on the first line is not supported, please report!");
649 XorMe=!XorMe; /* or XorMe=1 ?? */
650 break;
651 case 0x7F:
652 if ((c = ReadBlobByte(image)) == EOF) /* BLK */
653 {
654 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
655 return(-4);
656 }
657 RunCount=c;
658 for(i=0; i < SampleSize*(RunCount+1); i++)
659 {
660 InsertByte6(0);
661 }
662 break;
663 case 0xFD:
664 if ((c = ReadBlobByte(image)) == EOF) /* EXT */
665 {
666 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
667 return(-4);
668 }
669 RunCount=c;
670 for(i=0; i<= RunCount;i++)
671 for(bbuf=0; bbuf < SampleSize; bbuf++)
672 InsertByte6(SampleBuffer[bbuf]);
673 break;
674 case 0xFE:
675 if ((c = ReadBlobByte(image)) == EOF) /* RST */
676 {
677 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
678 return(-4);
679 }
680 RunCount = c;
681 if(x!=0)
682 {
683 (void) fprintf(stderr,
684 "\nUnsupported WPG2 unaligned token RST x=%lu, please report!\n"
685 ,x);
686 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
687 return(-3);
688 }
689 {
690 /* duplicate the previous row RunCount x */
691 for(i=0;i<=RunCount;i++)
692 {
693 if(InsertRow(UpImgBuff,(long)((image->rows>y) ? y : image->rows-1),image,bpp) == MagickFail)
694 {
695 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
696 return(-4);
697 }
698 y++;
699 }
700 }
701 break;
702 case 0xFF:
703 if ((c = ReadBlobByte(image)) == EOF) /* WHT */
704 {
705 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
706 return(-4);
707 }
708 RunCount=c;
709 for(i=0; i < SampleSize*(RunCount+1); i++)
710 {
711 InsertByte6(0xFF);
712 }
713 break;
714 default:
715 RunCount=bbuf & 0x7F;
716
717 if(bbuf & 0x80) /* REP */
718 {
719 for(i=0; i < SampleSize; i++)
720 SampleBuffer[i]=ReadBlobByte(image);
721 for(i=0;i<=RunCount;i++)
722 for(bbuf=0;bbuf<SampleSize;bbuf++)
723 InsertByte6(SampleBuffer[bbuf]);
724 }
725 else { /* NRP */
726 for(i=0; i< SampleSize*(RunCount+1);i++)
727 {
728 bbuf=ReadBlobByte(image);
729 InsertByte6(bbuf);
730 }
731 }
732 if (EOFBlob(image))
733 {
734 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
735 return(-4);
736 }
737 }
738 }
739 unpack_wpg2_error:;
740 FreeUnpackWPG2RasterAllocs(BImgBuff,UpImgBuff);
741 return(RetVal);
742 }
743
744
745 typedef float tCTM[3][3];
746
LoadWPG2Flags(Image * image,char Precision,float * Angle,tCTM * CTM)747 static unsigned LoadWPG2Flags(Image *image,char Precision,float *Angle,tCTM *CTM)
748 {
749 const unsigned char TPR=1,TRN=2,SKW=4,SCL=8,ROT=0x10,OID=0x20,LCK=0x80;
750 long x;
751 unsigned DenX;
752 unsigned Flags;
753
754 (void) memset(*CTM,0,sizeof(*CTM)); /*CTM.erase();CTM.resize(3,3);*/
755 (*CTM)[0][0]=1;
756 (*CTM)[1][1]=1;
757 (*CTM)[2][2]=1;
758
759 Flags=ReadBlobLSBShort(image);
760 if(Flags & LCK) /*x=*/ (void) ReadBlobLSBLong(image); /*Edit lock*/
761 if(Flags & OID)
762 {
763 if(Precision==0)
764 {/*x=*/ (void) ReadBlobLSBShort(image);} /*ObjectID*/
765 else
766 {/*x=*/ (void) ReadBlobLSBLong(image);} /*ObjectID (Double precision)*/
767 }
768 if(Flags & ROT)
769 {
770 x=ReadBlobLSBLong(image); /*Rot Angle*/
771 if(Angle) *Angle=x/65536.0;
772 }
773 if(Flags & (ROT|SCL))
774 {
775 x=ReadBlobLSBLong(image); /*Sx*cos()*/
776 (*CTM)[0][0] = (float)x/0x10000;
777 x=ReadBlobLSBLong(image); /*Sy*cos()*/
778 (*CTM)[1][1] = (float)x/0x10000;
779 }
780 if(Flags & (ROT|SKW))
781 {
782 x=ReadBlobLSBLong(image); /*Kx*sin()*/
783 (*CTM)[1][0] = (float)x/0x10000;
784 x=ReadBlobLSBLong(image); /*Ky*sin()*/
785 (*CTM)[0][1] = (float)x/0x10000;
786 }
787 if(Flags & TRN)
788 {
789 x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Tx*/
790 if(x>=0) (*CTM)[0][2] = (float)x+(float)DenX/0x10000;
791 else (*CTM)[0][2] = (float)x-(float)DenX/0x10000;
792 x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Ty*/
793 (*CTM)[1][2]=(float)x + ((x>=0)?1:-1)*(float)DenX/0x10000;
794 if(x>=0) (*CTM)[1][2] = (float)x+(float)DenX/0x10000;
795 else (*CTM)[1][2] = (float)x-(float)DenX/0x10000;
796 }
797 if(Flags & TPR)
798 {
799 x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Px*/
800 (*CTM)[2][0] = x + (float)DenX/0x10000;;
801 x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Py*/
802 (*CTM)[2][1] = x + (float)DenX/0x10000;
803 }
804 return(Flags);
805 }
806
807
ExtractPostscript(Image * image,const ImageInfo * image_info,ExtendedSignedIntegralType PS_Offset,size_t PS_Size,ExceptionInfo * exception)808 static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
809 ExtendedSignedIntegralType PS_Offset,
810 size_t PS_Size,ExceptionInfo *exception)
811 {
812 ImageInfo
813 *clone_info;
814
815 Image
816 *image2;
817
818 unsigned char
819 header_magick[2*MaxTextExtent];
820
821 void
822 *ps_data,
823 *ps_data_alloc = (unsigned char *) NULL;
824
825 char
826 format[MaxTextExtent];
827
828 size_t
829 header_magick_size;
830
831 magick_off_t
832 filesize;
833
834 if (image->logging)
835 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
836 "ExtractPostscript(): PS_Offset=%"MAGICK_OFF_F"d, PS_Size=%"MAGICK_SIZE_T_F"u",
837 (magick_off_t) PS_Offset, (MAGICK_SIZE_T) PS_Size);
838
839 /*
840 Validate that claimed subordinate image data is contained in file size
841 */
842 filesize = GetBlobSize(image);
843 if ((PS_Offset > filesize) || ((size_t) (filesize - PS_Offset) < PS_Size))
844 {
845 if (image->logging)
846 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
847 "ExtractPostscript(): Failed to seek to PS_Offset=%"MAGICK_OFF_F"d",
848 (magick_off_t) PS_Offset);
849 ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename);
850 return image;
851 }
852
853 /*
854 Get subordinate file header magick and use it to identify file format
855 */
856 if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
857 {
858 if (image->logging)
859 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
860 "ExtractPostscript(): Failed to seek to PS_Offset=%"MAGICK_OFF_F"d",
861 (magick_off_t) PS_Offset);
862 ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename);
863 return image;
864 }
865 header_magick_size = ReadBlob(image, Min(sizeof(header_magick),PS_Size), header_magick);
866 format[0]='\0';
867 /*
868 MagickExport MagickPassFail
869 GetMagickFileFormat(const unsigned char *header, const size_t header_length,
870 char *format, const size_t format_length,
871 ExceptionInfo *exception)
872 */
873 if (GetMagickFileFormat(header_magick,header_magick_size,format,
874 sizeof(format),exception) == MagickFail)
875 {
876 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
877 "Failed to identify embedded file type!");
878 ThrowException(exception,CorruptImageError,UnableToReadImageHeader,image->filename);
879 return image;
880 }
881
882 /*
883 Verify if this is an allowed subordinate image format
884 */
885 if(!ApproveFormatForWPG(format))
886 {
887 (void) LogMagickEvent(CoderEvent, GetMagickModule(),
888 "Format \"%s\" cannot be embedded inside WPG.", format);
889 ThrowException(exception,CorruptImageError,UnableToReadImageHeader,image->filename);
890 return image;
891 }
892
893 /*
894 Restore seek offset after reading header
895 */
896 if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
897 {
898 if (image->logging)
899 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
900 "ExtractPostscript(): Failed to seek to PS_Offset=%"MAGICK_OFF_F"d",
901 (magick_off_t) PS_Offset);
902 ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename);
903 return image;
904 }
905 /*
906 Allocate buffer if zero-copy read is not possible.
907 */
908 if (GetBlobStreamData(image) == (unsigned char *) NULL)
909 {
910 ps_data_alloc=MagickAllocateResourceLimitedMemory(unsigned char *, PS_Size);
911 if (ps_data_alloc == (unsigned char *) NULL)
912 {
913 if (image->logging)
914 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
915 "ExtractPostscript(): Failed to allocate "
916 "%"MAGICK_SIZE_T_F"u bytes of memory",
917 (MAGICK_SIZE_T) PS_Size);
918 ThrowException(exception,ResourceLimitError,MemoryAllocationFailed,image->filename);
919 return image;
920 }
921 }
922 /*
923 Use a zero-copy read when possible to access data
924 */
925 ps_data=ps_data_alloc;
926 if (ReadBlobZC(image,PS_Size,&ps_data) != PS_Size)
927 {
928 MagickFreeResourceLimitedMemory(ps_data_alloc);
929 if (image->logging)
930 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
931 "ExtractPostscript(): Failed to read %"MAGICK_SIZE_T_F"u bytes of data at"
932 " offset=%"MAGICK_OFF_F"d",
933 (MAGICK_SIZE_T) PS_Size, (magick_off_t) PS_Offset);
934 ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename);
935 return image; /* return (Image *) NULL; */
936 }
937 if (ps_data_alloc != ps_data)
938 {
939 if (image->logging)
940 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
941 "ExtractPostscript(): Zero copy read.");
942 }
943
944 /*
945 Read nested image from blob, forcing read as Postscript format
946 */
947 if ((clone_info=CloneImageInfo(image_info)) == NULL)
948 {
949 MagickFreeResourceLimitedMemory(ps_data_alloc);
950 return(image);
951 }
952 clone_info->blob=(void *) NULL;
953 /* clone_info->length=0; */
954 (void) strlcpy(clone_info->magick, format, sizeof(clone_info->magick));
955 (void) strcpy(clone_info->filename, "");
956 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
957 "Reading embedded \"%s\" content from blob...", clone_info->magick);
958 image2 = BlobToImage(clone_info, ps_data, PS_Size, &image->exception );
959 MagickFreeResourceLimitedMemory(ps_data_alloc);
960 if (!image2)
961 {
962 goto FINISH_UNL;
963 }
964 if(exception->severity>=ErrorException) /* When exception is raised, destroy image2 read. */
965 {
966 CloseBlob(image2);
967 DestroyImageList(image2);
968 goto FINISH_UNL;
969 }
970
971 /*
972 Replace current image with new image while copying base image
973 attributes.
974 */
975 {
976 Image *p;
977 p = image2;
978 do
979 {
980 (void) strlcpy(p->filename,image->filename,MaxTextExtent);
981 (void) strlcpy(p->magick_filename,image->magick_filename,MaxTextExtent);
982 (void) strlcpy(p->magick,image->magick,MaxTextExtent);
983 /*image2->depth=image->depth;*/ /* !!!! The image2 depth should not be modified here. Image2 is completely different. */
984 DestroyBlob(p);
985
986 if(p->rows==0 || p->columns==0)
987 {
988 DeleteImageFromList(&p);
989 if(p==NULL)
990 {
991 image2 = NULL;
992 goto FINISH_UNL; /* Nothing to add, skip. */
993 }
994 }
995 else
996 {
997 p->blob = ReferenceBlob(image->blob);
998 p = p->next;
999 }
1000 } while(p!=NULL);
1001 }
1002
1003 if((image->rows==0 || image->columns==0) && (image->previous!=NULL || image->next!=NULL))
1004 {
1005 DeleteImageFromList(&image);
1006 }
1007
1008 AppendImageToList(&image,image2); /* This should append list 'image2' to the list 'image', image2 accepts NULL. */
1009 while(image->next != NULL)
1010 image = image->next; /* Rewind the cursor to the end. */
1011
1012 FINISH_UNL:
1013 DestroyImageInfo(clone_info);
1014 return(image);
1015 }
1016
1017
1018 /*
1019 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1020 % %
1021 % %
1022 % %
1023 % R e a d W P G I m a g e %
1024 % %
1025 % %
1026 % %
1027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1028 %
1029 % Method ReadWPGImage reads an WPG X image file and returns it. It
1030 % allocates the memory necessary for the new Image structure and returns a
1031 % pointer to the new image.
1032 %
1033 % The format of the ReadWPGImage method is:
1034 %
1035 % Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
1036 %
1037 % A description of each parameter follows:
1038 %
1039 % o image: Method ReadWPGImage returns a pointer to the image after
1040 % reading. A null image is returned if there is a memory shortage or if
1041 % the image cannot be read.
1042 %
1043 % o image_info: Specifies a pointer to a ImageInfo structure.
1044 %
1045 % o exception: return any errors or warnings in this structure.
1046 %
1047 %
1048 */
ReadWPGImage(const ImageInfo * image_info,ExceptionInfo * exception)1049 static Image *ReadWPGImage(const ImageInfo *image_info,
1050 ExceptionInfo *exception)
1051 {
1052 typedef struct
1053 {
1054 unsigned long FileId;
1055 ExtendedSignedIntegralType DataOffset; /* magick_uint32_t */
1056 unsigned int ProductType;
1057 unsigned int FileType;
1058 unsigned char MajorVersion;
1059 unsigned char MinorVersion;
1060 unsigned int EncryptKey;
1061 unsigned int Reserved;
1062 } WPGHeader;
1063
1064 typedef struct
1065 {
1066 unsigned char RecType;
1067 unsigned long RecordLength;
1068 } WPGRecord;
1069
1070 typedef struct
1071 {
1072 unsigned char Class;
1073 unsigned char RecType;
1074 unsigned long Extension;
1075 unsigned long RecordLength;
1076 } WPG2Record;
1077
1078 typedef struct
1079 {
1080 unsigned HorizontalUnits;
1081 unsigned VerticalUnits;
1082 unsigned char PosSizePrecision;
1083 } WPG2Start;
1084
1085 typedef struct
1086 {
1087 unsigned int Width;
1088 unsigned int Heigth;
1089 unsigned int Depth;
1090 unsigned int HorzRes;
1091 unsigned int VertRes;
1092 } WPGBitmapType1;
1093
1094 typedef struct
1095 {
1096 unsigned int Width;
1097 unsigned int Heigth;
1098 unsigned char Depth;
1099 unsigned char Compression;
1100 } WPG2BitmapType1;
1101
1102 typedef struct
1103 {
1104 unsigned int RotAngle;
1105 unsigned int LowLeftX;
1106 unsigned int LowLeftY;
1107 unsigned int UpRightX;
1108 unsigned int UpRightY;
1109 unsigned int Width;
1110 unsigned int Heigth;
1111 unsigned int Depth;
1112 unsigned int HorzRes;
1113 unsigned int VertRes;
1114 } WPGBitmapType2;
1115
1116 typedef struct
1117 {
1118 unsigned int StartIndex;
1119 unsigned int NumOfEntries;
1120 } WPGColorMapRec;
1121
1122 /*
1123 typedef struct {
1124 unsigned long PS_unknown1;
1125 unsigned int PS_unknown2;
1126 unsigned int PS_unknown3;
1127 } WPGPSl1Record;
1128 */
1129
1130 Image
1131 *image,
1132 *rotated_image;
1133
1134 unsigned int
1135 status;
1136
1137 WPGHeader
1138 Header;
1139
1140 WPGRecord
1141 Rec;
1142
1143 WPG2Record
1144 Rec2;
1145
1146 WPG2Start StartWPG;
1147
1148 WPGBitmapType1
1149 BitmapHeader1;
1150
1151 WPG2BitmapType1
1152 Bitmap2Header1;
1153
1154 WPGBitmapType2
1155 BitmapHeader2;
1156
1157 WPGColorMapRec
1158 WPG_Palette;
1159
1160 int
1161 i,
1162 bpp;
1163
1164 int logging;
1165
1166 long
1167 ldblk;
1168
1169 unsigned char
1170 *BImgBuff;
1171 BlobInfo *TmpBlob;
1172 magick_off_t FilePos, filesize;
1173
1174 tCTM CTM; /*current transform matrix*/
1175
1176 /*
1177 Open image file.
1178 */
1179 assert(image_info != (const ImageInfo *) NULL);
1180 assert(image_info->signature == MagickSignature);
1181 assert(exception != (ExceptionInfo *) NULL);
1182 assert(exception->signature == MagickSignature);
1183
1184 logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter");
1185
1186 image=AllocateImage(image_info);
1187 image->depth=8;
1188 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1189 if (status == False)
1190 ThrowReaderException(FileOpenError,UnableToOpenFile,image);
1191
1192 /*
1193 Read WPG image.
1194 */
1195 Header.FileId=ReadBlobLSBLong(image);
1196 Header.DataOffset=(ExtendedSignedIntegralType) ReadBlobLSBLong(image);
1197 Header.ProductType=ReadBlobLSBShort(image);
1198 Header.FileType=ReadBlobLSBShort(image);
1199 Header.MajorVersion=ReadBlobByte(image);
1200 Header.MinorVersion=ReadBlobByte(image);
1201 Header.EncryptKey=ReadBlobLSBShort(image);
1202 Header.Reserved=ReadBlobLSBShort(image);
1203
1204 if (Header.FileId!=0x435057FF || (Header.ProductType>>8)!=0x16)
1205 ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1206 if (Header.EncryptKey!=0)
1207 ThrowReaderException(CoderError,EncryptedWPGImageFileNotSupported,image);
1208
1209 image->colors = 0;
1210 image->storage_class = DirectClass;
1211 bpp=0;
1212
1213 if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1214 "File type: %d", Header.FileType);
1215
1216 /* Determine file size. */
1217 filesize = GetBlobSize(image); /* zero is returned if the size cannot be determined. */
1218 if(filesize>0 && BlobIsSeekable(image))
1219 {
1220 if(filesize > (magick_off_t)0xFFFFFFFF)
1221 filesize = (magick_off_t)0xFFFFFFFF; /* More than 4GiB are not supported in WPG! */
1222 }
1223 else
1224 {
1225 filesize = (magick_off_t)0xFFFFFFFF;
1226 if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1227 "Blob is not seekable, WPG reader could fail.");
1228 ThrowReaderException(CorruptImageError,AnErrorHasOccurredReadingFromFile,image);
1229 }
1230
1231 switch(Header.FileType)
1232 {
1233 case 1: /* WPG level 1 */
1234 BitmapHeader2.RotAngle = 0;
1235 FilePos = Header.DataOffset;
1236 while(!EOFBlob(image)) /* object parser loop */
1237 {
1238 if(SeekBlob(image,FilePos,SEEK_SET) != FilePos)
1239 break;
1240
1241 Rec.RecType = (i=ReadBlobByte(image));
1242 if(i==EOF) break;
1243 FilePos += 1;
1244
1245 FilePos += Rd_WP_DWORD(image,&Rec.RecordLength);
1246 if((magick_off_t)Rec.RecordLength > filesize)
1247 ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1248 if(EOFBlob(image)) break;
1249
1250 FilePos += (magick_off_t)Rec.RecordLength;
1251 if(FilePos>filesize || FilePos<Header.DataOffset)
1252 {
1253 if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1254 "Invalid record length: %X", (unsigned)Rec.RecType);
1255 break;
1256 }
1257 Header.DataOffset = FilePos;
1258
1259 if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1260 "Parsing object: %X", Rec.RecType);
1261 /* printf("\nParsing object: %u:%X", (unsigned)FilePos, Rec.RecType); */
1262
1263 switch(Rec.RecType)
1264 {
1265 case 0x0B: /* bitmap type 1 */
1266 BitmapHeader1.Width=ReadBlobLSBShort(image);
1267 BitmapHeader1.Heigth=ReadBlobLSBShort(image);
1268 if ((BitmapHeader1.Width == 0) || (BitmapHeader1.Heigth == 0))
1269 ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1270 BitmapHeader1.Depth=ReadBlobLSBShort(image);
1271 BitmapHeader1.HorzRes=ReadBlobLSBShort(image);
1272 BitmapHeader1.VertRes=ReadBlobLSBShort(image);
1273
1274 if(BitmapHeader1.HorzRes && BitmapHeader1.VertRes)
1275 {
1276 image->units=PixelsPerCentimeterResolution;
1277 image->x_resolution=BitmapHeader1.HorzRes/470.0;
1278 image->y_resolution=BitmapHeader1.VertRes/470.0;
1279 }
1280 image->columns=BitmapHeader1.Width;
1281 image->rows=BitmapHeader1.Heigth;
1282 bpp=BitmapHeader1.Depth;
1283
1284 goto UnpackRaster;
1285
1286 case 0x0E: /*Color palette */
1287 WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1288 WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1289
1290 image->colors=WPG_Palette.NumOfEntries;
1291 if (!AllocateImageColormap(image,image->colors))
1292 goto NoMemory;
1293 image->storage_class = PseudoClass;
1294 for (i=WPG_Palette.StartIndex;
1295 i < (int)WPG_Palette.NumOfEntries; i++)
1296 {
1297 image->colormap[i].red=ScaleCharToQuantum(ReadBlobByte(image));
1298 image->colormap[i].green=ScaleCharToQuantum(ReadBlobByte(image));
1299 image->colormap[i].blue=ScaleCharToQuantum(ReadBlobByte(image));
1300 image->colormap[i].opacity = OpaqueOpacity;
1301 }
1302 break;
1303
1304 case 0x11: /* Start PS l1 */
1305 if(Rec.RecordLength > 8)
1306 image=ExtractPostscript(image,image_info,
1307 TellBlob(image)+8, /* skip PS header in the wpg */
1308 (size_t) (Rec.RecordLength-8),exception);
1309 break;
1310
1311 case 0x14: /* bitmap type 2 */
1312 BitmapHeader2.RotAngle=ReadBlobLSBShort(image);
1313 BitmapHeader2.LowLeftX=ReadBlobLSBShort(image);
1314 BitmapHeader2.LowLeftY=ReadBlobLSBShort(image);
1315 BitmapHeader2.UpRightX=ReadBlobLSBShort(image);
1316 BitmapHeader2.UpRightY=ReadBlobLSBShort(image);
1317 BitmapHeader2.Width=ReadBlobLSBShort(image);
1318 BitmapHeader2.Heigth=ReadBlobLSBShort(image);
1319 if ((BitmapHeader2.Width == 0) || (BitmapHeader2.Heigth == 0))
1320 ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1321 BitmapHeader2.Depth=ReadBlobLSBShort(image);
1322 BitmapHeader2.HorzRes=ReadBlobLSBShort(image);
1323 BitmapHeader2.VertRes=ReadBlobLSBShort(image);
1324
1325 image->units=PixelsPerCentimeterResolution;
1326 image->page.width=(unsigned int)
1327 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0);
1328 image->page.height=(unsigned int)
1329 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0);
1330 image->page.x=(int) (BitmapHeader2.LowLeftX/470.0);
1331 image->page.y=(int) (BitmapHeader2.LowLeftX/470.0);
1332 if(BitmapHeader2.HorzRes && BitmapHeader2.VertRes)
1333 {
1334 image->x_resolution=BitmapHeader2.HorzRes/470.0;
1335 image->y_resolution=BitmapHeader2.VertRes/470.0;
1336 }
1337 image->columns=BitmapHeader2.Width;
1338 image->rows=BitmapHeader2.Heigth;
1339 bpp=BitmapHeader2.Depth;
1340
1341 UnpackRaster:
1342 if(bpp>24)
1343 {ThrowReaderException(CoderError,ColorTypeNotSupported,image)}
1344
1345 if ((image->storage_class != PseudoClass) && (bpp != 24))
1346 {
1347 image->colors=1 << bpp;
1348 if (!AllocateImageColormap(image,image->colors))
1349 {
1350 NoMemory:
1351 ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,
1352 image)
1353 }
1354 image->storage_class = PseudoClass;
1355 /* printf("Load default colormap \n"); */
1356 for (i=0; (i < (int) image->colors) && (i < 256); i++)
1357 {
1358 image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red);
1359 image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green);
1360 image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue);
1361 image->colormap[i].opacity = OpaqueOpacity;
1362 }
1363 }
1364 else
1365 {
1366 if (bpp < 24)
1367 if ( (image->colors < (1UL<<bpp)) && (bpp != 24) )
1368 if (!ReallocColormap(image,1U<<bpp))
1369 goto NoMemory;
1370 }
1371
1372 if(bpp == 1)
1373 {
1374 if(image->colors<=0)
1375 {
1376 image->colormap[0].red =
1377 image->colormap[0].green =
1378 image->colormap[0].blue = 0;
1379 image->colormap[0].opacity = OpaqueOpacity;
1380 }
1381 if(image->colors<=1 || /* Realloc has been enforced and value [1] remains uninitialised, or .. */
1382 (image->colormap[0].red==0 && image->colormap[0].green==0 && image->colormap[0].blue==0 &&
1383 image->colormap[1].red==0 && image->colormap[1].green==0 && image->colormap[1].blue==0))
1384 { /* fix crippled monochrome palette */
1385 image->colormap[1].red =
1386 image->colormap[1].green =
1387 image->colormap[1].blue = MaxRGB;
1388 image->colormap[1].opacity = OpaqueOpacity;
1389 }
1390 }
1391
1392 if(!image_info->ping)
1393 if(UnpackWPGRaster(image,bpp) < 0)
1394 { /* The raster cannot be unpacked */
1395 DecompressionFailed:
1396 ThrowReaderException(CoderError,UnableToDecompressImage,image)
1397 }
1398
1399 if(Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
1400 {
1401 /* flop command */
1402 if(BitmapHeader2.RotAngle & 0x8000)
1403 {
1404 rotated_image = FlopImage(image, exception);
1405 if (rotated_image != (Image *)NULL)
1406 {
1407 TmpBlob = rotated_image->blob;
1408 rotated_image->blob = image->blob;
1409 image->blob = TmpBlob;
1410 ReplaceImageInList(&image,rotated_image);
1411 }
1412 }
1413 /* flip command */
1414 if(BitmapHeader2.RotAngle & 0x2000)
1415 {
1416 rotated_image = FlipImage(image, exception);
1417 if (rotated_image != (Image *) NULL)
1418 {
1419 TmpBlob = rotated_image->blob;
1420 rotated_image->blob = image->blob;
1421 image->blob = TmpBlob;
1422 ReplaceImageInList(&image,rotated_image);
1423 }
1424 }
1425
1426 /* rotate command */
1427 if(BitmapHeader2.RotAngle & 0x0FFF)
1428 {
1429 rotated_image = RotateImage(image,
1430 (BitmapHeader2.RotAngle & 0x0FFF),
1431 exception);
1432 if (rotated_image != (Image *) NULL)
1433 {
1434 TmpBlob = rotated_image->blob;
1435 rotated_image->blob = image->blob;
1436 image->blob = TmpBlob;
1437 ReplaceImageInList(&image,rotated_image);
1438 }
1439 }
1440 }
1441
1442 StopTimer(&image->timer);
1443
1444 if (image_info->subrange != 0)
1445 if (image->scene >= (image_info->subimage+image_info->subrange-1))
1446 goto Finish;
1447
1448 /* Allocate next image structure. */
1449 AllocateNextImage(image_info,image);
1450 image->depth=8;
1451 if (image->next == (Image *) NULL)
1452 goto Finish;
1453 image=SyncNextImageInList(image);
1454 image->columns=image->rows=0;
1455 image->colors=0;
1456 break;
1457
1458 case 0x1B: /* Postscript l2 */
1459 if(Rec.RecordLength>0x3C)
1460 image=ExtractPostscript(image,image_info,
1461 TellBlob(image)+0x3C, /* skip PS l2 header in the wpg */
1462 (size_t) (Rec.RecordLength-0x3C),exception);
1463 break;
1464 }
1465 }
1466 break;
1467
1468 case 2: /* WPG level 2 */
1469 (void) memset(CTM,0,sizeof(CTM));
1470 StartWPG.PosSizePrecision = 0;
1471 while(!EOFBlob(image)) /* object parser loop */
1472 {
1473 if(SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
1474 break;
1475 if(EOFBlob(image))
1476 break;
1477
1478 Rec2.Class=(i=ReadBlobByte(image));
1479 if(i==EOF)
1480 break;
1481 Rec2.RecType=(i=ReadBlobByte(image));
1482 if(i==EOF)
1483 break;
1484 Rd_WP_DWORD(image,&Rec2.Extension);
1485 Rd_WP_DWORD(image,&Rec2.RecordLength);
1486 if(EOFBlob(image))
1487 break;
1488
1489 Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
1490
1491 if(logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),
1492 "Parsing object: %X", Rec2.RecType);
1493
1494 switch(Rec2.RecType)
1495 {
1496 case 1:
1497 StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
1498 StartWPG.VerticalUnits=ReadBlobLSBShort(image);
1499 StartWPG.PosSizePrecision=ReadBlobByte(image);
1500 break;
1501 case 0x0C: /* Color palette */
1502 WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1503 WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1504
1505 /* Sanity check for amount of palette entries. */
1506 if (WPG_Palette.NumOfEntries == 0)
1507 ThrowReaderException(CorruptImageError,UnrecognizedNumberOfColors,image);
1508
1509 if (WPG_Palette.NumOfEntries > MaxMap+1)
1510 ThrowReaderException(CorruptImageError,ColormapExceedsColorsLimit,image);
1511
1512 if ( (WPG_Palette.StartIndex > WPG_Palette.NumOfEntries) ||
1513 (((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
1514 ((Rec2.RecordLength-2-2) / 3))) )
1515 ThrowReaderException(CorruptImageError,InvalidColormapIndex,image);
1516
1517 image->colors=WPG_Palette.NumOfEntries;
1518 if (!AllocateImageColormap(image,image->colors))
1519 ThrowReaderException(ResourceLimitError,MemoryAllocationFailed,image);
1520
1521 for (i=WPG_Palette.StartIndex;
1522 i < (int)WPG_Palette.NumOfEntries; i++)
1523 {
1524 image->colormap[i].red=ScaleCharToQuantum(ReadBlobByte(image));
1525 image->colormap[i].green=ScaleCharToQuantum(ReadBlobByte(image));
1526 image->colormap[i].blue=ScaleCharToQuantum(ReadBlobByte(image));
1527 image->colormap[i].opacity = OpaqueOpacity;
1528 (void) ReadBlobByte(image); /*Opacity??*/
1529 }
1530 break;
1531 case 0x0E:
1532 Bitmap2Header1.Width=ReadBlobLSBShort(image);
1533 Bitmap2Header1.Heigth=ReadBlobLSBShort(image);
1534 if ((Bitmap2Header1.Width == 0) || (Bitmap2Header1.Heigth == 0))
1535 ThrowReaderException(CorruptImageError,ImproperImageHeader,image);
1536 Bitmap2Header1.Depth=ReadBlobByte(image);
1537 Bitmap2Header1.Compression=ReadBlobByte(image);
1538
1539 if(Bitmap2Header1.Compression > 1)
1540 continue; /*Unknown compression method */
1541 switch(Bitmap2Header1.Depth)
1542 {
1543 case 1: bpp=1;
1544 break;
1545 case 2: bpp=2;
1546 break;
1547 case 3: bpp=4;
1548 break;
1549 case 4: bpp=8;
1550 break;
1551 case 8: bpp=24;
1552 break;
1553 default:
1554 continue; /*Ignore raster with unknown depth*/
1555 }
1556 image->columns=Bitmap2Header1.Width;
1557 image->rows=Bitmap2Header1.Heigth;
1558
1559 if ((image->colors == 0) && (bpp != 24))
1560 {
1561 image->colors=1 << bpp;
1562 if (!AllocateImageColormap(image,image->colors))
1563 goto NoMemory;
1564 image->storage_class = PseudoClass;
1565 }
1566 else
1567 {
1568 if(bpp < 24)
1569 if( image->colors<(1UL<<bpp) && bpp!=24 )
1570 if (!ReallocColormap(image,1U<<bpp))
1571 goto NoMemory;
1572 }
1573
1574
1575 switch(Bitmap2Header1.Compression)
1576 {
1577 case 0: /*Uncompressed raster*/
1578 {
1579 ldblk=(long) ((bpp*image->columns+7)/8);
1580 BImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) ldblk);
1581 if(BImgBuff == (unsigned char *) NULL)
1582 goto NoMemory;
1583
1584 for(i=0; i< (long) image->rows; i++)
1585 {
1586 if (ReadBlob(image,ldblk,(char *) BImgBuff) != (size_t) ldblk)
1587 {
1588 MagickFreeResourceLimitedMemory(BImgBuff);
1589 ThrowException(exception,CorruptImageError,UnexpectedEndOfFile,image->filename);
1590 goto DecompressionFailed;
1591 }
1592 if(InsertRow(BImgBuff,i,image,bpp) == MagickFail)
1593 {
1594 if(BImgBuff) MagickFreeResourceLimitedMemory(BImgBuff);
1595 goto DecompressionFailed;
1596 }
1597 }
1598
1599 if(BImgBuff) MagickFreeResourceLimitedMemory(BImgBuff);
1600 break;
1601 }
1602 case 1: /*RLE for WPG2 */
1603 {
1604 if( UnpackWPG2Raster(image,bpp) < 0)
1605 goto DecompressionFailed;
1606 break;
1607 }
1608 }
1609
1610
1611 if(CTM[0][0]<0 && !image_info->ping)
1612 { /*?? RotAngle=360-RotAngle;*/
1613 rotated_image = FlopImage(image, exception);
1614 if (rotated_image != (Image *) NULL)
1615 {
1616 TmpBlob = rotated_image->blob;
1617 rotated_image->blob = image->blob;
1618 image->blob = TmpBlob;
1619 ReplaceImageInList(&image,rotated_image);
1620 }
1621 /* Try to change CTM according to Flip - I am not sure, must be checked.
1622 Tx(0,0)=-1; Tx(1,0)=0; Tx(2,0)=0;
1623 Tx(0,1)= 0; Tx(1,1)=1; Tx(2,1)=0;
1624 Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
1625 Tx(1,2)=0; Tx(2,2)=1; */
1626 }
1627 if(CTM[1][1]<0 && !image_info->ping)
1628 { /*?? RotAngle=360-RotAngle;*/
1629 rotated_image = FlipImage(image, exception);
1630 if (rotated_image != (Image *) NULL)
1631 {
1632 TmpBlob = rotated_image->blob;
1633 rotated_image->blob = image->blob;
1634 image->blob = TmpBlob;
1635 ReplaceImageInList(&image,rotated_image);
1636 }
1637 /* Try to change CTM according to Flip - I am not sure, must be checked.
1638 float_matrix Tx(3,3);
1639 Tx(0,0)= 1; Tx(1,0)= 0; Tx(2,0)=0;
1640 Tx(0,1)= 0; Tx(1,1)=-1; Tx(2,1)=0;
1641 Tx(0,2)= 0; Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
1642 Tx(2,2)=1; */
1643 }
1644
1645 StopTimer(&image->timer);
1646
1647 if (image_info->subrange != 0)
1648 if (image->scene >= (image_info->subimage+image_info->subrange-1))
1649 goto Finish;
1650
1651 /* Allocate next image structure. */
1652 AllocateNextImage(image_info,image);
1653 image->depth=8;
1654 if (image->next == (Image *) NULL)
1655 goto Finish;
1656 image=SyncNextImageInList(image);
1657 image->columns=image->rows=0;
1658 image->colors=0;
1659 break;
1660
1661 case 0x12: /* Postscript WPG2*/
1662 i=ReadBlobLSBShort(image);
1663 if(Rec2.RecordLength > ((unsigned long) i+2))
1664 image=ExtractPostscript(image,image_info,
1665 TellBlob(image)+i, /*skip PS header in the wpg2*/
1666 (size_t)Rec2.RecordLength-i-2,exception);
1667 break;
1668
1669 case 0x1B: /*bitmap rectangle*/
1670 (void) LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM); /* WPG2Flags */
1671 break;
1672 }
1673 }
1674
1675 break;
1676
1677 default:
1678 {
1679 ThrowReaderException(CoderError,DataEncodingSchemeIsNotSupported,image);
1680 }
1681 }
1682
1683 Finish:
1684 CloseBlob(image);
1685
1686 {
1687 Image
1688 *p;
1689
1690 long
1691 scene=0;
1692
1693 /*
1694 Rewind list, removing any empty images while rewinding.
1695 */
1696 p=image;
1697 image=NULL;
1698 while (p != (Image *) NULL)
1699 {
1700 Image *tmp=p;
1701 if ((p->rows == 0) || (p->columns == 0)) {
1702 p=p->previous;
1703 DeleteImageFromList(&tmp);
1704 } else {
1705 image=p;
1706 p=p->previous;
1707 }
1708 }
1709
1710 /*
1711 Fix scene numbers
1712 */
1713 for (p=image; p != (Image *) NULL; p=p->next)
1714 p->scene=scene++;
1715 }
1716
1717 if (logging) (void)LogMagickEvent(CoderEvent,GetMagickModule(),"return");
1718 if(image==NULL)
1719 ThrowReaderException(CorruptImageError,ImageFileDoesNotContainAnyImageData,image);
1720 return(image);
1721 }
1722
1723 /*
1724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1725 % %
1726 % %
1727 % %
1728 % R e g i s t e r W P G I m a g e %
1729 % %
1730 % %
1731 % %
1732 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1733 %
1734 % Method RegisterWPGImage adds attributes for the WPG image format to
1735 % the list of supported formats. The attributes include the image format
1736 % tag, a method to read and/or write the format, whether the format
1737 % supports the saving of more than one frame to the same file or blob,
1738 % whether the format supports native in-memory I/O, and a brief
1739 % description of the format.
1740 %
1741 % The format of the RegisterWPGImage method is:
1742 %
1743 % RegisterWPGImage(void)
1744 %
1745 */
RegisterWPGImage(void)1746 ModuleExport void RegisterWPGImage(void)
1747 {
1748 MagickInfo
1749 *entry;
1750
1751 entry=SetMagickInfo("WPG");
1752 entry->decoder=(DecoderHandler) ReadWPGImage;
1753 entry->magick=(MagickHandler) IsWPG;
1754 entry->description="Word Perfect Graphics";
1755 entry->module="WPG";
1756 entry->seekable_stream=True;
1757 entry->coder_class=UnstableCoderClass;
1758 (void) RegisterMagickInfo(entry);
1759 }
1760
1761 /*
1762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1763 % %
1764 % %
1765 % %
1766 % U n r e g i s t e r W P G I m a g e %
1767 % %
1768 % %
1769 % %
1770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1771 %
1772 % Method UnregisterWPGImage removes format registrations made by the
1773 % WPG module from the list of supported formats.
1774 %
1775 % The format of the UnregisterWPGImage method is:
1776 %
1777 % UnregisterWPGImage(void)
1778 %
1779 */
UnregisterWPGImage(void)1780 ModuleExport void UnregisterWPGImage(void)
1781 {
1782 (void) UnregisterMagickInfo("WPG");
1783 }
1784