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 if(Precision==0)
713 {(void) ReadBlobLSBShort(image);} /*ObjectID*/
714 else
715 {(void) ReadBlobLSBLong(image);} /*ObjectID (Double precision)*/
716 }
717 if(Flags & ROT)
718 {
719 x=ReadBlobLSBLong(image); /*Rot Angle*/
720 if(Angle) *Angle=x/65536.0;
721 }
722 if(Flags & (ROT|SCL))
723 {
724 x=ReadBlobLSBLong(image); /*Sx*cos()*/
725 (*CTM)[0][0] = (float)x/0x10000;
726 x=ReadBlobLSBLong(image); /*Sy*cos()*/
727 (*CTM)[1][1] = (float)x/0x10000;
728 }
729 if(Flags & (ROT|SKW))
730 {
731 x=ReadBlobLSBLong(image); /*Kx*sin()*/
732 (*CTM)[1][0] = (float)x/0x10000;
733 x=ReadBlobLSBLong(image); /*Ky*sin()*/
734 (*CTM)[0][1] = (float)x/0x10000;
735 }
736 if(Flags & TRN)
737 {
738 x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Tx*/
739 if(x>=0) (*CTM)[0][2] = (float)x+(float)DenX/0x10000;
740 else (*CTM)[0][2] = (float)x-(float)DenX/0x10000;
741 x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Ty*/
742 (*CTM)[1][2]=(float)x + ((x>=0)?1:-1)*(float)DenX/0x10000;
743 if(x>=0) (*CTM)[1][2] = (float)x+(float)DenX/0x10000;
744 else (*CTM)[1][2] = (float)x-(float)DenX/0x10000;
745 }
746 if(Flags & TPR)
747 {
748 x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Px*/
749 (*CTM)[2][0] = x + (float)DenX/0x10000;;
750 x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Py*/
751 (*CTM)[2][1] = x + (float)DenX/0x10000;
752 }
753 return(Flags);
754 }
755
756
ExtractPostscript(Image * image,const ImageInfo * image_info,MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo * exception)757 static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
758 MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo *exception)
759 {
760 char
761 postscript_file[MagickPathExtent];
762
763 const MagicInfo
764 *magic_info;
765
766 FILE
767 *ps_file;
768
769 int
770 c;
771
772 ImageInfo
773 *clone_info;
774
775 Image
776 *image2;
777
778 MagickBooleanType
779 status;
780
781 unsigned char
782 magick[2*MagickPathExtent];
783
784 ssize_t
785 count;
786
787 if ((clone_info=CloneImageInfo(image_info)) == NULL)
788 return(image);
789 clone_info->blob=(void *) NULL;
790 clone_info->length=0;
791 status=MagickFalse;
792
793 /* Obtain temporary file */
794 (void) AcquireUniqueFilename(postscript_file);
795 ps_file=fopen_utf8(postscript_file,"wb");
796 if (ps_file == (FILE *) NULL)
797 goto FINISH;
798
799 /* Copy postscript to temporary file */
800 if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
801 {
802 (void) fclose(ps_file);
803 ThrowException(exception,CorruptImageError,"ImproperImageHeader",
804 image->filename);
805 goto FINISH_UNL;
806 }
807 count=ReadBlob(image, 2*MagickPathExtent, magick);
808 if (count < 1)
809 {
810 (void) fclose(ps_file);
811 ThrowException(exception,CorruptImageError,"ImproperImageHeader",
812 image->filename);
813 goto FINISH_UNL;
814 }
815
816 if (SeekBlob(image,PS_Offset,SEEK_SET) != PS_Offset)
817 {
818 (void) fclose(ps_file);
819 ThrowException(exception,CorruptImageError,"ImproperImageHeader",
820 image->filename);
821 goto FINISH_UNL;
822 }
823 while (PS_Size-- > 0)
824 {
825 c=ReadBlobByte(image);
826 if (c == EOF)
827 {
828 (void) fclose(ps_file);
829 ThrowException(exception,CorruptImageError,"ImproperImageHeader",
830 image->filename);
831 goto FINISH_UNL;
832 }
833 (void) fputc(c,ps_file);
834 }
835 (void) fclose(ps_file);
836
837 /* Detect file format - Check magic.mgk configuration file. */
838 magic_info=GetMagicInfo(magick,count,exception);
839 if(magic_info == (const MagicInfo *) NULL) goto FINISH_UNL;
840 /* printf("Detected:%s \n",magic_info->name); */
841 if(exception->severity != UndefinedException) goto FINISH_UNL;
842 (void) CopyMagickString(clone_info->magick,GetMagicName(magic_info),
843 MagickPathExtent);
844 if (LocaleCompare(clone_info->magick,"PFB") != 0)
845 {
846 ThrowException(exception,CorruptImageError,"ImproperImageHeader",
847 image->filename);
848 goto FINISH_UNL;
849 }
850
851 /* Read nested image */
852 /*FormatString(clone_info->filename,"%s:%s",magic_info->name,postscript_file);*/
853 FormatLocaleString(clone_info->filename,MagickPathExtent,"%.1024s:%.1024s",
854 clone_info->magick,postscript_file);
855 image2=ReadImage(clone_info,exception);
856
857 if (!image2)
858 goto FINISH_UNL;
859 if(exception->severity>=ErrorException)
860 {
861 CloseBlob(image2);
862 DestroyImageList(image2);
863 goto FINISH_UNL;
864 }
865
866 {
867 Image
868 *p;
869
870 /*
871 Replace current image with new image while copying base image attributes.
872 */
873 p=image2;
874 do
875 {
876 (void) CopyMagickString(p->filename,image->filename,MagickPathExtent);
877 (void) CopyMagickString(p->magick_filename,image->magick_filename,
878 MagickPathExtent);
879 (void) CopyMagickString(p->magick,image->magick,MagickPathExtent);
880 if ((p->rows == 0) || (p->columns == 0))
881 {
882 DeleteImageFromList(&p);
883 if (p == (Image *) NULL)
884 {
885 image2=(Image *) NULL;
886 goto FINISH_UNL;
887 }
888 }
889 else
890 {
891 DestroyBlob(p);
892 p->blob=ReferenceBlob(image->blob);
893 p=p->next;
894 }
895 } while (p != (Image *) NULL);
896 }
897
898 if ((image->rows == 0 || image->columns == 0) &&
899 (image->previous != NULL || image->next != NULL))
900 {
901 DeleteImageFromList(&image);
902 }
903
904 AppendImageToList(&image,image2);
905 while (image->next != NULL)
906 image=image->next;
907 status=MagickTrue;
908
909 FINISH_UNL:
910 (void) RelinquishUniqueFileResource(postscript_file);
911 FINISH:
912 DestroyImageInfo(clone_info);
913 if (status == MagickFalse)
914 return(DestroyImageList(image));
915 return(image);
916 }
917
918 /*
919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
920 % %
921 % %
922 % %
923 % R e a d W P G I m a g e %
924 % %
925 % %
926 % %
927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
928 %
929 % Method ReadWPGImage reads an WPG X image file and returns it. It
930 % allocates the memory necessary for the new Image structure and returns a
931 % pointer to the new image.
932 %
933 % The format of the ReadWPGImage method is:
934 %
935 % Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
936 %
937 % A description of each parameter follows:
938 %
939 % o image: Method ReadWPGImage returns a pointer to the image after
940 % reading. A null image is returned if there is a memory shortage or if
941 % the image cannot be read.
942 %
943 % o image_info: Specifies a pointer to a ImageInfo structure.
944 %
945 % o exception: return any errors or warnings in this structure.
946 %
947 */
ReadWPGImage(const ImageInfo * image_info,ExceptionInfo * exception)948 static Image *ReadWPGImage(const ImageInfo *image_info,
949 ExceptionInfo *exception)
950 {
951 typedef struct
952 {
953 size_t FileId;
954 MagickOffsetType DataOffset;
955 unsigned int ProductType;
956 unsigned int FileType;
957 unsigned char MajorVersion;
958 unsigned char MinorVersion;
959 unsigned int EncryptKey;
960 unsigned int Reserved;
961 } WPGHeader;
962
963 typedef struct
964 {
965 unsigned char RecType;
966 size_t RecordLength;
967 } WPGRecord;
968
969 typedef struct
970 {
971 unsigned char Class;
972 unsigned char RecType;
973 size_t Extension;
974 size_t RecordLength;
975 } WPG2Record;
976
977 typedef struct
978 {
979 unsigned HorizontalUnits;
980 unsigned VerticalUnits;
981 unsigned char PosSizePrecision;
982 } WPG2Start;
983
984 typedef struct
985 {
986 unsigned int Width;
987 unsigned int Height;
988 unsigned int Depth;
989 unsigned int HorzRes;
990 unsigned int VertRes;
991 } WPGBitmapType1;
992
993 typedef struct
994 {
995 unsigned int Width;
996 unsigned int Height;
997 unsigned char Depth;
998 unsigned char Compression;
999 } WPG2BitmapType1;
1000
1001 typedef struct
1002 {
1003 unsigned int RotAngle;
1004 unsigned int LowLeftX;
1005 unsigned int LowLeftY;
1006 unsigned int UpRightX;
1007 unsigned int UpRightY;
1008 unsigned int Width;
1009 unsigned int Height;
1010 unsigned int Depth;
1011 unsigned int HorzRes;
1012 unsigned int VertRes;
1013 } WPGBitmapType2;
1014
1015 typedef struct
1016 {
1017 unsigned int StartIndex;
1018 unsigned int NumOfEntries;
1019 } WPGColorMapRec;
1020
1021 /*
1022 typedef struct {
1023 size_t PS_unknown1;
1024 unsigned int PS_unknown2;
1025 unsigned int PS_unknown3;
1026 } WPGPSl1Record;
1027 */
1028
1029 Image
1030 *image;
1031
1032 unsigned int
1033 status;
1034
1035 WPGHeader
1036 Header;
1037
1038 WPGRecord
1039 Rec;
1040
1041 WPG2Record
1042 Rec2;
1043
1044 WPG2Start StartWPG;
1045
1046 WPGBitmapType1
1047 BitmapHeader1;
1048
1049 WPG2BitmapType1
1050 Bitmap2Header1;
1051
1052 WPGBitmapType2
1053 BitmapHeader2;
1054
1055 WPGColorMapRec
1056 WPG_Palette;
1057
1058 int
1059 i,
1060 bpp,
1061 WPG2Flags;
1062
1063 ssize_t
1064 ldblk;
1065
1066 size_t
1067 one;
1068
1069 unsigned char
1070 *BImgBuff;
1071
1072 tCTM CTM; /*current transform matrix*/
1073
1074 /*
1075 Open image file.
1076 */
1077 assert(image_info != (const ImageInfo *) NULL);
1078 assert(image_info->signature == MagickCoreSignature);
1079 assert(exception != (ExceptionInfo *) NULL);
1080 assert(exception->signature == MagickCoreSignature);
1081 one=1;
1082 image=AcquireImage(image_info,exception);
1083 image->depth=8;
1084 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1085 if (status == MagickFalse)
1086 {
1087 image=DestroyImageList(image);
1088 return((Image *) NULL);
1089 }
1090 /*
1091 Read WPG image.
1092 */
1093 Header.FileId=ReadBlobLSBLong(image);
1094 Header.DataOffset=(MagickOffsetType) ReadBlobLSBLong(image);
1095 Header.ProductType=ReadBlobLSBShort(image);
1096 Header.FileType=ReadBlobLSBShort(image);
1097 Header.MajorVersion=ReadBlobByte(image);
1098 Header.MinorVersion=ReadBlobByte(image);
1099 Header.EncryptKey=ReadBlobLSBShort(image);
1100 Header.Reserved=ReadBlobLSBShort(image);
1101
1102 if (Header.FileId!=0x435057FF || (Header.ProductType>>8)!=0x16)
1103 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1104 if (Header.EncryptKey!=0)
1105 ThrowReaderException(CoderError,"EncryptedWPGImageFileNotSupported");
1106
1107 image->columns = 1;
1108 image->rows = 1;
1109 image->colors = 0;
1110 image->storage_class=DirectClass;
1111 (void) ResetImagePixels(image,exception);
1112 bpp=0;
1113 BitmapHeader2.RotAngle=0;
1114 Rec2.RecordLength=0;
1115
1116 switch(Header.FileType)
1117 {
1118 case 1: /* WPG level 1 */
1119 while(!EOFBlob(image)) /* object parser loop */
1120 {
1121 if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
1122 break;
1123 if(EOFBlob(image))
1124 break;
1125
1126 Rec.RecType=(i=ReadBlobByte(image));
1127 if(i==EOF)
1128 break;
1129 Rd_WP_DWORD(image,&Rec.RecordLength);
1130 if (Rec.RecordLength > GetBlobSize(image))
1131 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1132 if(EOFBlob(image))
1133 break;
1134
1135 Header.DataOffset=TellBlob(image)+Rec.RecordLength;
1136
1137 switch(Rec.RecType)
1138 {
1139 case 0x0B: /* bitmap type 1 */
1140 BitmapHeader1.Width=ReadBlobLSBShort(image);
1141 BitmapHeader1.Height=ReadBlobLSBShort(image);
1142 if ((BitmapHeader1.Width == 0) || (BitmapHeader1.Height == 0))
1143 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1144 BitmapHeader1.Depth=ReadBlobLSBShort(image);
1145 BitmapHeader1.HorzRes=ReadBlobLSBShort(image);
1146 BitmapHeader1.VertRes=ReadBlobLSBShort(image);
1147
1148 if(BitmapHeader1.HorzRes && BitmapHeader1.VertRes)
1149 {
1150 image->units=PixelsPerCentimeterResolution;
1151 image->resolution.x=BitmapHeader1.HorzRes/470.0;
1152 image->resolution.y=BitmapHeader1.VertRes/470.0;
1153 }
1154 image->columns=BitmapHeader1.Width;
1155 image->rows=BitmapHeader1.Height;
1156 bpp=BitmapHeader1.Depth;
1157
1158 goto UnpackRaster;
1159
1160 case 0x0E: /*Color palette */
1161 WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1162 WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1163 if ((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
1164 (Rec2.RecordLength-2-2)/3)
1165 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1166 if (WPG_Palette.StartIndex > WPG_Palette.NumOfEntries)
1167 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1168 image->colors=WPG_Palette.NumOfEntries;
1169 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
1170 goto NoMemory;
1171 for (i=WPG_Palette.StartIndex;
1172 i < (int)WPG_Palette.NumOfEntries; i++)
1173 {
1174 image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1175 ReadBlobByte(image));
1176 image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1177 ReadBlobByte(image));
1178 image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1179 ReadBlobByte(image));
1180 }
1181 break;
1182
1183 case 0x11: /* Start PS l1 */
1184 if (Rec.RecordLength > 8)
1185 {
1186 image=ExtractPostscript(image,image_info,
1187 TellBlob(image)+8, /* skip PS header in the wpg */
1188 (ssize_t) Rec.RecordLength-8,exception);
1189 if (image == NULL)
1190 ThrowReaderException(CorruptImageError,
1191 "ImproperImageHeader");
1192 }
1193 break;
1194
1195 case 0x14: /* bitmap type 2 */
1196 BitmapHeader2.RotAngle=ReadBlobLSBShort(image);
1197 BitmapHeader2.LowLeftX=ReadBlobLSBShort(image);
1198 BitmapHeader2.LowLeftY=ReadBlobLSBShort(image);
1199 BitmapHeader2.UpRightX=ReadBlobLSBShort(image);
1200 BitmapHeader2.UpRightY=ReadBlobLSBShort(image);
1201 BitmapHeader2.Width=ReadBlobLSBShort(image);
1202 BitmapHeader2.Height=ReadBlobLSBShort(image);
1203 if ((BitmapHeader2.Width == 0) || (BitmapHeader2.Height == 0))
1204 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1205 BitmapHeader2.Depth=ReadBlobLSBShort(image);
1206 BitmapHeader2.HorzRes=ReadBlobLSBShort(image);
1207 BitmapHeader2.VertRes=ReadBlobLSBShort(image);
1208
1209 image->units=PixelsPerCentimeterResolution;
1210 image->page.width=(unsigned int)
1211 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0);
1212 image->page.height=(unsigned int)
1213 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0);
1214 image->page.x=(int) (BitmapHeader2.LowLeftX/470.0);
1215 image->page.y=(int) (BitmapHeader2.LowLeftX/470.0);
1216 if(BitmapHeader2.HorzRes && BitmapHeader2.VertRes)
1217 {
1218 image->resolution.x=BitmapHeader2.HorzRes/470.0;
1219 image->resolution.y=BitmapHeader2.VertRes/470.0;
1220 }
1221 image->columns=BitmapHeader2.Width;
1222 image->rows=BitmapHeader2.Height;
1223 bpp=BitmapHeader2.Depth;
1224
1225 UnpackRaster:
1226 status=SetImageExtent(image,image->columns,image->rows,exception);
1227 if (status == MagickFalse)
1228 break;
1229 (void) ResetImagePixels(image,exception);
1230 if ((image->storage_class != PseudoClass) && (bpp < 24))
1231 {
1232 image->colors=one << bpp;
1233 if (image->colors > GetBlobSize(image))
1234 ThrowReaderException(CorruptImageError,
1235 "InsufficientImageDataInFile");
1236 if (!AcquireImageColormap(image,image->colors,exception))
1237 {
1238 NoMemory:
1239 ThrowReaderException(ResourceLimitError,
1240 "MemoryAllocationFailed");
1241 }
1242 /* printf("Load default colormap \n"); */
1243 for (i=0; (i < (int) image->colors) && (i < 256); i++)
1244 {
1245 image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red);
1246 image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green);
1247 image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue);
1248 image->colormap[i].alpha=OpaqueAlpha;
1249 }
1250 }
1251 else
1252 {
1253 if (bpp < 24)
1254 if ( (image->colors < (one << bpp)) && (bpp != 24) )
1255 {
1256 PixelInfo
1257 *colormap;
1258
1259 size_t
1260 colors;
1261
1262 colormap=image->colormap;
1263 colors=image->colors;
1264 image->colormap=(PixelInfo *) NULL;
1265 if (AcquireImageColormap(image,one << bpp,exception) == MagickFalse)
1266 {
1267 colormap=(PixelInfo *)
1268 RelinquishMagickMemory(colormap);
1269 goto NoMemory;
1270 }
1271 (void) memcpy(image->colormap,colormap,MagickMin(
1272 image->colors,colors)*sizeof(*image->colormap));
1273 colormap=(PixelInfo *)
1274 RelinquishMagickMemory(colormap);
1275 }
1276 }
1277
1278 if ((bpp == 1) && (image->colors > 1))
1279 {
1280 if(image->colormap[0].red==0 &&
1281 image->colormap[0].green==0 &&
1282 image->colormap[0].blue==0 &&
1283 image->colormap[1].red==0 &&
1284 image->colormap[1].green==0 &&
1285 image->colormap[1].blue==0)
1286 { /* fix crippled monochrome palette */
1287 image->colormap[1].red =
1288 image->colormap[1].green =
1289 image->colormap[1].blue = QuantumRange;
1290 image->colormap[1].alpha=OpaqueAlpha;
1291 }
1292 }
1293 if(!image_info->ping)
1294 if(UnpackWPGRaster(image,bpp,exception) < 0)
1295 /* The raster cannot be unpacked */
1296 {
1297 DecompressionFailed:
1298 ThrowReaderException(CoderError,"UnableToDecompressImage");
1299 }
1300
1301 if(Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
1302 {
1303 /* flop command */
1304 if(BitmapHeader2.RotAngle & 0x8000)
1305 {
1306 Image
1307 *flop_image;
1308
1309 flop_image = FlopImage(image, exception);
1310 if (flop_image != (Image *) NULL) {
1311 DuplicateBlob(flop_image,image);
1312 ReplaceImageInList(&image,flop_image);
1313 }
1314 }
1315 /* flip command */
1316 if(BitmapHeader2.RotAngle & 0x2000)
1317 {
1318 Image
1319 *flip_image;
1320
1321 flip_image = FlipImage(image, exception);
1322 if (flip_image != (Image *) NULL) {
1323 DuplicateBlob(flip_image,image);
1324 ReplaceImageInList(&image,flip_image);
1325 }
1326 }
1327 /* rotate command */
1328 if(BitmapHeader2.RotAngle & 0x0FFF)
1329 {
1330 Image
1331 *rotate_image;
1332
1333 rotate_image=RotateImage(image,(BitmapHeader2.RotAngle &
1334 0x0FFF), exception);
1335 if (rotate_image != (Image *) NULL) {
1336 DuplicateBlob(rotate_image,image);
1337 ReplaceImageInList(&image,rotate_image);
1338 }
1339 }
1340 }
1341
1342 /* Allocate next image structure. */
1343 if ((image_info->ping != MagickFalse) &&
1344 (image_info->number_scenes != 0))
1345 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1346 goto Finish;
1347 AcquireNextImage(image_info,image,exception);
1348 image->depth=8;
1349 if (image->next == (Image *) NULL)
1350 goto Finish;
1351 image=SyncNextImageInList(image);
1352 image->columns=image->rows=0;
1353 image->colors=0;
1354 break;
1355
1356 case 0x1B: /* Postscript l2 */
1357 if (Rec.RecordLength>0x3C)
1358 {
1359 image=ExtractPostscript(image,image_info,
1360 TellBlob(image)+0x3C, /* skip PS l2 header in the wpg */
1361 (ssize_t) Rec.RecordLength-0x3C,exception);
1362 if (image == NULL)
1363 ThrowReaderException(CorruptImageError,
1364 "ImproperImageHeader");
1365 }
1366 break;
1367 }
1368 }
1369 break;
1370
1371 case 2: /* WPG level 2 */
1372 (void) memset(CTM,0,sizeof(CTM));
1373 StartWPG.PosSizePrecision = 0;
1374 while(!EOFBlob(image)) /* object parser loop */
1375 {
1376 if (SeekBlob(image,Header.DataOffset,SEEK_SET) != Header.DataOffset)
1377 break;
1378 if (EOFBlob(image))
1379 break;
1380
1381 Rec2.Class=(i=ReadBlobByte(image));
1382 if(i==EOF)
1383 break;
1384 Rec2.RecType=(i=ReadBlobByte(image));
1385 if(i==EOF)
1386 break;
1387 Rd_WP_DWORD(image,&Rec2.Extension);
1388 Rd_WP_DWORD(image,&Rec2.RecordLength);
1389 if(EOFBlob(image))
1390 break;
1391
1392 Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
1393
1394 switch(Rec2.RecType)
1395 {
1396 case 1:
1397 StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
1398 StartWPG.VerticalUnits=ReadBlobLSBShort(image);
1399 StartWPG.PosSizePrecision=ReadBlobByte(image);
1400 break;
1401 case 0x0C: /* Color palette */
1402 WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1403 WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1404 if ((WPG_Palette.NumOfEntries-WPG_Palette.StartIndex) >
1405 (Rec2.RecordLength-2-2) / 3)
1406 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1407 if (WPG_Palette.StartIndex >= WPG_Palette.NumOfEntries)
1408 ThrowReaderException(CorruptImageError,"InvalidColormapIndex");
1409 image->colors=WPG_Palette.NumOfEntries;
1410 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
1411 ThrowReaderException(ResourceLimitError,
1412 "MemoryAllocationFailed");
1413 for (i=WPG_Palette.StartIndex;
1414 i < (int)WPG_Palette.NumOfEntries; i++)
1415 {
1416 image->colormap[i].red=ScaleCharToQuantum((char)
1417 ReadBlobByte(image));
1418 image->colormap[i].green=ScaleCharToQuantum((char)
1419 ReadBlobByte(image));
1420 image->colormap[i].blue=ScaleCharToQuantum((char)
1421 ReadBlobByte(image));
1422 image->colormap[i].alpha=OpaqueAlpha;
1423 (void) ReadBlobByte(image); /*Opacity??*/
1424 }
1425 break;
1426 case 0x0E:
1427 Bitmap2Header1.Width=ReadBlobLSBShort(image);
1428 Bitmap2Header1.Height=ReadBlobLSBShort(image);
1429 if ((Bitmap2Header1.Width == 0) || (Bitmap2Header1.Height == 0))
1430 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1431 Bitmap2Header1.Depth=ReadBlobByte(image);
1432 Bitmap2Header1.Compression=ReadBlobByte(image);
1433
1434 if(Bitmap2Header1.Compression > 1)
1435 continue; /*Unknown compression method */
1436 switch(Bitmap2Header1.Depth)
1437 {
1438 case 1:
1439 bpp=1;
1440 break;
1441 case 2:
1442 bpp=2;
1443 break;
1444 case 3:
1445 bpp=4;
1446 break;
1447 case 4:
1448 bpp=8;
1449 break;
1450 case 8:
1451 bpp=24;
1452 break;
1453 default:
1454 continue; /*Ignore raster with unknown depth*/
1455 }
1456 image->columns=Bitmap2Header1.Width;
1457 image->rows=Bitmap2Header1.Height;
1458 if (image_info->ping != MagickFalse)
1459 return(image);
1460 status=SetImageExtent(image,image->columns,image->rows,exception);
1461 if (status != MagickFalse)
1462 status=ResetImagePixels(image,exception);
1463 if (status == MagickFalse)
1464 break;
1465 if ((image->colors == 0) && (bpp != 24))
1466 {
1467 image->colors=one << bpp;
1468 if (!AcquireImageColormap(image,image->colors,exception))
1469 goto NoMemory;
1470 }
1471 else
1472 {
1473 if(bpp < 24)
1474 if( image->colors<(one << bpp) && bpp!=24 )
1475 image->colormap=(PixelInfo *) ResizeQuantumMemory(
1476 image->colormap,(size_t) (one << bpp),
1477 sizeof(*image->colormap));
1478 }
1479
1480
1481 switch(Bitmap2Header1.Compression)
1482 {
1483 case 0: /*Uncompressed raster*/
1484 {
1485 ldblk=(ssize_t) ((bpp*image->columns+7)/8);
1486 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t)
1487 ldblk+1,sizeof(*BImgBuff));
1488 if (BImgBuff == (unsigned char *) NULL)
1489 goto NoMemory;
1490 for (i=0; i< (ssize_t) image->rows; i++)
1491 {
1492 ssize_t
1493 count;
1494
1495 count=ReadBlob(image,(size_t) ldblk,BImgBuff);
1496 if (count != ldblk)
1497 break;
1498 if (InsertRow(image,BImgBuff,i,bpp,exception) == MagickFalse)
1499 break;
1500 }
1501 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
1502 if (i < (ssize_t) image->rows)
1503 goto DecompressionFailed;
1504 break;
1505 }
1506 case 1: /*RLE for WPG2 */
1507 {
1508 if( UnpackWPG2Raster(image,bpp,exception) < 0)
1509 goto DecompressionFailed;
1510 break;
1511 }
1512 }
1513
1514 if(CTM[0][0]<0 && !image_info->ping)
1515 { /*?? RotAngle=360-RotAngle;*/
1516 Image
1517 *flop_image;
1518
1519 flop_image = FlopImage(image, exception);
1520 if (flop_image != (Image *) NULL) {
1521 DuplicateBlob(flop_image,image);
1522 ReplaceImageInList(&image,flop_image);
1523 }
1524 /* Try to change CTM according to Flip - I am not sure, must be checked.
1525 Tx(0,0)=-1; Tx(1,0)=0; Tx(2,0)=0;
1526 Tx(0,1)= 0; Tx(1,1)=1; Tx(2,1)=0;
1527 Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
1528 Tx(1,2)=0; Tx(2,2)=1; */
1529 }
1530 if(CTM[1][1]<0 && !image_info->ping)
1531 { /*?? RotAngle=360-RotAngle;*/
1532 Image
1533 *flip_image;
1534
1535 flip_image = FlipImage(image, exception);
1536 if (flip_image != (Image *) NULL) {
1537 DuplicateBlob(flip_image,image);
1538 ReplaceImageInList(&image,flip_image);
1539 }
1540 /* Try to change CTM according to Flip - I am not sure, must be checked.
1541 float_matrix Tx(3,3);
1542 Tx(0,0)= 1; Tx(1,0)= 0; Tx(2,0)=0;
1543 Tx(0,1)= 0; Tx(1,1)=-1; Tx(2,1)=0;
1544 Tx(0,2)= 0; Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
1545 Tx(2,2)=1; */
1546 }
1547
1548
1549 /* Allocate next image structure. */
1550 if ((image_info->ping != MagickFalse) &&
1551 (image_info->number_scenes != 0))
1552 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
1553 goto Finish;
1554 AcquireNextImage(image_info,image,exception);
1555 image->depth=8;
1556 if (image->next == (Image *) NULL)
1557 goto Finish;
1558 image=SyncNextImageInList(image);
1559 image->columns=image->rows=0;
1560 image->colors=0;
1561 break;
1562
1563 case 0x12: /* Postscript WPG2*/
1564 i=ReadBlobLSBShort(image);
1565 if (Rec2.RecordLength > (unsigned int) i)
1566 {
1567 image=ExtractPostscript(image,image_info,
1568 TellBlob(image)+i, /*skip PS header in the wpg2*/
1569 (ssize_t) (Rec2.RecordLength-i-2),exception);
1570 if (image == NULL)
1571 ThrowReaderException(CorruptImageError,
1572 "ImproperImageHeader");
1573 }
1574 break;
1575
1576 case 0x1B: /*bitmap rectangle*/
1577 WPG2Flags = LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM);
1578 (void) WPG2Flags;
1579 break;
1580 }
1581 }
1582
1583 break;
1584
1585 default:
1586 {
1587 ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
1588 }
1589 }
1590
1591 Finish:
1592 (void) CloseBlob(image);
1593
1594 {
1595 Image
1596 *p;
1597
1598 ssize_t
1599 scene=0;
1600
1601 /*
1602 Rewind list, removing any empty images while rewinding.
1603 */
1604 p=image;
1605 image=NULL;
1606 while (p != (Image *) NULL)
1607 {
1608 Image *tmp=p;
1609 if ((p->rows == 0) || (p->columns == 0)) {
1610 p=p->previous;
1611 DeleteImageFromList(&tmp);
1612 } else {
1613 image=p;
1614 p=p->previous;
1615 }
1616 }
1617 /*
1618 Fix scene numbers.
1619 */
1620 for (p=image; p != (Image *) NULL; p=p->next)
1621 p->scene=(size_t) scene++;
1622 }
1623 if (image == (Image *) NULL)
1624 ThrowReaderException(CorruptImageError,
1625 "ImageFileDoesNotContainAnyImageData");
1626 return(image);
1627 }
1628
1629 /*
1630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631 % %
1632 % %
1633 % %
1634 % R e g i s t e r W P G I m a g e %
1635 % %
1636 % %
1637 % %
1638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639 %
1640 % Method RegisterWPGImage adds attributes for the WPG image format to
1641 % the list of supported formats. The attributes include the image format
1642 % tag, a method to read and/or write the format, whether the format
1643 % supports the saving of more than one frame to the same file or blob,
1644 % whether the format supports native in-memory I/O, and a brief
1645 % description of the format.
1646 %
1647 % The format of the RegisterWPGImage method is:
1648 %
1649 % size_t RegisterWPGImage(void)
1650 %
1651 */
RegisterWPGImage(void)1652 ModuleExport size_t RegisterWPGImage(void)
1653 {
1654 MagickInfo
1655 *entry;
1656
1657 entry=AcquireMagickInfo("WPG","WPG","Word Perfect Graphics");
1658 entry->decoder=(DecodeImageHandler *) ReadWPGImage;
1659 entry->magick=(IsImageFormatHandler *) IsWPG;
1660 entry->flags|=CoderDecoderSeekableStreamFlag;
1661 (void) RegisterMagickInfo(entry);
1662 return(MagickImageCoderSignature);
1663 }
1664
1665 /*
1666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1667 % %
1668 % %
1669 % %
1670 % U n r e g i s t e r W P G I m a g e %
1671 % %
1672 % %
1673 % %
1674 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1675 %
1676 % Method UnregisterWPGImage removes format registrations made by the
1677 % WPG module from the list of supported formats.
1678 %
1679 % The format of the UnregisterWPGImage method is:
1680 %
1681 % UnregisterWPGImage(void)
1682 %
1683 */
UnregisterWPGImage(void)1684 ModuleExport void UnregisterWPGImage(void)
1685 {
1686 (void) UnregisterMagickInfo("WPG");
1687 }
1688