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