/src/graphicsmagick/coders/cut.c
Line | Count | Source |
1 | | /* |
2 | | % Copyright (C) 2003-2025 GraphicsMagick Group |
3 | | % Copyright (C) 2002 ImageMagick Studio |
4 | | % |
5 | | % This program is covered by multiple licenses, which are described in |
6 | | % Copyright.txt. You should have received a copy of Copyright.txt with this |
7 | | % package; otherwise see http://www.graphicsmagick.org/www/Copyright.html. |
8 | | % |
9 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
10 | | % % |
11 | | % % |
12 | | % CCC U U TTTTT % |
13 | | % C U U T % |
14 | | % C U U T % |
15 | | % C U U T % |
16 | | % CCC UUU T % |
17 | | % % |
18 | | % % |
19 | | % Read DR Halo Image Format. % |
20 | | % % |
21 | | % % |
22 | | % Software Design % |
23 | | % Jaroslav Fojtik % |
24 | | % June 2000 - 2007 % |
25 | | % % |
26 | | % % |
27 | | % % |
28 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
29 | | % |
30 | | % |
31 | | */ |
32 | | |
33 | | /* |
34 | | Include declarations. |
35 | | */ |
36 | | #include "magick/studio.h" |
37 | | #include "magick/analyze.h" |
38 | | #include "magick/blob.h" |
39 | | #include "magick/color.h" |
40 | | #include "magick/colormap.h" |
41 | | #include "magick/magick.h" |
42 | | #include "magick/pixel_cache.h" |
43 | | #include "magick/utility.h" |
44 | | #include "magick/static.h" |
45 | | |
46 | | typedef struct |
47 | | { |
48 | | unsigned Width; |
49 | | unsigned Height; |
50 | | unsigned Reserved; |
51 | | }CUTHeader; /*Dr Halo*/ |
52 | | typedef struct |
53 | | { |
54 | | char FileId[2]; |
55 | | unsigned Version; |
56 | | unsigned Size; |
57 | | char FileType; |
58 | | char SubType; |
59 | | unsigned BoardID; |
60 | | unsigned GraphicsMode; |
61 | | unsigned MaxIndex; |
62 | | unsigned MaxRed; |
63 | | unsigned MaxGreen; |
64 | | unsigned MaxBlue; |
65 | | char PaletteId[20]; |
66 | | }CUTPalHeader; |
67 | | |
68 | | |
69 | | static void InsertRow(unsigned char *p,long y,Image *image) |
70 | 89.5k | { |
71 | 89.5k | int bit; long x; |
72 | 89.5k | register PixelPacket *q; |
73 | 89.5k | IndexPacket index; |
74 | 89.5k | register IndexPacket *indexes; |
75 | | |
76 | | |
77 | 89.5k | switch (image->depth) |
78 | 89.5k | { |
79 | 6.51k | case 1: /* Convert bitmap scanline. */ |
80 | 6.51k | { |
81 | 6.51k | q=SetImagePixels(image,0,y,image->columns,1); |
82 | 6.51k | if (q == (PixelPacket *) NULL) |
83 | 0 | break; |
84 | 6.51k | indexes=AccessMutableIndexes(image); |
85 | 173k | for (x=0; x < ((long) image->columns-7); x+=8) |
86 | 166k | { |
87 | 1.49M | for (bit=0; bit < 8; bit++) |
88 | 1.33M | { |
89 | 1.33M | index=((*p) & (0x80U >> bit) ? 0x01U : 0x00U); |
90 | 1.33M | indexes[x+bit]=index; |
91 | 1.33M | *q++=image->colormap[index]; |
92 | 1.33M | } |
93 | 166k | p++; |
94 | 166k | } |
95 | 6.51k | if ((image->columns % 8) != 0) |
96 | 0 | { |
97 | 0 | for (bit=0; bit < (long) (image->columns % 8); bit++) |
98 | 0 | { |
99 | 0 | index=((*p) & (0x80 >> bit) ? 0x01U : 0x00U); |
100 | 0 | indexes[x+bit]=index; |
101 | 0 | *q++=image->colormap[index]; |
102 | 0 | } |
103 | 0 | p++; |
104 | 0 | } |
105 | 6.51k | if (!SyncImagePixels(image)) |
106 | 0 | break; |
107 | | /* if (image->previous == (Image *) NULL) |
108 | | if (QuantumTick(y,image->rows)) |
109 | | ProgressMonitor(LoadImageText,image->rows-y-1,image->rows);*/ |
110 | 6.51k | break; |
111 | 6.51k | } |
112 | 6.51k | case 2: /* Convert PseudoColor scanline. */ |
113 | 0 | { |
114 | 0 | q=SetImagePixels(image,0,y,image->columns,1); |
115 | 0 | if (q == (PixelPacket *) NULL) |
116 | 0 | break; |
117 | 0 | indexes=AccessMutableIndexes(image); |
118 | 0 | for (x=0; x < ((long) image->columns-1); x+=2) |
119 | 0 | { |
120 | 0 | index=(IndexPacket) ((*p >> 6U) & 0x3U); |
121 | 0 | VerifyColormapIndex(image,index); |
122 | 0 | indexes[x]=index; |
123 | 0 | *q++=image->colormap[index]; |
124 | 0 | index=(IndexPacket) ((*p >> 4U) & 0x3U); |
125 | 0 | VerifyColormapIndex(image,index); |
126 | 0 | indexes[x]=index; |
127 | 0 | *q++=image->colormap[index]; |
128 | 0 | index=(IndexPacket) ((*p >> 2U) & 0x3U); |
129 | 0 | VerifyColormapIndex(image,index); |
130 | 0 | indexes[x]=index; |
131 | 0 | *q++=image->colormap[index]; |
132 | 0 | index=(IndexPacket) ((*p) & 0x3U); |
133 | 0 | VerifyColormapIndex(image,index); |
134 | 0 | indexes[x+1]=index; |
135 | 0 | *q++=image->colormap[index]; |
136 | 0 | p++; |
137 | 0 | } |
138 | 0 | if ((image->columns % 4) != 0) |
139 | 0 | { |
140 | 0 | index=(IndexPacket) ((*p >> 6U) & 0x3U); |
141 | 0 | VerifyColormapIndex(image,index); |
142 | 0 | indexes[x]=index; |
143 | 0 | *q++=image->colormap[index]; |
144 | 0 | if ((image->columns % 4) >= 1) |
145 | | |
146 | 0 | { |
147 | 0 | index=(IndexPacket) ((*p >> 4U) & 0x3U); |
148 | 0 | VerifyColormapIndex(image,index); |
149 | 0 | indexes[x]=index; |
150 | 0 | *q++=image->colormap[index]; |
151 | 0 | if ((image->columns % 4) >= 2U) |
152 | | |
153 | 0 | { |
154 | 0 | index=(IndexPacket) ((*p >> 2U) & 0x3U); |
155 | 0 | VerifyColormapIndex(image,index); |
156 | 0 | indexes[x]=index; |
157 | 0 | *q++=image->colormap[index]; |
158 | 0 | } |
159 | 0 | } |
160 | 0 | p++; |
161 | 0 | } |
162 | 0 | if (!SyncImagePixels(image)) |
163 | 0 | break; |
164 | | /* if (image->previous == (Image *) NULL) |
165 | | if (QuantumTick(y,image->rows)) |
166 | | ProgressMonitor(LoadImageText,image->rows-y-1,image->rows);*/ |
167 | 0 | break; |
168 | 0 | } |
169 | | |
170 | 33.5k | case 4: /* Convert PseudoColor scanline. */ |
171 | 33.5k | { |
172 | 33.5k | q=SetImagePixels(image,0,y,image->columns,1); |
173 | 33.5k | if (q == (PixelPacket *) NULL) |
174 | 0 | break; |
175 | 33.5k | indexes=AccessMutableIndexes(image); |
176 | 11.1M | for (x=0; x < ((long) image->columns-1); x+=2) |
177 | 11.1M | { |
178 | 11.1M | index=(IndexPacket) ((*p >> 4U) & 0xfU); |
179 | 11.1M | VerifyColormapIndex(image,index); |
180 | 11.1M | indexes[x]=index; |
181 | 11.1M | *q++=image->colormap[index]; |
182 | 11.1M | index=(IndexPacket) ((*p) & 0xfU); |
183 | 11.1M | VerifyColormapIndex(image,index); |
184 | 11.1M | indexes[x+1]=index; |
185 | 11.1M | *q++=image->colormap[index]; |
186 | 11.1M | p++; |
187 | 11.1M | } |
188 | 33.5k | if ((image->columns % 2) != 0) |
189 | 0 | { |
190 | 0 | index=(IndexPacket) ((*p >> 4U) & 0xfU); |
191 | 0 | VerifyColormapIndex(image,index); |
192 | 0 | indexes[x]=index; |
193 | 0 | *q++=image->colormap[index]; |
194 | 0 | p++; |
195 | 0 | } |
196 | 33.5k | if (!SyncImagePixels(image)) |
197 | 0 | break; |
198 | | /* if (image->previous == (Image *) NULL) |
199 | | if (QuantumTick(y,image->rows)) |
200 | | ProgressMonitor(LoadImageText,image->rows-y-1,image->rows);*/ |
201 | 33.5k | break; |
202 | 33.5k | } |
203 | 49.3k | case 8: /* Convert PseudoColor scanline. */ |
204 | 49.3k | { |
205 | 49.3k | q=SetImagePixels(image,0,y,image->columns,1); |
206 | 49.3k | if (q == (PixelPacket *) NULL) break; |
207 | 49.3k | indexes=AccessMutableIndexes(image); |
208 | | |
209 | 53.9M | for (x=0; x < (long) image->columns; x++) |
210 | 53.9M | { |
211 | 53.9M | index=(IndexPacket) (*p); |
212 | 53.9M | VerifyColormapIndex(image,index); |
213 | 53.9M | indexes[x]=index; |
214 | 53.9M | *q++=image->colormap[index]; |
215 | 53.9M | p++; |
216 | 53.9M | } |
217 | 49.3k | if (!SyncImagePixels(image)) |
218 | 0 | break; |
219 | | /* if (image->previous == (Image *) NULL) |
220 | | if (QuantumTick(y,image->rows)) |
221 | | ProgressMonitor(LoadImageText,image->rows-y-1,image->rows);*/ |
222 | 49.3k | } |
223 | 49.3k | break; |
224 | | |
225 | 89.5k | } |
226 | 89.5k | } |
227 | | |
228 | | static unsigned int GetCutColors(Image *image) |
229 | 76 | { |
230 | 76 | unsigned long |
231 | 76 | x, |
232 | 76 | y; |
233 | | |
234 | 76 | PixelPacket |
235 | 76 | *q; |
236 | | |
237 | 76 | Quantum |
238 | 76 | MaxColor, |
239 | 76 | ScaleCharToQuantum16; |
240 | | |
241 | | /* Compute the number of colors in Grayed R[i]=G[i]=B[i] image */ |
242 | 76 | ScaleCharToQuantum16=ScaleCharToQuantum(16U); |
243 | 76 | MaxColor=0U; |
244 | 12.0k | for (y=0; y < image->rows; y++) |
245 | 11.9k | { |
246 | | |
247 | 11.9k | q=SetImagePixels(image,0,y,image->columns,1); |
248 | 11.9k | if (q == (PixelPacket *) NULL) |
249 | 0 | break; |
250 | 2.21M | for (x=image->columns; x != 0; x--) |
251 | 2.19M | { |
252 | 2.19M | if (MaxColor < q->red) |
253 | 88 | MaxColor=q->red; |
254 | 2.19M | if (MaxColor >= ScaleCharToQuantum16) |
255 | 10 | return(255U); |
256 | 2.19M | q++; |
257 | 2.19M | } |
258 | 11.9k | } |
259 | 66 | if (MaxColor < ScaleCharToQuantum(2)) |
260 | 49 | MaxColor=2U; |
261 | 17 | else if (MaxColor < ScaleCharToQuantum(16U)) |
262 | 17 | MaxColor=16U; |
263 | 66 | return (MaxColor); |
264 | 76 | } |
265 | | |
266 | | /* |
267 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
268 | | % % |
269 | | % % |
270 | | % % |
271 | | % R e a d C U T I m a g e % |
272 | | % % |
273 | | % % |
274 | | % % |
275 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
276 | | % |
277 | | % Method ReadCUTImage reads an CUT X image file and returns it. It |
278 | | % allocates the memory necessary for the new Image structure and returns a |
279 | | % pointer to the new image. |
280 | | % |
281 | | % The format of the ReadCUTImage method is: |
282 | | % |
283 | | % Image *ReadCUTImage(const ImageInfo *image_info,ExceptionInfo *exception) |
284 | | % |
285 | | % A description of each parameter follows: |
286 | | % |
287 | | % o image: Method ReadCUTImage returns a pointer to the image after |
288 | | % reading. A null image is returned if there is a memory shortage or if |
289 | | % the image cannot be read. |
290 | | % |
291 | | % o image_info: Specifies a pointer to a ImageInfo structure. |
292 | | % |
293 | | % o exception: return any errors or warnings in this structure. |
294 | | % |
295 | | % |
296 | | */ |
297 | 570 | #define ThrowCUTReaderException(code_,reason_,image_) \ |
298 | 570 | { \ |
299 | 570 | if (palette != (Image *) NULL) \ |
300 | 570 | DestroyImage(palette); \ |
301 | 570 | if (clone_info != (ImageInfo *) NULL) \ |
302 | 570 | DestroyImageInfo(clone_info); \ |
303 | 570 | ThrowReaderException(code_,reason_,image_); \ |
304 | 0 | } |
305 | | static Image *ReadCUTImage(const ImageInfo *image_info,ExceptionInfo *exception) |
306 | 639 | { |
307 | 639 | Image *image,*palette = (Image *) NULL; |
308 | 639 | ImageInfo *clone_info = (ImageInfo *) NULL; |
309 | 639 | unsigned int status; |
310 | 639 | unsigned long EncodedByte; |
311 | 639 | unsigned char RunCount,RunValue,RunCountMasked; |
312 | 639 | CUTHeader Header; |
313 | 639 | CUTPalHeader PalHeader; |
314 | 639 | long i,j; |
315 | 639 | long ldblk; |
316 | 639 | unsigned char *BImgBuff=NULL,*ptrB; |
317 | 639 | PixelPacket *q; |
318 | | |
319 | | /* |
320 | | Open image file. |
321 | | */ |
322 | 639 | assert(image_info != (const ImageInfo *) NULL); |
323 | 639 | assert(image_info->signature == MagickSignature); |
324 | 639 | assert(exception != (ExceptionInfo *) NULL); |
325 | 639 | assert(exception->signature == MagickSignature); |
326 | 639 | image=AllocateImage(image_info); |
327 | 639 | status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); |
328 | 639 | if (status == False) |
329 | 639 | ThrowReaderException(FileOpenError,UnableToOpenFile,image); |
330 | | /* |
331 | | Read CUT image. |
332 | | */ |
333 | 639 | Header.Width=ReadBlobLSBShort(image); |
334 | 639 | Header.Height=ReadBlobLSBShort(image); |
335 | 639 | Header.Reserved=ReadBlobLSBShort(image); |
336 | | |
337 | 639 | if (Header.Width==0 || Header.Height==0 || Header.Reserved!=0 || |
338 | 596 | (Header.Width > INT_MAX) || (Header.Height > INT_MAX) ) |
339 | 596 | CUT_KO: ThrowCUTReaderException(CorruptImageError,ImproperImageHeader,image); |
340 | | |
341 | | /*---This code checks first line of image---*/ |
342 | 596 | EncodedByte=ReadBlobLSBShort(image); |
343 | 596 | RunCount=ReadBlobByte(image); |
344 | 596 | RunCountMasked=RunCount & 0x7F; |
345 | 596 | ldblk=0; |
346 | 1.20M | while (RunCountMasked != 0) /*end of line?*/ |
347 | 1.20M | { |
348 | 1.20M | i=1; |
349 | 1.20M | if (RunCount<0x80) i=RunCountMasked; |
350 | 1.20M | (void) SeekBlob(image,TellBlob(image)+i,SEEK_SET); |
351 | 1.20M | if (EOFBlob(image)) goto CUT_KO; /*wrong data*/ |
352 | 1.20M | EncodedByte-=i+1; |
353 | 1.20M | ldblk+=RunCountMasked; |
354 | | |
355 | 1.20M | RunCount=ReadBlobByte(image); |
356 | 1.20M | if (EOFBlob(image)) goto CUT_KO; /*wrong data: unexpected eof in line*/ |
357 | 1.20M | RunCountMasked=RunCount & 0x7F; |
358 | 1.20M | } |
359 | 512 | if (EncodedByte!=1) goto CUT_KO; /*wrong data: size incorrect*/ |
360 | 476 | i=0; /*guess a number of bit planes*/ |
361 | 476 | if (ldblk==(int) Header.Width) i=8; |
362 | 476 | if (2*ldblk==(int) Header.Width) i=4; |
363 | 476 | if (8*ldblk==(int) Header.Width) i=1; |
364 | 476 | if (i==0) goto CUT_KO; /*wrong data: incorrect bit planes*/ |
365 | | |
366 | 426 | image->columns=Header.Width; |
367 | 426 | image->rows=Header.Height; |
368 | 426 | image->depth=i; |
369 | 426 | image->colors=1l >> i; |
370 | | |
371 | | /* If ping is true, then only set image size and colors without reading any image data. */ |
372 | 426 | if (image_info->ping) goto Finish; |
373 | | |
374 | 426 | if (CheckImagePixelLimits(image, exception) != MagickPass) |
375 | 400 | ThrowCUTReaderException(ResourceLimitError,ImagePixelLimitExceeded,image); |
376 | | |
377 | | /* ----- Do something with palette ----- */ |
378 | 400 | if ((clone_info=CloneImageInfo(image_info)) == NULL) goto NoPalette; |
379 | | |
380 | 400 | i=(long) strlen(clone_info->filename); |
381 | 400 | j=i; |
382 | 400 | while (--i>0) |
383 | 0 | { |
384 | 0 | if (clone_info->filename[i]=='.') |
385 | 0 | { |
386 | 0 | break; |
387 | 0 | } |
388 | 0 | if (clone_info->filename[i]=='/' || clone_info->filename[i]=='\\' || |
389 | 0 | clone_info->filename[i]==':' ) |
390 | 0 | { |
391 | 0 | i=j; |
392 | 0 | break; |
393 | 0 | } |
394 | 0 | } |
395 | | |
396 | 400 | if (i <= 0) |
397 | 400 | goto NoPalette; |
398 | | |
399 | 0 | (void) strlcpy(clone_info->filename+i,".PAL",sizeof(clone_info->filename)-i); |
400 | 0 | if ((clone_info->file=fopen(clone_info->filename,"rb"))==NULL) |
401 | 0 | { |
402 | 0 | (void) strlcpy(clone_info->filename+i,".pal",sizeof(clone_info->filename)-i); |
403 | 0 | if ((clone_info->file=fopen(clone_info->filename,"rb"))==NULL) |
404 | 0 | { |
405 | 0 | clone_info->filename[i]=0; |
406 | 0 | if ((clone_info->file=fopen(clone_info->filename,"rb"))==NULL) |
407 | 0 | { |
408 | 0 | DestroyImageInfo(clone_info); |
409 | 0 | clone_info=NULL; |
410 | 0 | goto NoPalette; |
411 | 0 | } |
412 | 0 | } |
413 | 0 | } |
414 | | |
415 | 0 | if ( (palette=AllocateImage(clone_info))==NULL ) goto NoPalette; |
416 | 0 | status=OpenBlob(clone_info,palette,ReadBinaryBlobMode,exception); |
417 | 0 | if (status == False) |
418 | 0 | { |
419 | 0 | ErasePalette: |
420 | 0 | DestroyImage(palette); |
421 | 0 | palette=NULL; |
422 | 0 | goto NoPalette; |
423 | 0 | } |
424 | | |
425 | | |
426 | 0 | if (palette!=NULL) |
427 | 0 | { |
428 | 0 | (void) ReadBlob(palette,2,PalHeader.FileId); |
429 | 0 | if (strncmp(PalHeader.FileId,"AH",2)) goto ErasePalette; |
430 | 0 | PalHeader.Version=ReadBlobLSBShort(palette); |
431 | 0 | PalHeader.Size=ReadBlobLSBShort(palette); |
432 | 0 | PalHeader.FileType=ReadBlobByte(palette); |
433 | 0 | PalHeader.SubType=ReadBlobByte(palette); |
434 | 0 | PalHeader.BoardID=ReadBlobLSBShort(palette); |
435 | 0 | PalHeader.GraphicsMode=ReadBlobLSBShort(palette); |
436 | 0 | PalHeader.MaxIndex=ReadBlobLSBShort(palette); |
437 | 0 | PalHeader.MaxRed=ReadBlobLSBShort(palette); |
438 | 0 | PalHeader.MaxGreen=ReadBlobLSBShort(palette); |
439 | 0 | PalHeader.MaxBlue=ReadBlobLSBShort(palette); |
440 | 0 | (void) ReadBlob(palette,20,PalHeader.PaletteId); |
441 | |
|
442 | 0 | if (EOFBlob(image)) |
443 | 0 | ThrowCUTReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
444 | |
|
445 | 0 | if (PalHeader.MaxIndex<1) goto ErasePalette; |
446 | 0 | image->colors=PalHeader.MaxIndex+1; |
447 | 0 | if (!AllocateImageColormap(image,image->colors)) goto NoMemory; |
448 | | |
449 | 0 | if (PalHeader.MaxRed==0) PalHeader.MaxRed=MaxRGB; /*avoid division by 0*/ |
450 | 0 | if (PalHeader.MaxGreen==0) PalHeader.MaxGreen=MaxRGB; |
451 | 0 | if (PalHeader.MaxBlue==0) PalHeader.MaxBlue=MaxRGB; |
452 | |
|
453 | 0 | for (i=0;i<=(int) PalHeader.MaxIndex;i++) |
454 | 0 | { |
455 | | /*this may be wrong- I don't know why is palette such strange*/ |
456 | 0 | j=(long) TellBlob(palette); |
457 | 0 | if ((j % 512)>512-6) |
458 | 0 | { |
459 | 0 | j=((j / 512)+1)*512; |
460 | 0 | (void) SeekBlob(palette,j,SEEK_SET); |
461 | 0 | } |
462 | 0 | image->colormap[i].red=ReadBlobLSBShort(palette); |
463 | 0 | if (MaxRGB!=PalHeader.MaxRed) |
464 | 0 | { |
465 | 0 | image->colormap[i].red=(Quantum) |
466 | 0 | (((double)image->colormap[i].red*MaxRGB+(PalHeader.MaxRed>>1))/PalHeader.MaxRed+0.5); |
467 | 0 | } |
468 | 0 | image->colormap[i].green=ReadBlobLSBShort(palette); |
469 | 0 | if (MaxRGB!=PalHeader.MaxGreen) |
470 | 0 | { |
471 | 0 | image->colormap[i].green=(Quantum) |
472 | 0 | (((double)image->colormap[i].green*MaxRGB+(PalHeader.MaxGreen>>1))/PalHeader.MaxGreen+0.5); |
473 | 0 | } |
474 | 0 | image->colormap[i].blue=ReadBlobLSBShort(palette); |
475 | 0 | if (MaxRGB!=PalHeader.MaxBlue) |
476 | 0 | { |
477 | 0 | image->colormap[i].blue=(Quantum) |
478 | 0 | (((double)image->colormap[i].blue*MaxRGB+(PalHeader.MaxBlue>>1))/PalHeader.MaxBlue+0.5); |
479 | 0 | } |
480 | |
|
481 | 0 | } |
482 | 0 | if (EOFBlob(image)) |
483 | 0 | ThrowCUTReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
484 | 0 | } |
485 | | |
486 | | |
487 | | |
488 | 400 | NoPalette: |
489 | 400 | if (palette==NULL) |
490 | 400 | { |
491 | | |
492 | 400 | image->colors=256; |
493 | 400 | if (!AllocateImageColormap(image,image->colors)) |
494 | 0 | { |
495 | 0 | NoMemory: |
496 | 0 | if (clone_info != NULL) |
497 | 0 | { |
498 | 0 | DestroyImageInfo(clone_info); |
499 | 0 | clone_info=(ImageInfo *) NULL; |
500 | 0 | } |
501 | 0 | ThrowCUTReaderException(ResourceLimitError,MemoryAllocationFailed,image); |
502 | 0 | } |
503 | | |
504 | 102k | for (i=0; i < (long)image->colors; i++) |
505 | 102k | { |
506 | 102k | image->colormap[i].red=ScaleCharToQuantum(i); |
507 | 102k | image->colormap[i].green=ScaleCharToQuantum(i); |
508 | 102k | image->colormap[i].blue=ScaleCharToQuantum(i); |
509 | 102k | } |
510 | 400 | } |
511 | | |
512 | | |
513 | | /* ----- Load RLE compressed raster ----- */ |
514 | 400 | BImgBuff=MagickAllocateResourceLimitedMemory(unsigned char *,(size_t) (ldblk)); /*Ldblk was set in the check phase*/ |
515 | 400 | if (BImgBuff==NULL) goto NoMemory; |
516 | | |
517 | 400 | (void) SeekBlob(image,6 /*sizeof(Header)*/,SEEK_SET); |
518 | 89.9k | for (i=0;i<(int) Header.Height;i++) |
519 | 89.8k | { |
520 | 89.8k | EncodedByte=ReadBlobLSBShort(image); |
521 | | |
522 | 89.8k | ptrB=BImgBuff; |
523 | 89.8k | j=ldblk; |
524 | | |
525 | 89.8k | RunCount=ReadBlobByte(image); |
526 | 89.8k | RunCountMasked=RunCount & 0x7F; |
527 | | |
528 | 1.87M | while (RunCountMasked!=0) |
529 | 1.85M | { |
530 | 1.85M | if (RunCountMasked>j) |
531 | 117k | { /*Wrong Data*/ |
532 | 117k | RunCountMasked=(unsigned char) j; |
533 | 117k | if (j==0) |
534 | 60.9k | { |
535 | 60.9k | break; |
536 | 60.9k | } |
537 | 117k | } |
538 | | |
539 | 1.78M | if (RunCount>0x80) |
540 | 1.19M | { |
541 | 1.19M | RunValue=ReadBlobByte(image); |
542 | 1.19M | (void) memset(ptrB,RunValue,RunCountMasked); |
543 | 1.19M | } |
544 | 591k | else { |
545 | 591k | (void) ReadBlob(image,RunCountMasked,ptrB); |
546 | 591k | } |
547 | | |
548 | 1.78M | ptrB+=RunCountMasked; |
549 | 1.78M | j-=RunCountMasked; |
550 | | |
551 | 1.78M | if (EOFBlob(image)) goto Finish; /* wrong data: unexpected eof in line */ |
552 | 1.78M | RunCount=ReadBlobByte(image); |
553 | 1.78M | RunCountMasked=RunCount & 0x7F; |
554 | 1.78M | } |
555 | | |
556 | 89.5k | InsertRow(BImgBuff,i,image); |
557 | 89.5k | } |
558 | | |
559 | | |
560 | | /*detect monochrome image*/ |
561 | | |
562 | 76 | if (palette==NULL) |
563 | 76 | { /*attempt to detect binary (black&white) images*/ |
564 | 76 | if ((image->storage_class == PseudoClass) && IsGrayImage(image,&image->exception)) |
565 | 76 | { |
566 | 76 | if (GetCutColors(image)==2) |
567 | 49 | { |
568 | 12.5k | for (i=0; i < (long)image->colors; i++) |
569 | 12.5k | { |
570 | 12.5k | register Quantum |
571 | 12.5k | sample; |
572 | 12.5k | sample=ScaleCharToQuantum(i); |
573 | 12.5k | if (image->colormap[i].red!=sample) goto Finish; |
574 | 12.5k | if (image->colormap[i].green!=sample) goto Finish; |
575 | 12.5k | if (image->colormap[i].blue!=sample) goto Finish; |
576 | 12.5k | } |
577 | | |
578 | 49 | image->colormap[1].red=image->colormap[1].green=image->colormap[1].blue=MaxRGB; |
579 | 6.81k | for (i=0; i < (long)image->rows; i++) |
580 | 6.77k | { |
581 | 6.77k | q=SetImagePixels(image,0,i,image->columns,1); |
582 | 6.77k | if (q == (PixelPacket *) NULL) |
583 | 0 | break; |
584 | 1.41M | for (j=0; j < (long)image->columns; j++) |
585 | 1.41M | { |
586 | 1.41M | if (q->red==ScaleCharToQuantum(1)) |
587 | 949k | { |
588 | 949k | q->red=q->green=q->blue=MaxRGB; |
589 | 949k | } |
590 | 1.41M | q++; |
591 | 1.41M | } |
592 | 6.77k | if (!SyncImagePixels(image)) goto Finish; |
593 | 6.77k | } |
594 | 49 | } |
595 | 76 | } |
596 | 76 | } |
597 | | |
598 | 400 | Finish: |
599 | 400 | if (BImgBuff!=NULL) MagickFreeResourceLimitedMemory(unsigned char *,BImgBuff); |
600 | 400 | if (palette!=NULL) |
601 | 0 | { |
602 | 0 | DestroyImage(palette); |
603 | 0 | palette=(Image *) NULL; |
604 | 0 | } |
605 | 400 | if (clone_info!=NULL) |
606 | 400 | { |
607 | 400 | DestroyImageInfo(clone_info); |
608 | 400 | clone_info=(ImageInfo *) NULL; |
609 | 400 | } |
610 | 400 | if (EOFBlob(image)) |
611 | 331 | ThrowCUTReaderException(CorruptImageError,UnexpectedEndOfFile,image); |
612 | 69 | CloseBlob(image); |
613 | 69 | StopTimer(&image->timer); |
614 | 69 | return(image); |
615 | 400 | } |
616 | | |
617 | | /* |
618 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
619 | | % % |
620 | | % % |
621 | | % % |
622 | | % R e g i s t e r C U T I m a g e % |
623 | | % % |
624 | | % % |
625 | | % % |
626 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
627 | | % |
628 | | % Method RegisterCUTImage adds attributes for the CUT image format to |
629 | | % the list of supported formats. The attributes include the image format |
630 | | % tag, a method to read and/or write the format, whether the format |
631 | | % supports the saving of more than one frame to the same file or blob, |
632 | | % whether the format supports native in-memory I/O, and a brief |
633 | | % description of the format. |
634 | | % |
635 | | % The format of the RegisterCUTImage method is: |
636 | | % |
637 | | % RegisterCUTImage(void) |
638 | | % |
639 | | */ |
640 | | ModuleExport void RegisterCUTImage(void) |
641 | 1 | { |
642 | 1 | MagickInfo |
643 | 1 | *entry; |
644 | | |
645 | 1 | entry=SetMagickInfo("CUT"); |
646 | 1 | entry->decoder=(DecoderHandler) ReadCUTImage; |
647 | 1 | entry->seekable_stream=True; |
648 | 1 | entry->description="DR Halo"; |
649 | 1 | entry->module="CUT"; |
650 | 1 | (void) RegisterMagickInfo(entry); |
651 | 1 | } |
652 | | |
653 | | /* |
654 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
655 | | % % |
656 | | % % |
657 | | % % |
658 | | % U n r e g i s t e r C U T I m a g e % |
659 | | % % |
660 | | % % |
661 | | % % |
662 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
663 | | % |
664 | | % Method UnregisterCUTImage removes format registrations made by the |
665 | | % CUT module from the list of supported formats. |
666 | | % |
667 | | % The format of the UnregisterCUTImage method is: |
668 | | % |
669 | | % UnregisterCUTImage(void) |
670 | | % |
671 | | */ |
672 | | ModuleExport void UnregisterCUTImage(void) |
673 | 0 | { |
674 | 0 | (void) UnregisterMagickInfo("CUT"); |
675 | 0 | } |