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