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