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