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