blob: 4e4f8f1e89f5a093be5767b54ebfaabd9bee5528 [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% %
Cristy7ce65e72015-12-12 18:03:16 -050019% Copyright 1999-2016 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*/
cristy4c08aed2011-07-01 19:47:50 +000041#include "MagickCore/studio.h"
42#include "MagickCore/blob.h"
43#include "MagickCore/blob-private.h"
44#include "MagickCore/color-private.h"
45#include "MagickCore/colormap.h"
46#include "MagickCore/colormap-private.h"
47#include "MagickCore/constitute.h"
48#include "MagickCore/exception.h"
49#include "MagickCore/exception-private.h"
50#include "MagickCore/cache.h"
cristyc53413d2011-11-17 13:04:26 +000051#include "MagickCore/distort.h"
cristy4c08aed2011-07-01 19:47:50 +000052#include "MagickCore/image.h"
53#include "MagickCore/image-private.h"
54#include "MagickCore/list.h"
55#include "MagickCore/magic.h"
56#include "MagickCore/magick.h"
57#include "MagickCore/memory_.h"
58#include "MagickCore/resource_.h"
59#include "MagickCore/pixel-accessor.h"
60#include "MagickCore/quantum-private.h"
cristy4c08aed2011-07-01 19:47:50 +000061#include "MagickCore/static.h"
62#include "MagickCore/string_.h"
63#include "MagickCore/module.h"
64#include "MagickCore/transform.h"
65#include "MagickCore/utility.h"
cristy18c6c272011-09-23 14:40:37 +000066#include "MagickCore/utility-private.h"
cristy3ed852e2009-09-05 21:47:34 +000067
68typedef struct
69 {
70 unsigned char Red;
71 unsigned char Blue;
72 unsigned char Green;
73 } RGB_Record;
74
75/* Default palette for WPG level 1 */
cristy41899842013-05-12 18:29:53 +000076static const RGB_Record WPG1_Palette[256]={
cristy3ed852e2009-09-05 21:47:34 +000077{ 0, 0, 0}, { 0, 0,168},
78{ 0,168, 0}, { 0,168,168},
79{168, 0, 0}, {168, 0,168},
80{168, 84, 0}, {168,168,168},
81{ 84, 84, 84}, { 84, 84,252},
82{ 84,252, 84}, { 84,252,252},
83{252, 84, 84}, {252, 84,252},
84{252,252, 84}, {252,252,252}, /*16*/
85{ 0, 0, 0}, { 20, 20, 20},
86{ 32, 32, 32}, { 44, 44, 44},
87{ 56, 56, 56}, { 68, 68, 68},
88{ 80, 80, 80}, { 96, 96, 96},
89{112,112,112}, {128,128,128},
90{144,144,144}, {160,160,160},
91{180,180,180}, {200,200,200},
92{224,224,224}, {252,252,252}, /*32*/
93{ 0, 0,252}, { 64, 0,252},
94{124, 0,252}, {188, 0,252},
95{252, 0,252}, {252, 0,188},
96{252, 0,124}, {252, 0, 64},
97{252, 0, 0}, {252, 64, 0},
98{252,124, 0}, {252,188, 0},
99{252,252, 0}, {188,252, 0},
100{124,252, 0}, { 64,252, 0}, /*48*/
101{ 0,252, 0}, { 0,252, 64},
102{ 0,252,124}, { 0,252,188},
103{ 0,252,252}, { 0,188,252},
104{ 0,124,252}, { 0, 64,252},
105{124,124,252}, {156,124,252},
106{188,124,252}, {220,124,252},
107{252,124,252}, {252,124,220},
108{252,124,188}, {252,124,156}, /*64*/
109{252,124,124}, {252,156,124},
110{252,188,124}, {252,220,124},
111{252,252,124}, {220,252,124},
112{188,252,124}, {156,252,124},
113{124,252,124}, {124,252,156},
114{124,252,188}, {124,252,220},
115{124,252,252}, {124,220,252},
116{124,188,252}, {124,156,252}, /*80*/
117{180,180,252}, {196,180,252},
118{216,180,252}, {232,180,252},
119{252,180,252}, {252,180,232},
120{252,180,216}, {252,180,196},
121{252,180,180}, {252,196,180},
122{252,216,180}, {252,232,180},
123{252,252,180}, {232,252,180},
124{216,252,180}, {196,252,180}, /*96*/
125{180,220,180}, {180,252,196},
126{180,252,216}, {180,252,232},
127{180,252,252}, {180,232,252},
128{180,216,252}, {180,196,252},
129{0,0,112}, {28,0,112},
130{56,0,112}, {84,0,112},
131{112,0,112}, {112,0,84},
132{112,0,56}, {112,0,28}, /*112*/
133{112,0,0}, {112,28,0},
134{112,56,0}, {112,84,0},
135{112,112,0}, {84,112,0},
136{56,112,0}, {28,112,0},
137{0,112,0}, {0,112,28},
138{0,112,56}, {0,112,84},
139{0,112,112}, {0,84,112},
140{0,56,112}, {0,28,112}, /*128*/
141{56,56,112}, {68,56,112},
142{84,56,112}, {96,56,112},
143{112,56,112}, {112,56,96},
144{112,56,84}, {112,56,68},
145{112,56,56}, {112,68,56},
146{112,84,56}, {112,96,56},
147{112,112,56}, {96,112,56},
148{84,112,56}, {68,112,56}, /*144*/
149{56,112,56}, {56,112,69},
150{56,112,84}, {56,112,96},
151{56,112,112}, {56,96,112},
152{56,84,112}, {56,68,112},
153{80,80,112}, {88,80,112},
154{96,80,112}, {104,80,112},
155{112,80,112}, {112,80,104},
156{112,80,96}, {112,80,88}, /*160*/
157{112,80,80}, {112,88,80},
158{112,96,80}, {112,104,80},
159{112,112,80}, {104,112,80},
160{96,112,80}, {88,112,80},
161{80,112,80}, {80,112,88},
162{80,112,96}, {80,112,104},
163{80,112,112}, {80,114,112},
164{80,96,112}, {80,88,112}, /*176*/
165{0,0,64}, {16,0,64},
166{32,0,64}, {48,0,64},
167{64,0,64}, {64,0,48},
168{64,0,32}, {64,0,16},
169{64,0,0}, {64,16,0},
170{64,32,0}, {64,48,0},
171{64,64,0}, {48,64,0},
172{32,64,0}, {16,64,0}, /*192*/
173{0,64,0}, {0,64,16},
174{0,64,32}, {0,64,48},
175{0,64,64}, {0,48,64},
176{0,32,64}, {0,16,64},
177{32,32,64}, {40,32,64},
178{48,32,64}, {56,32,64},
179{64,32,64}, {64,32,56},
180{64,32,48}, {64,32,40}, /*208*/
181{64,32,32}, {64,40,32},
182{64,48,32}, {64,56,32},
183{64,64,32}, {56,64,32},
184{48,64,32}, {40,64,32},
185{32,64,32}, {32,64,40},
186{32,64,48}, {32,64,56},
187{32,64,64}, {32,56,64},
188{32,48,64}, {32,40,64}, /*224*/
189{44,44,64}, {48,44,64},
190{52,44,64}, {60,44,64},
191{64,44,64}, {64,44,60},
192{64,44,52}, {64,44,48},
193{64,44,44}, {64,48,44},
194{64,52,44}, {64,60,44},
195{64,64,44}, {60,64,44},
196{52,64,44}, {48,64,44}, /*240*/
197{44,64,44}, {44,64,48},
198{44,64,52}, {44,64,60},
199{44,64,64}, {44,60,64},
200{44,55,64}, {44,48,64},
201{0,0,0}, {0,0,0},
202{0,0,0}, {0,0,0},
203{0,0,0}, {0,0,0},
204{0,0,0}, {0,0,0} /*256*/
205};
206
207/*
208%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
209% %
210% %
211% %
212% I s W P G %
213% %
214% %
215% %
216%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217%
218% IsWPG() returns True if the image format type, identified by the magick
219% string, is WPG.
220%
221% The format of the IsWPG method is:
222%
223% unsigned int IsWPG(const unsigned char *magick,const size_t length)
224%
225% A description of each parameter follows:
226%
227% o status: Method IsWPG returns True if the image format type is WPG.
228%
229% o magick: compare image format pattern against these bytes.
230%
231% o length: Specifies the length of the magick string.
232%
233*/
234static unsigned int IsWPG(const unsigned char *magick,const size_t length)
235{
236 if (length < 4)
237 return(MagickFalse);
238 if (memcmp(magick,"\377WPC",4) == 0)
239 return(MagickTrue);
240 return(MagickFalse);
241}
242
243
cristybb503372010-05-27 20:51:26 +0000244static void Rd_WP_DWORD(Image *image,size_t *d)
cristy3ed852e2009-09-05 21:47:34 +0000245{
246 unsigned char
247 b;
248
249 b=ReadBlobByte(image);
250 *d=b;
251 if (b < 0xFFU)
252 return;
253 b=ReadBlobByte(image);
cristybb503372010-05-27 20:51:26 +0000254 *d=(size_t) b;
cristy3ed852e2009-09-05 21:47:34 +0000255 b=ReadBlobByte(image);
cristybb503372010-05-27 20:51:26 +0000256 *d+=(size_t) b*256l;
cristy3ed852e2009-09-05 21:47:34 +0000257 if (*d < 0x8000)
258 return;
259 *d=(*d & 0x7FFF) << 16;
260 b=ReadBlobByte(image);
cristybb503372010-05-27 20:51:26 +0000261 *d+=(size_t) b;
cristy3ed852e2009-09-05 21:47:34 +0000262 b=ReadBlobByte(image);
cristybb503372010-05-27 20:51:26 +0000263 *d+=(size_t) b*256l;
cristy3ed852e2009-09-05 21:47:34 +0000264 return;
265}
266
cristyc82a27b2011-10-21 01:07:16 +0000267static void InsertRow(Image *image,unsigned char *p,ssize_t y,int bpp,
268 ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000269{
cristy3ed852e2009-09-05 21:47:34 +0000270 int
271 bit;
272
cristy4c08aed2011-07-01 19:47:50 +0000273 Quantum
cristy3ed852e2009-09-05 21:47:34 +0000274 index;
275
cristy4c08aed2011-07-01 19:47:50 +0000276 register Quantum
277 *q;
278
279 ssize_t
280 x;
cristy3ed852e2009-09-05 21:47:34 +0000281
cristy3ed852e2009-09-05 21:47:34 +0000282 switch (bpp)
283 {
284 case 1: /* Convert bitmap scanline. */
285 {
286 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000287 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000288 break;
cristybb503372010-05-27 20:51:26 +0000289 for (x=0; x < ((ssize_t) image->columns-7); x+=8)
cristy4c08aed2011-07-01 19:47:50 +0000290 {
291 for (bit=0; bit < 8; bit++)
cristy3ed852e2009-09-05 21:47:34 +0000292 {
cristy4c08aed2011-07-01 19:47:50 +0000293 index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
294 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000295 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000296 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000297 }
cristy4c08aed2011-07-01 19:47:50 +0000298 p++;
299 }
cristy3ed852e2009-09-05 21:47:34 +0000300 if ((image->columns % 8) != 0)
301 {
cristybb503372010-05-27 20:51:26 +0000302 for (bit=0; bit < (ssize_t) (image->columns % 8); bit++)
cristy4c08aed2011-07-01 19:47:50 +0000303 {
304 index=((*p) & (0x80 >> bit) ? 0x01 : 0x00);
305 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000306 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000307 q+=GetPixelChannels(image);
cristy4c08aed2011-07-01 19:47:50 +0000308 }
cristy3ed852e2009-09-05 21:47:34 +0000309 p++;
310 }
311 if (!SyncAuthenticPixels(image,exception))
312 break;
313 break;
314 }
315 case 2: /* Convert PseudoColor scanline. */
316 {
317 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000318 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000319 break;
cristybb503372010-05-27 20:51:26 +0000320 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000321 {
cristyc82a27b2011-10-21 01:07:16 +0000322 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
cristy4c08aed2011-07-01 19:47:50 +0000323 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000324 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000325 q+=GetPixelChannels(image);
cristyc82a27b2011-10-21 01:07:16 +0000326 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
cristy4c08aed2011-07-01 19:47:50 +0000327 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000328 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000329 q+=GetPixelChannels(image);
cristyc82a27b2011-10-21 01:07:16 +0000330 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,exception);
cristy4c08aed2011-07-01 19:47:50 +0000331 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000332 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000333 q+=GetPixelChannels(image);
cristyc82a27b2011-10-21 01:07:16 +0000334 index=ConstrainColormapIndex(image,(*p) & 0x3,exception);
cristy4c08aed2011-07-01 19:47:50 +0000335 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000336 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristy3ed852e2009-09-05 21:47:34 +0000337 p++;
cristyed231572011-07-14 02:18:59 +0000338 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000339 }
340 if ((image->columns % 4) != 0)
341 {
cristyc82a27b2011-10-21 01:07:16 +0000342 index=ConstrainColormapIndex(image,(*p >> 6) & 0x3,exception);
cristy4c08aed2011-07-01 19:47:50 +0000343 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000344 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000345 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000346 if ((image->columns % 4) >= 1)
347
348 {
cristyc82a27b2011-10-21 01:07:16 +0000349 index=ConstrainColormapIndex(image,(*p >> 4) & 0x3,exception);
cristy4c08aed2011-07-01 19:47:50 +0000350 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000351 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000352 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000353 if ((image->columns % 4) >= 2)
354
355 {
cristyc82a27b2011-10-21 01:07:16 +0000356 index=ConstrainColormapIndex(image,(*p >> 2) & 0x3,
357 exception);
cristy4c08aed2011-07-01 19:47:50 +0000358 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000359 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000360 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000361 }
362 }
363 p++;
364 }
365 if (SyncAuthenticPixels(image,exception) == MagickFalse)
366 break;
367 break;
368 }
369
370 case 4: /* Convert PseudoColor scanline. */
371 {
372 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000373 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000374 break;
cristybb503372010-05-27 20:51:26 +0000375 for (x=0; x < ((ssize_t) image->columns-1); x+=2)
cristy3ed852e2009-09-05 21:47:34 +0000376 {
cristyc82a27b2011-10-21 01:07:16 +0000377 index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
cristy4c08aed2011-07-01 19:47:50 +0000378 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000379 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000380 q+=GetPixelChannels(image);
cristyc82a27b2011-10-21 01:07:16 +0000381 index=ConstrainColormapIndex(image,(*p) & 0x0f,exception);
cristy4c08aed2011-07-01 19:47:50 +0000382 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000383 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristy3ed852e2009-09-05 21:47:34 +0000384 p++;
cristyed231572011-07-14 02:18:59 +0000385 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000386 }
387 if ((image->columns % 2) != 0)
388 {
cristyc82a27b2011-10-21 01:07:16 +0000389 index=ConstrainColormapIndex(image,(*p >> 4) & 0x0f,exception);
cristy4c08aed2011-07-01 19:47:50 +0000390 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000391 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristy3ed852e2009-09-05 21:47:34 +0000392 p++;
cristyed231572011-07-14 02:18:59 +0000393 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000394 }
395 if (SyncAuthenticPixels(image,exception) == MagickFalse)
396 break;
397 break;
398 }
399 case 8: /* Convert PseudoColor scanline. */
400 {
401 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000402 if (q == (Quantum *) NULL) break;
cristy3ed852e2009-09-05 21:47:34 +0000403
cristybb503372010-05-27 20:51:26 +0000404 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000405 {
cristyc82a27b2011-10-21 01:07:16 +0000406 index=ConstrainColormapIndex(image,*p,exception);
cristy4c08aed2011-07-01 19:47:50 +0000407 SetPixelIndex(image,index,q);
cristy11a06d32015-01-04 12:03:27 +0000408 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
cristy3ed852e2009-09-05 21:47:34 +0000409 p++;
cristyed231572011-07-14 02:18:59 +0000410 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000411 }
412 if (SyncAuthenticPixels(image,exception) == MagickFalse)
413 break;
414 }
415 break;
416
417 case 24: /* Convert DirectColor scanline. */
418 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000419 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000420 break;
cristybb503372010-05-27 20:51:26 +0000421 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000422 {
cristy4c08aed2011-07-01 19:47:50 +0000423 SetPixelRed(image,ScaleCharToQuantum(*p++),q);
424 SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
425 SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
cristyed231572011-07-14 02:18:59 +0000426 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000427 }
428 if (!SyncAuthenticPixels(image,exception))
429 break;
430 break;
431 }
432}
433
434
435/* Helper for WPG1 raster reader. */
436#define InsertByte(b) \
437{ \
438 BImgBuff[x]=b; \
439 x++; \
cristybb503372010-05-27 20:51:26 +0000440 if((ssize_t) x>=ldblk) \
cristy3ed852e2009-09-05 21:47:34 +0000441 { \
cristyc82a27b2011-10-21 01:07:16 +0000442 InsertRow(image,BImgBuff,(ssize_t) y,bpp,exception); \
cristy3ed852e2009-09-05 21:47:34 +0000443 x=0; \
444 y++; \
445 } \
446}
447/* WPG1 raster reader. */
cristyc82a27b2011-10-21 01:07:16 +0000448static int UnpackWPGRaster(Image *image,int bpp,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000449{
450 int
451 x,
452 y,
453 i;
454
455 unsigned char
456 bbuf,
457 *BImgBuff,
458 RunCount;
459
cristybb503372010-05-27 20:51:26 +0000460 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000461 ldblk;
462
463 x=0;
464 y=0;
465
cristybb503372010-05-27 20:51:26 +0000466 ldblk=(ssize_t) ((bpp*image->columns+7)/8);
cristy3ed852e2009-09-05 21:47:34 +0000467 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
cristyf432c632014-12-07 15:11:28 +0000468 8*sizeof(*BImgBuff));
cristy3ed852e2009-09-05 21:47:34 +0000469 if(BImgBuff==NULL) return(-2);
470
cristybb503372010-05-27 20:51:26 +0000471 while(y<(ssize_t) image->rows)
cristy3ed852e2009-09-05 21:47:34 +0000472 {
cristy46938362015-01-10 23:56:02 +0000473 int
474 c;
cristy3ed852e2009-09-05 21:47:34 +0000475
cristy46938362015-01-10 23:56:02 +0000476 c=ReadBlobByte(image);
477 if (c == EOF)
478 break;
479 bbuf=(unsigned char) c;
cristy3ed852e2009-09-05 21:47:34 +0000480 RunCount=bbuf & 0x7F;
481 if(bbuf & 0x80)
482 {
483 if(RunCount) /* repeat next byte runcount * */
484 {
485 bbuf=ReadBlobByte(image);
486 for(i=0;i<(int) RunCount;i++) InsertByte(bbuf);
487 }
488 else { /* read next byte as RunCount; repeat 0xFF runcount* */
cristy1d4a6952015-03-24 00:42:52 +0000489 c=ReadBlobByte(image);
490 if (c < 0)
491 break;
492 RunCount=(unsigned char) c;
cristy3ed852e2009-09-05 21:47:34 +0000493 for(i=0;i<(int) RunCount;i++) InsertByte(0xFF);
494 }
495 }
496 else {
497 if(RunCount) /* next runcount byte are readed directly */
498 {
499 for(i=0;i < (int) RunCount;i++)
500 {
501 bbuf=ReadBlobByte(image);
502 InsertByte(bbuf);
503 }
504 }
505 else { /* repeat previous line runcount* */
cristy1d4a6952015-03-24 00:42:52 +0000506 c=ReadBlobByte(image);
507 if (c < 0)
508 break;
509 RunCount=(unsigned char) c;
cristy3ed852e2009-09-05 21:47:34 +0000510 if(x) { /* attempt to duplicate row from x position: */
511 /* I do not know what to do here */
512 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
513 return(-3);
514 }
515 for(i=0;i < (int) RunCount;i++)
516 {
517 x=0;
518 y++; /* Here I need to duplicate previous row RUNCOUNT* */
519 if(y<2) continue;
cristybb503372010-05-27 20:51:26 +0000520 if(y>(ssize_t) image->rows)
cristy3ed852e2009-09-05 21:47:34 +0000521 {
522 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
523 return(-4);
524 }
cristyc82a27b2011-10-21 01:07:16 +0000525 InsertRow(image,BImgBuff,y-1,bpp,exception);
cristy3ed852e2009-09-05 21:47:34 +0000526 }
527 }
528 }
529 }
530 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
cristy46938362015-01-10 23:56:02 +0000531 return(y <(ssize_t) image->rows ? -5 : 0);
cristy3ed852e2009-09-05 21:47:34 +0000532}
533
534
535/* Helper for WPG2 reader. */
536#define InsertByte6(b) \
537{ \
dirk93b02b72013-11-16 16:03:36 +0000538DisableMSCWarning(4310) \
cristy3ed852e2009-09-05 21:47:34 +0000539 if(XorMe)\
540 BImgBuff[x] = (unsigned char)~b;\
541 else\
542 BImgBuff[x] = b;\
dirk93b02b72013-11-16 16:03:36 +0000543RestoreMSCWarning \
cristy3ed852e2009-09-05 21:47:34 +0000544 x++; \
cristybb503372010-05-27 20:51:26 +0000545 if((ssize_t) x >= ldblk) \
cristy3ed852e2009-09-05 21:47:34 +0000546 { \
cristyc82a27b2011-10-21 01:07:16 +0000547 InsertRow(image,BImgBuff,(ssize_t) y,bpp,exception); \
cristy3ed852e2009-09-05 21:47:34 +0000548 x=0; \
549 y++; \
550 } \
551}
552/* WPG2 raster reader. */
cristyc82a27b2011-10-21 01:07:16 +0000553static int UnpackWPG2Raster(Image *image,int bpp,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000554{
cristy8418c7e2014-05-18 18:38:26 +0000555 int
556 RunCount,
557 XorMe = 0;
558
cristy6a1c5a92011-04-28 01:57:04 +0000559 size_t
560 x,
561 y;
562
563 ssize_t
cristyf2a82ee2014-05-26 17:49:54 +0000564 i,
cristy6a1c5a92011-04-28 01:57:04 +0000565 ldblk;
566
cristy3ed852e2009-09-05 21:47:34 +0000567 unsigned int
568 SampleSize=1;
569
570 unsigned char
571 bbuf,
572 *BImgBuff,
cristy8a1e4af2014-01-15 21:46:52 +0000573 SampleBuffer[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
cristy3ed852e2009-09-05 21:47:34 +0000574
cristy3ed852e2009-09-05 21:47:34 +0000575 x=0;
576 y=0;
cristybb503372010-05-27 20:51:26 +0000577 ldblk=(ssize_t) ((bpp*image->columns+7)/8);
cristy3ed852e2009-09-05 21:47:34 +0000578 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t) ldblk,
579 sizeof(*BImgBuff));
580 if(BImgBuff==NULL)
581 return(-2);
582
583 while( y< image->rows)
584 {
585 bbuf=ReadBlobByte(image);
586
587 switch(bbuf)
588 {
589 case 0x7D:
590 SampleSize=ReadBlobByte(image); /* DSZ */
591 if(SampleSize>8)
592 return(-2);
593 if(SampleSize<1)
594 return(-2);
595 break;
596 case 0x7E:
cristy1e604812011-05-19 18:07:50 +0000597 (void) FormatLocaleFile(stderr,
598 "\nUnsupported WPG token XOR, please report!");
599 XorMe=!XorMe;
cristy3ed852e2009-09-05 21:47:34 +0000600 break;
601 case 0x7F:
602 RunCount=ReadBlobByte(image); /* BLK */
cristy1d4a6952015-03-24 00:42:52 +0000603 if (RunCount < 0)
cristy6e394042015-03-24 15:59:17 +0000604 break;
cristy3ed852e2009-09-05 21:47:34 +0000605 for(i=0; i < SampleSize*(RunCount+1); i++)
606 {
607 InsertByte6(0);
608 }
609 break;
610 case 0xFD:
cristy1e604812011-05-19 18:07:50 +0000611 RunCount=ReadBlobByte(image); /* EXT */
cristy1d4a6952015-03-24 00:42:52 +0000612 if (RunCount < 0)
cristy6e394042015-03-24 15:59:17 +0000613 break;
cristy1e604812011-05-19 18:07:50 +0000614 for(i=0; i<= RunCount;i++)
cristy3ed852e2009-09-05 21:47:34 +0000615 for(bbuf=0; bbuf < SampleSize; bbuf++)
616 InsertByte6(SampleBuffer[bbuf]);
617 break;
618 case 0xFE:
619 RunCount=ReadBlobByte(image); /* RST */
cristy1d4a6952015-03-24 00:42:52 +0000620 if (RunCount < 0)
cristy6e394042015-03-24 15:59:17 +0000621 break;
cristy3ed852e2009-09-05 21:47:34 +0000622 if(x!=0)
623 {
cristyb51dff52011-05-19 16:55:47 +0000624 (void) FormatLocaleFile(stderr,
cristy1e604812011-05-19 18:07:50 +0000625 "\nUnsupported WPG2 unaligned token RST x=%.20g, please report!\n"
626 ,(double) x);
cristy3ed852e2009-09-05 21:47:34 +0000627 return(-3);
628 }
629 {
630 /* duplicate the previous row RunCount x */
631 for(i=0;i<=RunCount;i++)
632 {
cristyc82a27b2011-10-21 01:07:16 +0000633 InsertRow(image,BImgBuff,(ssize_t) (image->rows >= y ? y : image->rows-1),
634 bpp,exception);
cristy3ed852e2009-09-05 21:47:34 +0000635 y++;
636 }
637 }
638 break;
639 case 0xFF:
640 RunCount=ReadBlobByte(image); /* WHT */
cristy1d4a6952015-03-24 00:42:52 +0000641 if (RunCount < 0)
cristy6e394042015-03-24 15:59:17 +0000642 break;
cristy3ed852e2009-09-05 21:47:34 +0000643 for(i=0; i < SampleSize*(RunCount+1); i++)
644 {
645 InsertByte6(0xFF);
646 }
647 break;
648 default:
649 RunCount=bbuf & 0x7F;
650
651 if(bbuf & 0x80) /* REP */
652 {
653 for(i=0; i < SampleSize; i++)
654 SampleBuffer[i]=ReadBlobByte(image);
655 for(i=0;i<=RunCount;i++)
656 for(bbuf=0;bbuf<SampleSize;bbuf++)
657 InsertByte6(SampleBuffer[bbuf]);
658 }
659 else { /* NRP */
660 for(i=0; i< SampleSize*(RunCount+1);i++)
661 {
662 bbuf=ReadBlobByte(image);
663 InsertByte6(bbuf);
664 }
665 }
666 }
667 }
668 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);
669 return(0);
670}
671
672
673typedef float tCTM[3][3];
674
675static unsigned LoadWPG2Flags(Image *image,char Precision,float *Angle,tCTM *CTM)
676{
677const unsigned char TPR=1,TRN=2,SKW=4,SCL=8,ROT=0x10,OID=0x20,LCK=0x80;
cristybb503372010-05-27 20:51:26 +0000678ssize_t x;
cristy3ed852e2009-09-05 21:47:34 +0000679unsigned DenX;
680unsigned Flags;
681
682 (void) memset(*CTM,0,sizeof(*CTM)); /*CTM.erase();CTM.resize(3,3);*/
683 (*CTM)[0][0]=1;
684 (*CTM)[1][1]=1;
685 (*CTM)[2][2]=1;
686
687 Flags=ReadBlobLSBShort(image);
cristy657749b2015-06-20 14:59:02 +0000688 if(Flags & LCK) (void) ReadBlobLSBLong(image); /*Edit lock*/
cristy3ed852e2009-09-05 21:47:34 +0000689 if(Flags & OID)
690 {
691 if(Precision==0)
cristy657749b2015-06-20 14:59:02 +0000692 {(void) ReadBlobLSBShort(image);} /*ObjectID*/
cristy3ed852e2009-09-05 21:47:34 +0000693 else
cristy657749b2015-06-20 14:59:02 +0000694 {(void) ReadBlobLSBLong(image);} /*ObjectID (Double precision)*/
cristy3ed852e2009-09-05 21:47:34 +0000695 }
696 if(Flags & ROT)
697 {
698 x=ReadBlobLSBLong(image); /*Rot Angle*/
699 if(Angle) *Angle=x/65536.0;
700 }
701 if(Flags & (ROT|SCL))
702 {
703 x=ReadBlobLSBLong(image); /*Sx*cos()*/
704 (*CTM)[0][0] = (float)x/0x10000;
705 x=ReadBlobLSBLong(image); /*Sy*cos()*/
706 (*CTM)[1][1] = (float)x/0x10000;
707 }
708 if(Flags & (ROT|SKW))
709 {
710 x=ReadBlobLSBLong(image); /*Kx*sin()*/
711 (*CTM)[1][0] = (float)x/0x10000;
712 x=ReadBlobLSBLong(image); /*Ky*sin()*/
713 (*CTM)[0][1] = (float)x/0x10000;
714 }
715 if(Flags & TRN)
716 {
717 x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Tx*/
718 if(x>=0) (*CTM)[0][2] = (float)x+(float)DenX/0x10000;
719 else (*CTM)[0][2] = (float)x-(float)DenX/0x10000;
720 x=ReadBlobLSBLong(image); DenX=ReadBlobLSBShort(image); /*Ty*/
721 (*CTM)[1][2]=(float)x + ((x>=0)?1:-1)*(float)DenX/0x10000;
722 if(x>=0) (*CTM)[1][2] = (float)x+(float)DenX/0x10000;
723 else (*CTM)[1][2] = (float)x-(float)DenX/0x10000;
724 }
725 if(Flags & TPR)
726 {
727 x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Px*/
728 (*CTM)[2][0] = x + (float)DenX/0x10000;;
729 x=ReadBlobLSBShort(image); DenX=ReadBlobLSBShort(image); /*Py*/
730 (*CTM)[2][1] = x + (float)DenX/0x10000;
731 }
732 return(Flags);
733}
734
735
736static Image *ExtractPostscript(Image *image,const ImageInfo *image_info,
cristybb503372010-05-27 20:51:26 +0000737 MagickOffsetType PS_Offset,ssize_t PS_Size,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000738{
739 char
cristy151b66d2015-04-15 10:50:31 +0000740 postscript_file[MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000741
742 const MagicInfo
743 *magic_info;
744
745 FILE
746 *ps_file;
747
748 ImageInfo
749 *clone_info;
750
751 Image
752 *image2;
753
754 unsigned char
cristy151b66d2015-04-15 10:50:31 +0000755 magick[2*MagickPathExtent];
cristy3ed852e2009-09-05 21:47:34 +0000756
757
758 if ((clone_info=CloneImageInfo(image_info)) == NULL)
759 return(image);
760 clone_info->blob=(void *) NULL;
761 clone_info->length=0;
762
763 /* Obtain temporary file */
cristy4d0ca342014-05-01 00:42:09 +0000764 (void) AcquireUniqueFilename(postscript_file);
cristy18c6c272011-09-23 14:40:37 +0000765 ps_file=fopen_utf8(postscript_file,"wb");
cristy3ed852e2009-09-05 21:47:34 +0000766 if (ps_file == (FILE *) NULL)
767 goto FINISH;
768
769 /* Copy postscript to temporary file */
770 (void) SeekBlob(image,PS_Offset,SEEK_SET);
cristy151b66d2015-04-15 10:50:31 +0000771 (void) ReadBlob(image, 2*MagickPathExtent, magick);
cristy3ed852e2009-09-05 21:47:34 +0000772
773 (void) SeekBlob(image,PS_Offset,SEEK_SET);
774 while(PS_Size-- > 0)
775 {
776 (void) fputc(ReadBlobByte(image),ps_file);
777 }
778 (void) fclose(ps_file);
779
780 /* Detect file format - Check magic.mgk configuration file. */
cristy151b66d2015-04-15 10:50:31 +0000781 magic_info=GetMagicInfo(magick,2*MagickPathExtent,exception);
cristy3ed852e2009-09-05 21:47:34 +0000782 if(magic_info == (const MagicInfo *) NULL) goto FINISH_UNL;
783 /* printf("Detected:%s \n",magic_info->name); */
784 if(exception->severity != UndefinedException) goto FINISH_UNL;
785 if(magic_info->name == (char *) NULL) goto FINISH_UNL;
786
cristy151b66d2015-04-15 10:50:31 +0000787 (void) CopyMagickMemory(clone_info->magick,magic_info->name,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000788
789 /* Read nested image */
cristy53a8bc92011-01-10 19:15:17 +0000790 /*FormatString(clone_info->filename,"%s:%s",magic_info->name,postscript_file);*/
cristy151b66d2015-04-15 10:50:31 +0000791 FormatLocaleString(clone_info->filename,MagickPathExtent,"%s",postscript_file);
cristy3ed852e2009-09-05 21:47:34 +0000792 image2=ReadImage(clone_info,exception);
793
794 if (!image2)
795 goto FINISH_UNL;
796
797 /*
798 Replace current image with new image while copying base image
799 attributes.
800 */
cristy151b66d2015-04-15 10:50:31 +0000801 (void) CopyMagickMemory(image2->filename,image->filename,MagickPathExtent);
802 (void) CopyMagickMemory(image2->magick_filename,image->magick_filename,MagickPathExtent);
803 (void) CopyMagickMemory(image2->magick,image->magick,MagickPathExtent);
cristy3ed852e2009-09-05 21:47:34 +0000804 image2->depth=image->depth;
805 DestroyBlob(image2);
806 image2->blob=ReferenceBlob(image->blob);
807
808 if ((image->rows == 0) || (image->columns == 0))
809 DeleteImageFromList(&image);
810
811 AppendImageToList(&image,image2);
812
813 FINISH_UNL:
814 (void) RelinquishUniqueFileResource(postscript_file);
815 FINISH:
816 DestroyImageInfo(clone_info);
817 return(image);
818}
819
820/*
821%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
822% %
823% %
824% %
825% R e a d W P G I m a g e %
826% %
827% %
828% %
829%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
830%
831% Method ReadWPGImage reads an WPG X image file and returns it. It
832% allocates the memory necessary for the new Image structure and returns a
833% pointer to the new image.
834%
835% The format of the ReadWPGImage method is:
836%
837% Image *ReadWPGImage(const ImageInfo *image_info,ExceptionInfo *exception)
838%
839% A description of each parameter follows:
840%
841% o image: Method ReadWPGImage returns a pointer to the image after
842% reading. A null image is returned if there is a memory shortage or if
843% the image cannot be read.
844%
845% o image_info: Specifies a pointer to a ImageInfo structure.
846%
847% o exception: return any errors or warnings in this structure.
848%
849*/
850static Image *ReadWPGImage(const ImageInfo *image_info,
851 ExceptionInfo *exception)
852{
853 typedef struct
854 {
cristybb503372010-05-27 20:51:26 +0000855 size_t FileId;
cristy3ed852e2009-09-05 21:47:34 +0000856 MagickOffsetType DataOffset;
857 unsigned int ProductType;
858 unsigned int FileType;
859 unsigned char MajorVersion;
860 unsigned char MinorVersion;
861 unsigned int EncryptKey;
862 unsigned int Reserved;
863 } WPGHeader;
864
865 typedef struct
866 {
867 unsigned char RecType;
cristybb503372010-05-27 20:51:26 +0000868 size_t RecordLength;
cristy3ed852e2009-09-05 21:47:34 +0000869 } WPGRecord;
870
871 typedef struct
872 {
873 unsigned char Class;
874 unsigned char RecType;
cristybb503372010-05-27 20:51:26 +0000875 size_t Extension;
876 size_t RecordLength;
cristy3ed852e2009-09-05 21:47:34 +0000877 } WPG2Record;
878
879 typedef struct
880 {
881 unsigned HorizontalUnits;
882 unsigned VerticalUnits;
883 unsigned char PosSizePrecision;
884 } WPG2Start;
885
886 typedef struct
887 {
888 unsigned int Width;
cristy74f7d412014-11-29 00:47:24 +0000889 unsigned int Height;
cristy3ed852e2009-09-05 21:47:34 +0000890 unsigned int Depth;
891 unsigned int HorzRes;
892 unsigned int VertRes;
893 } WPGBitmapType1;
894
895 typedef struct
896 {
897 unsigned int Width;
cristy74f7d412014-11-29 00:47:24 +0000898 unsigned int Height;
cristy3ed852e2009-09-05 21:47:34 +0000899 unsigned char Depth;
900 unsigned char Compression;
901 } WPG2BitmapType1;
902
903 typedef struct
904 {
905 unsigned int RotAngle;
906 unsigned int LowLeftX;
907 unsigned int LowLeftY;
908 unsigned int UpRightX;
909 unsigned int UpRightY;
910 unsigned int Width;
cristy74f7d412014-11-29 00:47:24 +0000911 unsigned int Height;
cristy3ed852e2009-09-05 21:47:34 +0000912 unsigned int Depth;
913 unsigned int HorzRes;
914 unsigned int VertRes;
915 } WPGBitmapType2;
916
917 typedef struct
918 {
919 unsigned int StartIndex;
920 unsigned int NumOfEntries;
921 } WPGColorMapRec;
922
cristyb0de93f2013-05-03 13:39:25 +0000923 /*
cristy3ed852e2009-09-05 21:47:34 +0000924 typedef struct {
cristybb503372010-05-27 20:51:26 +0000925 size_t PS_unknown1;
cristy3ed852e2009-09-05 21:47:34 +0000926 unsigned int PS_unknown2;
927 unsigned int PS_unknown3;
928 } WPGPSl1Record;
cristyb0de93f2013-05-03 13:39:25 +0000929 */
cristy3ed852e2009-09-05 21:47:34 +0000930
931 Image
cristy74f7d412014-11-29 00:47:24 +0000932 *image;
cristy3ed852e2009-09-05 21:47:34 +0000933
934 unsigned int
935 status;
936
937 WPGHeader
938 Header;
939
940 WPGRecord
941 Rec;
942
943 WPG2Record
944 Rec2;
945
946 WPG2Start StartWPG;
947
948 WPGBitmapType1
949 BitmapHeader1;
950
951 WPG2BitmapType1
952 Bitmap2Header1;
953
954 WPGBitmapType2
955 BitmapHeader2;
956
957 WPGColorMapRec
958 WPG_Palette;
959
960 int
961 i,
962 bpp,
963 WPG2Flags;
964
cristybb503372010-05-27 20:51:26 +0000965 ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000966 ldblk;
967
cristyeaedf062010-05-29 22:36:02 +0000968 size_t
969 one;
970
cristy3ed852e2009-09-05 21:47:34 +0000971 unsigned char
972 *BImgBuff;
973
974 tCTM CTM; /*current transform matrix*/
975
976 /*
977 Open image file.
978 */
979 assert(image_info != (const ImageInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000980 assert(image_info->signature == MagickCoreSignature);
cristy3ed852e2009-09-05 21:47:34 +0000981 assert(exception != (ExceptionInfo *) NULL);
cristye1c94d92015-06-28 12:16:33 +0000982 assert(exception->signature == MagickCoreSignature);
cristyeaedf062010-05-29 22:36:02 +0000983 one=1;
cristy9950d572011-10-01 18:22:35 +0000984 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000985 image->depth=8;
986 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
987 if (status == MagickFalse)
988 {
989 image=DestroyImageList(image);
990 return((Image *) NULL);
991 }
992 /*
993 Read WPG image.
994 */
995 Header.FileId=ReadBlobLSBLong(image);
996 Header.DataOffset=(MagickOffsetType) ReadBlobLSBLong(image);
997 Header.ProductType=ReadBlobLSBShort(image);
998 Header.FileType=ReadBlobLSBShort(image);
999 Header.MajorVersion=ReadBlobByte(image);
1000 Header.MinorVersion=ReadBlobByte(image);
1001 Header.EncryptKey=ReadBlobLSBShort(image);
1002 Header.Reserved=ReadBlobLSBShort(image);
1003
1004 if (Header.FileId!=0x435057FF || (Header.ProductType>>8)!=0x16)
1005 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1006 if (Header.EncryptKey!=0)
1007 ThrowReaderException(CoderError,"EncryptedWPGImageFileNotSupported");
1008
1009 image->columns = 1;
1010 image->rows = 1;
1011 image->colors = 0;
1012 bpp=0;
1013 BitmapHeader2.RotAngle=0;
1014
1015 switch(Header.FileType)
1016 {
1017 case 1: /* WPG level 1 */
1018 while(!EOFBlob(image)) /* object parser loop */
1019 {
1020 (void) SeekBlob(image,Header.DataOffset,SEEK_SET);
1021 if(EOFBlob(image))
1022 break;
1023
1024 Rec.RecType=(i=ReadBlobByte(image));
1025 if(i==EOF)
1026 break;
1027 Rd_WP_DWORD(image,&Rec.RecordLength);
1028 if(EOFBlob(image))
1029 break;
1030
1031 Header.DataOffset=TellBlob(image)+Rec.RecordLength;
1032
1033 switch(Rec.RecType)
1034 {
1035 case 0x0B: /* bitmap type 1 */
1036 BitmapHeader1.Width=ReadBlobLSBShort(image);
cristy74f7d412014-11-29 00:47:24 +00001037 BitmapHeader1.Height=ReadBlobLSBShort(image);
1038 if ((BitmapHeader1.Width == 0) || (BitmapHeader1.Height == 0))
1039 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +00001040 BitmapHeader1.Depth=ReadBlobLSBShort(image);
1041 BitmapHeader1.HorzRes=ReadBlobLSBShort(image);
1042 BitmapHeader1.VertRes=ReadBlobLSBShort(image);
1043
1044 if(BitmapHeader1.HorzRes && BitmapHeader1.VertRes)
1045 {
1046 image->units=PixelsPerCentimeterResolution;
cristy2a11bef2011-10-28 18:33:11 +00001047 image->resolution.x=BitmapHeader1.HorzRes/470.0;
1048 image->resolution.y=BitmapHeader1.VertRes/470.0;
cristy3ed852e2009-09-05 21:47:34 +00001049 }
1050 image->columns=BitmapHeader1.Width;
cristy74f7d412014-11-29 00:47:24 +00001051 image->rows=BitmapHeader1.Height;
cristy3ed852e2009-09-05 21:47:34 +00001052 bpp=BitmapHeader1.Depth;
1053
1054 goto UnpackRaster;
1055
1056 case 0x0E: /*Color palette */
1057 WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1058 WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1059
1060 image->colors=WPG_Palette.NumOfEntries;
cristy018f07f2011-09-04 21:15:19 +00001061 if (!AcquireImageColormap(image,image->colors,exception))
cristy3ed852e2009-09-05 21:47:34 +00001062 goto NoMemory;
1063 for (i=WPG_Palette.StartIndex;
1064 i < (int)WPG_Palette.NumOfEntries; i++)
1065 {
1066 image->colormap[i].red=ScaleCharToQuantum((unsigned char)
1067 ReadBlobByte(image));
1068 image->colormap[i].green=ScaleCharToQuantum((unsigned char)
1069 ReadBlobByte(image));
1070 image->colormap[i].blue=ScaleCharToQuantum((unsigned char)
1071 ReadBlobByte(image));
1072 }
1073 break;
1074
1075 case 0x11: /* Start PS l1 */
1076 if(Rec.RecordLength > 8)
1077 image=ExtractPostscript(image,image_info,
1078 TellBlob(image)+8, /* skip PS header in the wpg */
cristybb503372010-05-27 20:51:26 +00001079 (ssize_t) Rec.RecordLength-8,exception);
cristy3ed852e2009-09-05 21:47:34 +00001080 break;
1081
1082 case 0x14: /* bitmap type 2 */
1083 BitmapHeader2.RotAngle=ReadBlobLSBShort(image);
1084 BitmapHeader2.LowLeftX=ReadBlobLSBShort(image);
1085 BitmapHeader2.LowLeftY=ReadBlobLSBShort(image);
1086 BitmapHeader2.UpRightX=ReadBlobLSBShort(image);
1087 BitmapHeader2.UpRightY=ReadBlobLSBShort(image);
1088 BitmapHeader2.Width=ReadBlobLSBShort(image);
cristy74f7d412014-11-29 00:47:24 +00001089 BitmapHeader2.Height=ReadBlobLSBShort(image);
1090 if ((BitmapHeader2.Width == 0) || (BitmapHeader2.Height == 0))
1091 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +00001092 BitmapHeader2.Depth=ReadBlobLSBShort(image);
1093 BitmapHeader2.HorzRes=ReadBlobLSBShort(image);
1094 BitmapHeader2.VertRes=ReadBlobLSBShort(image);
1095
1096 image->units=PixelsPerCentimeterResolution;
1097 image->page.width=(unsigned int)
1098 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightX)/470.0);
1099 image->page.height=(unsigned int)
1100 ((BitmapHeader2.LowLeftX-BitmapHeader2.UpRightY)/470.0);
1101 image->page.x=(int) (BitmapHeader2.LowLeftX/470.0);
1102 image->page.y=(int) (BitmapHeader2.LowLeftX/470.0);
1103 if(BitmapHeader2.HorzRes && BitmapHeader2.VertRes)
1104 {
cristy2a11bef2011-10-28 18:33:11 +00001105 image->resolution.x=BitmapHeader2.HorzRes/470.0;
1106 image->resolution.y=BitmapHeader2.VertRes/470.0;
cristy3ed852e2009-09-05 21:47:34 +00001107 }
1108 image->columns=BitmapHeader2.Width;
cristy74f7d412014-11-29 00:47:24 +00001109 image->rows=BitmapHeader2.Height;
cristy3ed852e2009-09-05 21:47:34 +00001110 bpp=BitmapHeader2.Depth;
1111
1112 UnpackRaster:
1113 if ((image->colors == 0) && (bpp != 24))
1114 {
cristyeaedf062010-05-29 22:36:02 +00001115 image->colors=one << bpp;
cristy018f07f2011-09-04 21:15:19 +00001116 if (!AcquireImageColormap(image,image->colors,exception))
cristy3ed852e2009-09-05 21:47:34 +00001117 {
1118 NoMemory:
1119 ThrowReaderException(ResourceLimitError,
1120 "MemoryAllocationFailed");
1121 }
1122 /* printf("Load default colormap \n"); */
1123 for (i=0; (i < (int) image->colors) && (i < 256); i++)
1124 {
1125 image->colormap[i].red=ScaleCharToQuantum(WPG1_Palette[i].Red);
1126 image->colormap[i].green=ScaleCharToQuantum(WPG1_Palette[i].Green);
1127 image->colormap[i].blue=ScaleCharToQuantum(WPG1_Palette[i].Blue);
1128 }
1129 }
1130 else
1131 {
1132 if (bpp < 24)
cristyeaedf062010-05-29 22:36:02 +00001133 if ( (image->colors < (one << bpp)) && (bpp != 24) )
cristy101ab702011-10-13 13:06:32 +00001134 image->colormap=(PixelInfo *) ResizeQuantumMemory(
cristyeaedf062010-05-29 22:36:02 +00001135 image->colormap,(size_t) (one << bpp),
cristy3ed852e2009-09-05 21:47:34 +00001136 sizeof(*image->colormap));
1137 }
1138
1139 if (bpp == 1)
1140 {
1141 if(image->colormap[0].red==0 &&
1142 image->colormap[0].green==0 &&
1143 image->colormap[0].blue==0 &&
1144 image->colormap[1].red==0 &&
1145 image->colormap[1].green==0 &&
1146 image->colormap[1].blue==0)
1147 { /* fix crippled monochrome palette */
1148 image->colormap[1].red =
1149 image->colormap[1].green =
1150 image->colormap[1].blue = QuantumRange;
1151 }
1152 }
1153
cristyc82a27b2011-10-21 01:07:16 +00001154 if(UnpackWPGRaster(image,bpp,exception) < 0)
cristy3ed852e2009-09-05 21:47:34 +00001155 /* The raster cannot be unpacked */
1156 {
1157 DecompressionFailed:
1158 ThrowReaderException(CoderError,"UnableToDecompressImage");
1159 }
1160
1161 if(Rec.RecType==0x14 && BitmapHeader2.RotAngle!=0 && !image_info->ping)
1162 {
1163 /* flop command */
1164 if(BitmapHeader2.RotAngle & 0x8000)
1165 {
cristy74f7d412014-11-29 00:47:24 +00001166 Image
1167 *flop_image;
1168
1169 flop_image = FlopImage(image, exception);
1170 if (flop_image != (Image *) NULL) {
1171 DuplicateBlob(flop_image,image);
1172 (void) RemoveLastImageFromList(&image);
1173 AppendImageToList(&image,flop_image);
1174 }
cristy3ed852e2009-09-05 21:47:34 +00001175 }
1176 /* flip command */
1177 if(BitmapHeader2.RotAngle & 0x2000)
1178 {
cristy74f7d412014-11-29 00:47:24 +00001179 Image
1180 *flip_image;
1181
1182 flip_image = FlipImage(image, exception);
1183 if (flip_image != (Image *) NULL) {
1184 DuplicateBlob(flip_image,image);
1185 (void) RemoveLastImageFromList(&image);
1186 AppendImageToList(&image,flip_image);
1187 }
cristy3ed852e2009-09-05 21:47:34 +00001188 }
1189
1190 /* rotate command */
1191 if(BitmapHeader2.RotAngle & 0x0FFF)
1192 {
cristy74f7d412014-11-29 00:47:24 +00001193 Image
1194 *rotate_image;
1195
1196 rotate_image=RotateImage(image,(BitmapHeader2.RotAngle &
1197 0x0FFF), exception);
1198 if (rotate_image != (Image *) NULL) {
1199 DuplicateBlob(rotate_image,image);
1200 (void) RemoveLastImageFromList(&image);
1201 AppendImageToList(&image,rotate_image);
1202 }
cristy3ed852e2009-09-05 21:47:34 +00001203 }
1204 }
1205
1206 /* Allocate next image structure. */
cristy9950d572011-10-01 18:22:35 +00001207 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001208 image->depth=8;
1209 if (image->next == (Image *) NULL)
1210 goto Finish;
1211 image=SyncNextImageInList(image);
1212 image->columns=image->rows=0;
1213 image->colors=0;
1214 break;
1215
1216 case 0x1B: /* Postscript l2 */
1217 if(Rec.RecordLength>0x3C)
1218 image=ExtractPostscript(image,image_info,
1219 TellBlob(image)+0x3C, /* skip PS l2 header in the wpg */
cristybb503372010-05-27 20:51:26 +00001220 (ssize_t) Rec.RecordLength-0x3C,exception);
cristy3ed852e2009-09-05 21:47:34 +00001221 break;
1222 }
1223 }
1224 break;
1225
1226 case 2: /* WPG level 2 */
1227 (void) memset(CTM,0,sizeof(CTM));
1228 StartWPG.PosSizePrecision = 0;
1229 while(!EOFBlob(image)) /* object parser loop */
1230 {
1231 (void) SeekBlob(image,Header.DataOffset,SEEK_SET);
1232 if(EOFBlob(image))
1233 break;
1234
1235 Rec2.Class=(i=ReadBlobByte(image));
1236 if(i==EOF)
1237 break;
1238 Rec2.RecType=(i=ReadBlobByte(image));
1239 if(i==EOF)
1240 break;
1241 Rd_WP_DWORD(image,&Rec2.Extension);
1242 Rd_WP_DWORD(image,&Rec2.RecordLength);
1243 if(EOFBlob(image))
1244 break;
1245
1246 Header.DataOffset=TellBlob(image)+Rec2.RecordLength;
1247
1248 switch(Rec2.RecType)
1249 {
1250 case 1:
1251 StartWPG.HorizontalUnits=ReadBlobLSBShort(image);
1252 StartWPG.VerticalUnits=ReadBlobLSBShort(image);
1253 StartWPG.PosSizePrecision=ReadBlobByte(image);
1254 break;
1255 case 0x0C: /* Color palette */
1256 WPG_Palette.StartIndex=ReadBlobLSBShort(image);
1257 WPG_Palette.NumOfEntries=ReadBlobLSBShort(image);
1258
1259 image->colors=WPG_Palette.NumOfEntries;
cristy018f07f2011-09-04 21:15:19 +00001260 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +00001261 ThrowReaderException(ResourceLimitError,
1262 "MemoryAllocationFailed");
1263 for (i=WPG_Palette.StartIndex;
1264 i < (int)WPG_Palette.NumOfEntries; i++)
1265 {
1266 image->colormap[i].red=ScaleCharToQuantum((char)
1267 ReadBlobByte(image));
1268 image->colormap[i].green=ScaleCharToQuantum((char)
1269 ReadBlobByte(image));
1270 image->colormap[i].blue=ScaleCharToQuantum((char)
1271 ReadBlobByte(image));
1272 (void) ReadBlobByte(image); /*Opacity??*/
1273 }
1274 break;
1275 case 0x0E:
1276 Bitmap2Header1.Width=ReadBlobLSBShort(image);
cristy74f7d412014-11-29 00:47:24 +00001277 Bitmap2Header1.Height=ReadBlobLSBShort(image);
1278 if ((Bitmap2Header1.Width == 0) || (Bitmap2Header1.Height == 0))
1279 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
cristy3ed852e2009-09-05 21:47:34 +00001280 Bitmap2Header1.Depth=ReadBlobByte(image);
1281 Bitmap2Header1.Compression=ReadBlobByte(image);
1282
1283 if(Bitmap2Header1.Compression > 1)
1284 continue; /*Unknown compression method */
1285 switch(Bitmap2Header1.Depth)
1286 {
1287 case 1:
1288 bpp=1;
1289 break;
1290 case 2:
1291 bpp=2;
1292 break;
1293 case 3:
1294 bpp=4;
1295 break;
1296 case 4:
1297 bpp=8;
1298 break;
1299 case 8:
1300 bpp=24;
1301 break;
1302 default:
1303 continue; /*Ignore raster with unknown depth*/
1304 }
1305 image->columns=Bitmap2Header1.Width;
cristy74f7d412014-11-29 00:47:24 +00001306 image->rows=Bitmap2Header1.Height;
cristy3ed852e2009-09-05 21:47:34 +00001307
1308 if ((image->colors == 0) && (bpp != 24))
1309 {
cristy0b29b252010-05-30 01:59:46 +00001310 size_t
1311 one;
1312
1313 one=1;
1314 image->colors=one << bpp;
cristy018f07f2011-09-04 21:15:19 +00001315 if (!AcquireImageColormap(image,image->colors,exception))
cristy3ed852e2009-09-05 21:47:34 +00001316 goto NoMemory;
1317 }
1318 else
1319 {
1320 if(bpp < 24)
cristyeaedf062010-05-29 22:36:02 +00001321 if( image->colors<(one << bpp) && bpp!=24 )
cristy101ab702011-10-13 13:06:32 +00001322 image->colormap=(PixelInfo *) ResizeQuantumMemory(
cristyeaedf062010-05-29 22:36:02 +00001323 image->colormap,(size_t) (one << bpp),
cristy3ed852e2009-09-05 21:47:34 +00001324 sizeof(*image->colormap));
1325 }
1326
1327
1328 switch(Bitmap2Header1.Compression)
1329 {
1330 case 0: /*Uncompressed raster*/
1331 {
cristybb503372010-05-27 20:51:26 +00001332 ldblk=(ssize_t) ((bpp*image->columns+7)/8);
cristy3ed852e2009-09-05 21:47:34 +00001333 BImgBuff=(unsigned char *) AcquireQuantumMemory((size_t)
1334 ldblk,sizeof(*BImgBuff));
1335 if (BImgBuff == (unsigned char *) NULL)
1336 goto NoMemory;
1337
cristybb503372010-05-27 20:51:26 +00001338 for(i=0; i< (ssize_t) image->rows; i++)
cristy3ed852e2009-09-05 21:47:34 +00001339 {
1340 (void) ReadBlob(image,ldblk,BImgBuff);
cristyc82a27b2011-10-21 01:07:16 +00001341 InsertRow(image,BImgBuff,i,bpp,exception);
cristy3ed852e2009-09-05 21:47:34 +00001342 }
1343
1344 if(BImgBuff)
1345 BImgBuff=(unsigned char *) RelinquishMagickMemory(BImgBuff);;
1346 break;
1347 }
1348 case 1: /*RLE for WPG2 */
1349 {
cristyc82a27b2011-10-21 01:07:16 +00001350 if( UnpackWPG2Raster(image,bpp,exception) < 0)
cristy3ed852e2009-09-05 21:47:34 +00001351 goto DecompressionFailed;
1352 break;
1353 }
1354 }
1355
1356 if(CTM[0][0]<0 && !image_info->ping)
cristy74f7d412014-11-29 00:47:24 +00001357 { /*?? RotAngle=360-RotAngle;*/
1358 Image
1359 *flop_image;
1360
1361 flop_image = FlopImage(image, exception);
1362 if (flop_image != (Image *) NULL) {
1363 DuplicateBlob(flop_image,image);
1364 (void) RemoveLastImageFromList(&image);
1365 AppendImageToList(&image,flop_image);
1366 }
cristy3ed852e2009-09-05 21:47:34 +00001367 /* Try to change CTM according to Flip - I am not sure, must be checked.
1368 Tx(0,0)=-1; Tx(1,0)=0; Tx(2,0)=0;
1369 Tx(0,1)= 0; Tx(1,1)=1; Tx(2,1)=0;
1370 Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
1371 Tx(1,2)=0; Tx(2,2)=1; */
1372 }
1373 if(CTM[1][1]<0 && !image_info->ping)
cristy74f7d412014-11-29 00:47:24 +00001374 { /*?? RotAngle=360-RotAngle;*/
1375 Image
1376 *flip_image;
1377
1378 flip_image = FlipImage(image, exception);
1379 if (flip_image != (Image *) NULL) {
1380 DuplicateBlob(flip_image,image);
1381 (void) RemoveLastImageFromList(&image);
1382 AppendImageToList(&image,flip_image);
1383 }
cristy3ed852e2009-09-05 21:47:34 +00001384 /* Try to change CTM according to Flip - I am not sure, must be checked.
1385 float_matrix Tx(3,3);
1386 Tx(0,0)= 1; Tx(1,0)= 0; Tx(2,0)=0;
1387 Tx(0,1)= 0; Tx(1,1)=-1; Tx(2,1)=0;
1388 Tx(0,2)= 0; Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
1389 Tx(2,2)=1; */
cristy74f7d412014-11-29 00:47:24 +00001390 }
cristy3ed852e2009-09-05 21:47:34 +00001391
1392
1393 /* Allocate next image structure. */
cristy9950d572011-10-01 18:22:35 +00001394 AcquireNextImage(image_info,image,exception);
cristy3ed852e2009-09-05 21:47:34 +00001395 image->depth=8;
1396 if (image->next == (Image *) NULL)
1397 goto Finish;
1398 image=SyncNextImageInList(image);
1399 image->columns=image->rows=1;
1400 image->colors=0;
1401 break;
1402
1403 case 0x12: /* Postscript WPG2*/
1404 i=ReadBlobLSBShort(image);
1405 if(Rec2.RecordLength > (unsigned int) i)
1406 image=ExtractPostscript(image,image_info,
1407 TellBlob(image)+i, /*skip PS header in the wpg2*/
cristybb503372010-05-27 20:51:26 +00001408 (ssize_t) (Rec2.RecordLength-i-2),exception);
cristy3ed852e2009-09-05 21:47:34 +00001409 break;
1410
1411 case 0x1B: /*bitmap rectangle*/
1412 WPG2Flags = LoadWPG2Flags(image,StartWPG.PosSizePrecision,NULL,&CTM);
cristyda16f162011-02-19 23:52:17 +00001413 (void) WPG2Flags;
cristy3ed852e2009-09-05 21:47:34 +00001414 break;
1415 }
1416 }
1417
1418 break;
1419
1420 default:
1421 {
1422 ThrowReaderException(CoderError,"DataEncodingSchemeIsNotSupported");
1423 }
1424 }
cristyacabb842014-12-14 23:36:33 +00001425 status=SetImageExtent(image,image->columns,image->rows,exception);
1426 if (status == MagickFalse)
1427 return(DestroyImageList(image));
cristy3ed852e2009-09-05 21:47:34 +00001428
1429 Finish:
1430 (void) CloseBlob(image);
1431
1432 {
1433 Image
1434 *p;
1435
cristybb503372010-05-27 20:51:26 +00001436 ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001437 scene=0;
1438
1439 /*
1440 Rewind list, removing any empty images while rewinding.
1441 */
1442 p=image;
1443 image=NULL;
1444 while (p != (Image *) NULL)
1445 {
1446 Image *tmp=p;
1447 if ((p->rows == 0) || (p->columns == 0)) {
1448 p=p->previous;
1449 DeleteImageFromList(&tmp);
1450 } else {
1451 image=p;
1452 p=p->previous;
1453 }
1454 }
1455 /*
1456 Fix scene numbers.
1457 */
1458 for (p=image; p != (Image *) NULL; p=p->next)
cristybb503372010-05-27 20:51:26 +00001459 p->scene=(size_t) scene++;
cristy3ed852e2009-09-05 21:47:34 +00001460 }
1461 if (image == (Image *) NULL)
1462 ThrowReaderException(CorruptImageError,
1463 "ImageFileDoesNotContainAnyImageData");
1464 return(image);
1465}
1466
1467/*
1468%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1469% %
1470% %
1471% %
1472% R e g i s t e r W P G I m a g e %
1473% %
1474% %
1475% %
1476%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1477%
1478% Method RegisterWPGImage adds attributes for the WPG image format to
1479% the list of supported formats. The attributes include the image format
1480% tag, a method to read and/or write the format, whether the format
1481% supports the saving of more than one frame to the same file or blob,
1482% whether the format supports native in-memory I/O, and a brief
1483% description of the format.
1484%
1485% The format of the RegisterWPGImage method is:
1486%
cristybb503372010-05-27 20:51:26 +00001487% size_t RegisterWPGImage(void)
cristy3ed852e2009-09-05 21:47:34 +00001488%
1489*/
cristybb503372010-05-27 20:51:26 +00001490ModuleExport size_t RegisterWPGImage(void)
cristy3ed852e2009-09-05 21:47:34 +00001491{
1492 MagickInfo
1493 *entry;
1494
dirk06b627a2015-04-06 18:59:17 +00001495 entry=AcquireMagickInfo("WPG","WPG","Word Perfect Graphics");
cristy3ed852e2009-09-05 21:47:34 +00001496 entry->decoder=(DecodeImageHandler *) ReadWPGImage;
1497 entry->magick=(IsImageFormatHandler *) IsWPG;
dirk08e9a112015-02-22 01:51:41 +00001498 entry->flags|=CoderSeekableStreamFlag;
cristy3ed852e2009-09-05 21:47:34 +00001499 (void) RegisterMagickInfo(entry);
1500 return(MagickImageCoderSignature);
1501}
1502
1503/*
1504%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1505% %
1506% %
1507% %
1508% U n r e g i s t e r W P G I m a g e %
1509% %
1510% %
1511% %
1512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1513%
1514% Method UnregisterWPGImage removes format registrations made by the
1515% WPG module from the list of supported formats.
1516%
1517% The format of the UnregisterWPGImage method is:
1518%
1519% UnregisterWPGImage(void)
1520%
1521*/
1522ModuleExport void UnregisterWPGImage(void)
1523{
1524 (void) UnregisterMagickInfo("WPG");
1525}