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