/src/imagemagick/MagickCore/compress.c
Line | Count | Source |
1 | | /* |
2 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3 | | % % |
4 | | % % |
5 | | % % |
6 | | % CCCC OOO M M PPPP RRRR EEEEE SSSSS SSSSS % |
7 | | % C O O MM MM P P R R E SS SS % |
8 | | % C O O M M M PPPP RRRR EEE SSS SSS % |
9 | | % C O O M M P R R E SS SS % |
10 | | % CCCC OOO M M P R R EEEEE SSSSS SSSSS % |
11 | | % % |
12 | | % % |
13 | | % MagickCore Image Compression/Decompression Methods % |
14 | | % % |
15 | | % Software Design % |
16 | | % Cristy % |
17 | | % May 1993 % |
18 | | % % |
19 | | % % |
20 | | % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization % |
21 | | % dedicated to making software imaging solutions freely available. % |
22 | | % % |
23 | | % You may not use this file except in compliance with the License. You may % |
24 | | % obtain a copy of the License at % |
25 | | % % |
26 | | % https://imagemagick.org/license/ % |
27 | | % % |
28 | | % Unless required by applicable law or agreed to in writing, software % |
29 | | % distributed under the License is distributed on an "AS IS" BASIS, % |
30 | | % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % |
31 | | % See the License for the specific language governing permissions and % |
32 | | % limitations under the License. % |
33 | | % % |
34 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
35 | | % |
36 | | % |
37 | | % |
38 | | */ |
39 | | |
40 | | /* |
41 | | Include declarations. |
42 | | */ |
43 | | #include "MagickCore/studio.h" |
44 | | #include "MagickCore/attribute.h" |
45 | | #include "MagickCore/blob.h" |
46 | | #include "MagickCore/blob-private.h" |
47 | | #include "MagickCore/color-private.h" |
48 | | #include "MagickCore/cache.h" |
49 | | #include "MagickCore/compress.h" |
50 | | #include "MagickCore/constitute.h" |
51 | | #include "MagickCore/exception.h" |
52 | | #include "MagickCore/exception-private.h" |
53 | | #include "MagickCore/image-private.h" |
54 | | #include "MagickCore/list.h" |
55 | | #include "MagickCore/memory_.h" |
56 | | #include "MagickCore/monitor.h" |
57 | | #include "MagickCore/monitor-private.h" |
58 | | #include "MagickCore/option.h" |
59 | | #include "MagickCore/pixel-accessor.h" |
60 | | #include "MagickCore/resource_.h" |
61 | | #include "MagickCore/string_.h" |
62 | | #if defined(MAGICKCORE_ZLIB_DELEGATE) |
63 | | #include "zlib.h" |
64 | | #endif |
65 | | |
66 | | /* |
67 | | Typedef declarations. |
68 | | */ |
69 | | struct _Ascii85Info |
70 | | { |
71 | | ssize_t |
72 | | offset, |
73 | | line_break; |
74 | | |
75 | | char |
76 | | tuple[6]; |
77 | | |
78 | | unsigned char |
79 | | buffer[10]; |
80 | | }; |
81 | | |
82 | | typedef struct HuffmanTable |
83 | | { |
84 | | size_t |
85 | | id, |
86 | | code, |
87 | | length, |
88 | | count; |
89 | | } HuffmanTable; |
90 | | |
91 | | /* |
92 | | Huffman coding declarations. |
93 | | */ |
94 | 0 | #define TWId 23L |
95 | 0 | #define MWId 24L |
96 | 0 | #define TBId 25L |
97 | 0 | #define MBId 26L |
98 | 0 | #define EXId 27L |
99 | | |
100 | | static const HuffmanTable |
101 | | MBTable[]= |
102 | | { |
103 | | { MBId, 0x0f, 10, 64 }, { MBId, 0xc8, 12, 128 }, |
104 | | { MBId, 0xc9, 12, 192 }, { MBId, 0x5b, 12, 256 }, |
105 | | { MBId, 0x33, 12, 320 }, { MBId, 0x34, 12, 384 }, |
106 | | { MBId, 0x35, 12, 448 }, { MBId, 0x6c, 13, 512 }, |
107 | | { MBId, 0x6d, 13, 576 }, { MBId, 0x4a, 13, 640 }, |
108 | | { MBId, 0x4b, 13, 704 }, { MBId, 0x4c, 13, 768 }, |
109 | | { MBId, 0x4d, 13, 832 }, { MBId, 0x72, 13, 896 }, |
110 | | { MBId, 0x73, 13, 960 }, { MBId, 0x74, 13, 1024 }, |
111 | | { MBId, 0x75, 13, 1088 }, { MBId, 0x76, 13, 1152 }, |
112 | | { MBId, 0x77, 13, 1216 }, { MBId, 0x52, 13, 1280 }, |
113 | | { MBId, 0x53, 13, 1344 }, { MBId, 0x54, 13, 1408 }, |
114 | | { MBId, 0x55, 13, 1472 }, { MBId, 0x5a, 13, 1536 }, |
115 | | { MBId, 0x5b, 13, 1600 }, { MBId, 0x64, 13, 1664 }, |
116 | | { MBId, 0x65, 13, 1728 }, { MBId, 0x00, 0, 0 } |
117 | | }; |
118 | | |
119 | | static const HuffmanTable |
120 | | EXTable[]= |
121 | | { |
122 | | { EXId, 0x08, 11, 1792 }, { EXId, 0x0c, 11, 1856 }, |
123 | | { EXId, 0x0d, 11, 1920 }, { EXId, 0x12, 12, 1984 }, |
124 | | { EXId, 0x13, 12, 2048 }, { EXId, 0x14, 12, 2112 }, |
125 | | { EXId, 0x15, 12, 2176 }, { EXId, 0x16, 12, 2240 }, |
126 | | { EXId, 0x17, 12, 2304 }, { EXId, 0x1c, 12, 2368 }, |
127 | | { EXId, 0x1d, 12, 2432 }, { EXId, 0x1e, 12, 2496 }, |
128 | | { EXId, 0x1f, 12, 2560 }, { EXId, 0x00, 0, 0 } |
129 | | }; |
130 | | |
131 | | static const HuffmanTable |
132 | | MWTable[]= |
133 | | { |
134 | | { MWId, 0x1b, 5, 64 }, { MWId, 0x12, 5, 128 }, |
135 | | { MWId, 0x17, 6, 192 }, { MWId, 0x37, 7, 256 }, |
136 | | { MWId, 0x36, 8, 320 }, { MWId, 0x37, 8, 384 }, |
137 | | { MWId, 0x64, 8, 448 }, { MWId, 0x65, 8, 512 }, |
138 | | { MWId, 0x68, 8, 576 }, { MWId, 0x67, 8, 640 }, |
139 | | { MWId, 0xcc, 9, 704 }, { MWId, 0xcd, 9, 768 }, |
140 | | { MWId, 0xd2, 9, 832 }, { MWId, 0xd3, 9, 896 }, |
141 | | { MWId, 0xd4, 9, 960 }, { MWId, 0xd5, 9, 1024 }, |
142 | | { MWId, 0xd6, 9, 1088 }, { MWId, 0xd7, 9, 1152 }, |
143 | | { MWId, 0xd8, 9, 1216 }, { MWId, 0xd9, 9, 1280 }, |
144 | | { MWId, 0xda, 9, 1344 }, { MWId, 0xdb, 9, 1408 }, |
145 | | { MWId, 0x98, 9, 1472 }, { MWId, 0x99, 9, 1536 }, |
146 | | { MWId, 0x9a, 9, 1600 }, { MWId, 0x18, 6, 1664 }, |
147 | | { MWId, 0x9b, 9, 1728 }, { MWId, 0x00, 0, 0 } |
148 | | }; |
149 | | |
150 | | static const HuffmanTable |
151 | | TBTable[]= |
152 | | { |
153 | | { TBId, 0x37, 10, 0 }, { TBId, 0x02, 3, 1 }, { TBId, 0x03, 2, 2 }, |
154 | | { TBId, 0x02, 2, 3 }, { TBId, 0x03, 3, 4 }, { TBId, 0x03, 4, 5 }, |
155 | | { TBId, 0x02, 4, 6 }, { TBId, 0x03, 5, 7 }, { TBId, 0x05, 6, 8 }, |
156 | | { TBId, 0x04, 6, 9 }, { TBId, 0x04, 7, 10 }, { TBId, 0x05, 7, 11 }, |
157 | | { TBId, 0x07, 7, 12 }, { TBId, 0x04, 8, 13 }, { TBId, 0x07, 8, 14 }, |
158 | | { TBId, 0x18, 9, 15 }, { TBId, 0x17, 10, 16 }, { TBId, 0x18, 10, 17 }, |
159 | | { TBId, 0x08, 10, 18 }, { TBId, 0x67, 11, 19 }, { TBId, 0x68, 11, 20 }, |
160 | | { TBId, 0x6c, 11, 21 }, { TBId, 0x37, 11, 22 }, { TBId, 0x28, 11, 23 }, |
161 | | { TBId, 0x17, 11, 24 }, { TBId, 0x18, 11, 25 }, { TBId, 0xca, 12, 26 }, |
162 | | { TBId, 0xcb, 12, 27 }, { TBId, 0xcc, 12, 28 }, { TBId, 0xcd, 12, 29 }, |
163 | | { TBId, 0x68, 12, 30 }, { TBId, 0x69, 12, 31 }, { TBId, 0x6a, 12, 32 }, |
164 | | { TBId, 0x6b, 12, 33 }, { TBId, 0xd2, 12, 34 }, { TBId, 0xd3, 12, 35 }, |
165 | | { TBId, 0xd4, 12, 36 }, { TBId, 0xd5, 12, 37 }, { TBId, 0xd6, 12, 38 }, |
166 | | { TBId, 0xd7, 12, 39 }, { TBId, 0x6c, 12, 40 }, { TBId, 0x6d, 12, 41 }, |
167 | | { TBId, 0xda, 12, 42 }, { TBId, 0xdb, 12, 43 }, { TBId, 0x54, 12, 44 }, |
168 | | { TBId, 0x55, 12, 45 }, { TBId, 0x56, 12, 46 }, { TBId, 0x57, 12, 47 }, |
169 | | { TBId, 0x64, 12, 48 }, { TBId, 0x65, 12, 49 }, { TBId, 0x52, 12, 50 }, |
170 | | { TBId, 0x53, 12, 51 }, { TBId, 0x24, 12, 52 }, { TBId, 0x37, 12, 53 }, |
171 | | { TBId, 0x38, 12, 54 }, { TBId, 0x27, 12, 55 }, { TBId, 0x28, 12, 56 }, |
172 | | { TBId, 0x58, 12, 57 }, { TBId, 0x59, 12, 58 }, { TBId, 0x2b, 12, 59 }, |
173 | | { TBId, 0x2c, 12, 60 }, { TBId, 0x5a, 12, 61 }, { TBId, 0x66, 12, 62 }, |
174 | | { TBId, 0x67, 12, 63 }, { TBId, 0x00, 0, 0 } |
175 | | }; |
176 | | |
177 | | static const HuffmanTable |
178 | | TWTable[]= |
179 | | { |
180 | | { TWId, 0x35, 8, 0 }, { TWId, 0x07, 6, 1 }, { TWId, 0x07, 4, 2 }, |
181 | | { TWId, 0x08, 4, 3 }, { TWId, 0x0b, 4, 4 }, { TWId, 0x0c, 4, 5 }, |
182 | | { TWId, 0x0e, 4, 6 }, { TWId, 0x0f, 4, 7 }, { TWId, 0x13, 5, 8 }, |
183 | | { TWId, 0x14, 5, 9 }, { TWId, 0x07, 5, 10 }, { TWId, 0x08, 5, 11 }, |
184 | | { TWId, 0x08, 6, 12 }, { TWId, 0x03, 6, 13 }, { TWId, 0x34, 6, 14 }, |
185 | | { TWId, 0x35, 6, 15 }, { TWId, 0x2a, 6, 16 }, { TWId, 0x2b, 6, 17 }, |
186 | | { TWId, 0x27, 7, 18 }, { TWId, 0x0c, 7, 19 }, { TWId, 0x08, 7, 20 }, |
187 | | { TWId, 0x17, 7, 21 }, { TWId, 0x03, 7, 22 }, { TWId, 0x04, 7, 23 }, |
188 | | { TWId, 0x28, 7, 24 }, { TWId, 0x2b, 7, 25 }, { TWId, 0x13, 7, 26 }, |
189 | | { TWId, 0x24, 7, 27 }, { TWId, 0x18, 7, 28 }, { TWId, 0x02, 8, 29 }, |
190 | | { TWId, 0x03, 8, 30 }, { TWId, 0x1a, 8, 31 }, { TWId, 0x1b, 8, 32 }, |
191 | | { TWId, 0x12, 8, 33 }, { TWId, 0x13, 8, 34 }, { TWId, 0x14, 8, 35 }, |
192 | | { TWId, 0x15, 8, 36 }, { TWId, 0x16, 8, 37 }, { TWId, 0x17, 8, 38 }, |
193 | | { TWId, 0x28, 8, 39 }, { TWId, 0x29, 8, 40 }, { TWId, 0x2a, 8, 41 }, |
194 | | { TWId, 0x2b, 8, 42 }, { TWId, 0x2c, 8, 43 }, { TWId, 0x2d, 8, 44 }, |
195 | | { TWId, 0x04, 8, 45 }, { TWId, 0x05, 8, 46 }, { TWId, 0x0a, 8, 47 }, |
196 | | { TWId, 0x0b, 8, 48 }, { TWId, 0x52, 8, 49 }, { TWId, 0x53, 8, 50 }, |
197 | | { TWId, 0x54, 8, 51 }, { TWId, 0x55, 8, 52 }, { TWId, 0x24, 8, 53 }, |
198 | | { TWId, 0x25, 8, 54 }, { TWId, 0x58, 8, 55 }, { TWId, 0x59, 8, 56 }, |
199 | | { TWId, 0x5a, 8, 57 }, { TWId, 0x5b, 8, 58 }, { TWId, 0x4a, 8, 59 }, |
200 | | { TWId, 0x4b, 8, 60 }, { TWId, 0x32, 8, 61 }, { TWId, 0x33, 8, 62 }, |
201 | | { TWId, 0x34, 8, 63 }, { TWId, 0x00, 0, 0 } |
202 | | }; |
203 | | |
204 | | /* |
205 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
206 | | % % |
207 | | % % |
208 | | % % |
209 | | % A S C I I 8 5 E n c o d e % |
210 | | % % |
211 | | % % |
212 | | % % |
213 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
214 | | % |
215 | | % ASCII85Encode() encodes data in ASCII base-85 format. ASCII base-85 |
216 | | % encoding produces five ASCII printing characters from every four bytes of |
217 | | % binary data. |
218 | | % |
219 | | % The format of the ASCII85Encode method is: |
220 | | % |
221 | | % void Ascii85Encode(Image *image,const size_t code) |
222 | | % |
223 | | % A description of each parameter follows: |
224 | | % |
225 | | % o code: a binary unsigned char to encode to ASCII 85. |
226 | | % |
227 | | % o file: write the encoded ASCII character to this file. |
228 | | % |
229 | | % |
230 | | */ |
231 | | static inline void Ascii85Tuple(Ascii85Info *ascii85_info, |
232 | | const unsigned char *magick_restrict data) |
233 | 0 | { |
234 | 0 | #define MaxLineExtent 36L |
235 | |
|
236 | 0 | size_t |
237 | 0 | code, |
238 | 0 | i, |
239 | 0 | quantum, |
240 | 0 | x; |
241 | |
|
242 | 0 | code=((((size_t) data[0] << 8) | (size_t) data[1]) << 16) | |
243 | 0 | ((size_t) data[2] << 8) | (size_t) data[3]; |
244 | 0 | if (code == 0L) |
245 | 0 | { |
246 | 0 | ascii85_info->tuple[0]='z'; |
247 | 0 | ascii85_info->tuple[1]='\0'; |
248 | 0 | return; |
249 | 0 | } |
250 | 0 | quantum=85UL*85UL*85UL*85UL; |
251 | 0 | for (i=0; i < 4; i++) |
252 | 0 | { |
253 | 0 | x=(code/quantum); |
254 | 0 | code-=quantum*x; |
255 | 0 | ascii85_info->tuple[i]=(char) (x+(int) '!'); |
256 | 0 | quantum/=85L; |
257 | 0 | } |
258 | 0 | ascii85_info->tuple[4]=(char) ((code % 85L)+(int) '!'); |
259 | 0 | ascii85_info->tuple[5]='\0'; |
260 | 0 | } |
261 | | |
262 | | MagickExport void Ascii85Initialize(Image *image) |
263 | 0 | { |
264 | | /* |
265 | | Allocate image structure. |
266 | | */ |
267 | 0 | if (image->ascii85 == (Ascii85Info *) NULL) |
268 | 0 | image->ascii85=(Ascii85Info *) AcquireCriticalMemory( |
269 | 0 | sizeof(*image->ascii85)); |
270 | 0 | (void) memset(image->ascii85,0,sizeof(*image->ascii85)); |
271 | 0 | image->ascii85->line_break=(ssize_t) (MaxLineExtent << 1); |
272 | 0 | image->ascii85->offset=0; |
273 | 0 | } |
274 | | |
275 | | MagickExport void Ascii85Flush(Image *image) |
276 | 0 | { |
277 | 0 | assert(image != (Image *) NULL); |
278 | 0 | assert(image->signature == MagickCoreSignature); |
279 | 0 | assert(image->ascii85 != (Ascii85Info *) NULL); |
280 | 0 | if (IsEventLogging() != MagickFalse) |
281 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
282 | 0 | if (image->ascii85->offset > 0) |
283 | 0 | { |
284 | 0 | image->ascii85->buffer[image->ascii85->offset]='\0'; |
285 | 0 | image->ascii85->buffer[image->ascii85->offset+1]='\0'; |
286 | 0 | image->ascii85->buffer[image->ascii85->offset+2]='\0'; |
287 | 0 | Ascii85Tuple(image->ascii85,image->ascii85->buffer); |
288 | 0 | (void) WriteBlob(image,(size_t) image->ascii85->offset+1, |
289 | 0 | (const unsigned char *) (*image->ascii85->tuple == 'z' ? "!!!!" : |
290 | 0 | image->ascii85->tuple)); |
291 | 0 | } |
292 | 0 | (void) WriteBlobByte(image,'~'); |
293 | 0 | (void) WriteBlobByte(image,'>'); |
294 | 0 | (void) WriteBlobByte(image,'\n'); |
295 | 0 | } |
296 | | |
297 | | MagickExport void Ascii85Encode(Image *image,const unsigned char code) |
298 | 0 | { |
299 | 0 | char |
300 | 0 | *q; |
301 | |
|
302 | 0 | unsigned char |
303 | 0 | *p; |
304 | |
|
305 | 0 | ssize_t |
306 | 0 | n; |
307 | |
|
308 | 0 | assert(image != (Image *) NULL); |
309 | 0 | assert(image->signature == MagickCoreSignature); |
310 | 0 | assert(image->ascii85 != (Ascii85Info *) NULL); |
311 | 0 | image->ascii85->buffer[image->ascii85->offset]=code; |
312 | 0 | image->ascii85->offset++; |
313 | 0 | if (image->ascii85->offset < 4) |
314 | 0 | return; |
315 | 0 | p=image->ascii85->buffer; |
316 | 0 | for (n=image->ascii85->offset; n >= 4; n-=4) |
317 | 0 | { |
318 | 0 | Ascii85Tuple(image->ascii85,p); |
319 | 0 | for (q=image->ascii85->tuple; *q != '\0'; q++) |
320 | 0 | { |
321 | 0 | image->ascii85->line_break--; |
322 | 0 | if ((image->ascii85->line_break < 0) && (*q != '%')) |
323 | 0 | { |
324 | 0 | (void) WriteBlobByte(image,'\n'); |
325 | 0 | image->ascii85->line_break=2*MaxLineExtent; |
326 | 0 | } |
327 | 0 | (void) WriteBlobByte(image,(unsigned char) *q); |
328 | 0 | } |
329 | 0 | p+=(ptrdiff_t) 8; |
330 | 0 | } |
331 | 0 | image->ascii85->offset=n; |
332 | 0 | p-=(ptrdiff_t)4; |
333 | 0 | for (n=0; n < 4; n++) |
334 | 0 | image->ascii85->buffer[n]=(*p++); |
335 | 0 | } |
336 | | |
337 | | /* |
338 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
339 | | % % |
340 | | % % |
341 | | % % |
342 | | % H u f f m a n D e c o d e I m a g e % |
343 | | % % |
344 | | % % |
345 | | % % |
346 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
347 | | % |
348 | | % HuffmanDecodeImage() uncompresses an image via Huffman-coding. |
349 | | % |
350 | | % The format of the HuffmanDecodeImage method is: |
351 | | % |
352 | | % MagickBooleanType HuffmanDecodeImage(Image *image, |
353 | | % ExceptionInfo *exception) |
354 | | % |
355 | | % A description of each parameter follows: |
356 | | % |
357 | | % o image: the image. |
358 | | % |
359 | | % o exception: return any errors or warnings in this structure. |
360 | | % |
361 | | */ |
362 | | MagickExport MagickBooleanType HuffmanDecodeImage(Image *image, |
363 | | ExceptionInfo *exception) |
364 | 25 | { |
365 | 50 | #define HashSize 1021L |
366 | 25 | #define MBHashA 293L |
367 | 25 | #define MBHashB 2695L |
368 | 25 | #define MWHashA 3510L |
369 | 25 | #define MWHashB 1178L |
370 | | |
371 | 25 | #define InitializeHashTable(hash,table,a,b) \ |
372 | 0 | { \ |
373 | 0 | entry=table; \ |
374 | 0 | while (entry->code != 0) \ |
375 | 0 | { \ |
376 | 0 | hash[((entry->length+a)*(entry->code+b)) % HashSize]=(HuffmanTable *) entry; \ |
377 | 0 | entry++; \ |
378 | 0 | } \ |
379 | 0 | } |
380 | | |
381 | 25 | #define InputBit(bit) \ |
382 | 0 | { \ |
383 | 0 | if ((mask & 0xff) == 0) \ |
384 | 0 | { \ |
385 | 0 | byte=ReadBlobByte(image); \ |
386 | 0 | if (byte == EOF) \ |
387 | 0 | break; \ |
388 | 0 | mask=0x80; \ |
389 | 0 | } \ |
390 | 0 | runlength++; \ |
391 | 0 | bit=(size_t) ((byte & mask) != 0 ? 0x01 : 0x00); \ |
392 | 0 | mask>>=1; \ |
393 | 0 | if (bit != 0) \ |
394 | 0 | runlength=0; \ |
395 | 0 | } |
396 | | |
397 | 25 | CacheView |
398 | 25 | *image_view; |
399 | | |
400 | 25 | const HuffmanTable |
401 | 25 | *entry; |
402 | | |
403 | 25 | HuffmanTable |
404 | 25 | **mb_hash, |
405 | 25 | **mw_hash; |
406 | | |
407 | 25 | int |
408 | 25 | byte, |
409 | 25 | mask; |
410 | | |
411 | 25 | MagickBooleanType |
412 | 25 | proceed; |
413 | | |
414 | 25 | Quantum |
415 | 25 | index; |
416 | | |
417 | 25 | size_t |
418 | 25 | bit, |
419 | 25 | code, |
420 | 25 | length, |
421 | 25 | null_lines, |
422 | 25 | runlength; |
423 | | |
424 | 25 | ssize_t |
425 | 25 | count, |
426 | 25 | i, |
427 | 25 | y; |
428 | | |
429 | 25 | unsigned char |
430 | 25 | *p, |
431 | 25 | *scanline; |
432 | | |
433 | 25 | unsigned int |
434 | 25 | bail, |
435 | 25 | color; |
436 | | |
437 | | /* |
438 | | Allocate buffers. |
439 | | */ |
440 | 25 | assert(image != (Image *) NULL); |
441 | 25 | assert(image->signature == MagickCoreSignature); |
442 | 25 | if (IsEventLogging() != MagickFalse) |
443 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
444 | 25 | if (image->blob == (BlobInfo *) NULL) |
445 | 25 | ThrowBinaryException(BlobError,"UnableToOpenBlob",image->filename); |
446 | 25 | mb_hash=(HuffmanTable **) AcquireQuantumMemory(HashSize,sizeof(*mb_hash)); |
447 | 25 | mw_hash=(HuffmanTable **) AcquireQuantumMemory(HashSize,sizeof(*mw_hash)); |
448 | 25 | scanline=(unsigned char *) AcquireQuantumMemory((size_t) image->columns, |
449 | 25 | sizeof(*scanline)); |
450 | 25 | if ((mb_hash == (HuffmanTable **) NULL) || |
451 | 25 | (mw_hash == (HuffmanTable **) NULL) || |
452 | 25 | (scanline == (unsigned char *) NULL)) |
453 | 25 | { |
454 | 25 | if (mb_hash != (HuffmanTable **) NULL) |
455 | 25 | mb_hash=(HuffmanTable **) RelinquishMagickMemory(mb_hash); |
456 | 25 | if (mw_hash != (HuffmanTable **) NULL) |
457 | 25 | mw_hash=(HuffmanTable **) RelinquishMagickMemory(mw_hash); |
458 | 25 | if (scanline != (unsigned char *) NULL) |
459 | 0 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
460 | 25 | ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", |
461 | 25 | image->filename); |
462 | 0 | } |
463 | | /* |
464 | | Initialize Huffman tables. |
465 | | */ |
466 | 0 | for (i=0; i < HashSize; i++) |
467 | 0 | { |
468 | 0 | mb_hash[i]=(HuffmanTable *) NULL; |
469 | 0 | mw_hash[i]=(HuffmanTable *) NULL; |
470 | 0 | } |
471 | 0 | InitializeHashTable(mw_hash,TWTable,MWHashA,MWHashB); |
472 | 0 | InitializeHashTable(mw_hash,MWTable,MWHashA,MWHashB); |
473 | 0 | InitializeHashTable(mw_hash,EXTable,MWHashA,MWHashB); |
474 | 0 | InitializeHashTable(mb_hash,TBTable,MBHashA,MBHashB); |
475 | 0 | InitializeHashTable(mb_hash,MBTable,MBHashA,MBHashB); |
476 | 0 | InitializeHashTable(mb_hash,EXTable,MBHashA,MBHashB); |
477 | | /* |
478 | | Uncompress 1D Huffman to runlength encoded pixels. |
479 | | */ |
480 | 0 | byte=0; |
481 | 0 | mask=0; |
482 | 0 | null_lines=0; |
483 | 0 | runlength=0; |
484 | 0 | while (runlength < 11) |
485 | 0 | InputBit(bit); |
486 | 0 | do { InputBit(bit); } while ((int) bit == 0); |
487 | 0 | image->resolution.x=204.0; |
488 | 0 | image->resolution.y=196.0; |
489 | 0 | image->units=PixelsPerInchResolution; |
490 | 0 | image_view=AcquireAuthenticCacheView(image,exception); |
491 | 0 | for (y=0; ((y < (ssize_t) image->rows) && (null_lines < 3)); ) |
492 | 0 | { |
493 | 0 | Quantum |
494 | 0 | *magick_restrict q; |
495 | |
|
496 | 0 | ssize_t |
497 | 0 | x; |
498 | | |
499 | | /* |
500 | | Initialize scanline to white. |
501 | | */ |
502 | 0 | memset(scanline,0,sizeof(*scanline)*image->columns); |
503 | | /* |
504 | | Decode Huffman encoded scanline. |
505 | | */ |
506 | 0 | color=MagickTrue; |
507 | 0 | code=0; |
508 | 0 | count=0; |
509 | 0 | length=0; |
510 | 0 | runlength=0; |
511 | 0 | x=0; |
512 | 0 | for ( ; ; ) |
513 | 0 | { |
514 | 0 | if (byte == EOF) |
515 | 0 | break; |
516 | 0 | if (x >= (ssize_t) image->columns) |
517 | 0 | { |
518 | 0 | while (runlength < 11) |
519 | 0 | InputBit(bit); |
520 | 0 | do { InputBit(bit); } while ((int) bit == 0); |
521 | 0 | break; |
522 | 0 | } |
523 | 0 | bail=MagickFalse; |
524 | 0 | do |
525 | 0 | { |
526 | 0 | if (runlength < 11) |
527 | 0 | InputBit(bit) |
528 | 0 | else |
529 | 0 | { |
530 | 0 | InputBit(bit); |
531 | 0 | if ((int) bit != 0) |
532 | 0 | { |
533 | 0 | null_lines++; |
534 | 0 | if (x != 0) |
535 | 0 | null_lines=0; |
536 | 0 | bail=MagickTrue; |
537 | 0 | break; |
538 | 0 | } |
539 | 0 | } |
540 | 0 | code=(code << 1)+(size_t) bit; |
541 | 0 | length++; |
542 | 0 | } while (code == 0); |
543 | 0 | if (bail != MagickFalse) |
544 | 0 | break; |
545 | 0 | if (length > 13) |
546 | 0 | { |
547 | 0 | while (runlength < 11) |
548 | 0 | InputBit(bit); |
549 | 0 | do { InputBit(bit); } while ((int) bit == 0); |
550 | 0 | break; |
551 | 0 | } |
552 | 0 | if (color != MagickFalse) |
553 | 0 | { |
554 | 0 | if (length < 4) |
555 | 0 | continue; |
556 | 0 | entry=mw_hash[((length+MWHashA)*(code+MWHashB)) % HashSize]; |
557 | 0 | } |
558 | 0 | else |
559 | 0 | { |
560 | 0 | if (length < 2) |
561 | 0 | continue; |
562 | 0 | entry=mb_hash[((length+MBHashA)*(code+MBHashB)) % HashSize]; |
563 | 0 | } |
564 | 0 | if (entry == (const HuffmanTable *) NULL) |
565 | 0 | continue; |
566 | 0 | if ((entry->length != length) || (entry->code != code)) |
567 | 0 | continue; |
568 | 0 | switch (entry->id) |
569 | 0 | { |
570 | 0 | case TWId: |
571 | 0 | case TBId: |
572 | 0 | { |
573 | 0 | count+=(ssize_t) entry->count; |
574 | 0 | if ((x+count) > (ssize_t) image->columns) |
575 | 0 | count=(ssize_t) image->columns-x; |
576 | 0 | if (count > 0) |
577 | 0 | { |
578 | 0 | if (color != MagickFalse) |
579 | 0 | { |
580 | 0 | x+=count; |
581 | 0 | count=0; |
582 | 0 | } |
583 | 0 | else |
584 | 0 | for ( ; count > 0; count--) |
585 | 0 | if ((x >= 0) && (x < (ssize_t) image->columns)) |
586 | 0 | scanline[x++]=(unsigned char) 1; |
587 | 0 | } |
588 | 0 | color=(unsigned int) |
589 | 0 | ((color == MagickFalse) ? MagickTrue : MagickFalse); |
590 | 0 | break; |
591 | 0 | } |
592 | 0 | case MWId: |
593 | 0 | case MBId: |
594 | 0 | case EXId: |
595 | 0 | { |
596 | 0 | count+=(ssize_t) entry->count; |
597 | 0 | break; |
598 | 0 | } |
599 | 0 | default: |
600 | 0 | break; |
601 | 0 | } |
602 | 0 | code=0; |
603 | 0 | length=0; |
604 | 0 | } |
605 | | /* |
606 | | Transfer scanline to image pixels. |
607 | | */ |
608 | 0 | p=scanline; |
609 | 0 | q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); |
610 | 0 | if (q == (Quantum *) NULL) |
611 | 0 | break; |
612 | 0 | for (x=0; x < (ssize_t) image->columns; x++) |
613 | 0 | { |
614 | 0 | index=(Quantum) (*p++); |
615 | 0 | SetPixelIndex(image,index,q); |
616 | 0 | SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q); |
617 | 0 | q+=(ptrdiff_t) GetPixelChannels(image); |
618 | 0 | } |
619 | 0 | if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) |
620 | 0 | break; |
621 | 0 | proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, |
622 | 0 | image->rows); |
623 | 0 | if (proceed == MagickFalse) |
624 | 0 | break; |
625 | 0 | y++; |
626 | 0 | } |
627 | 0 | image_view=DestroyCacheView(image_view); |
628 | 0 | image->rows=(size_t) MagickMax((size_t) y-3,1); |
629 | 0 | image->compression=FaxCompression; |
630 | | /* |
631 | | Free decoder memory. |
632 | | */ |
633 | 0 | mw_hash=(HuffmanTable **) RelinquishMagickMemory(mw_hash); |
634 | 0 | mb_hash=(HuffmanTable **) RelinquishMagickMemory(mb_hash); |
635 | 0 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
636 | 0 | return(MagickTrue); |
637 | 0 | } |
638 | | |
639 | | /* |
640 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
641 | | % % |
642 | | % % |
643 | | % % |
644 | | % H u f f m a n E n c o d e I m a g e % |
645 | | % % |
646 | | % % |
647 | | % % |
648 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
649 | | % |
650 | | % HuffmanEncodeImage() compresses an image via Huffman-coding. |
651 | | % |
652 | | % The format of the HuffmanEncodeImage method is: |
653 | | % |
654 | | % MagickBooleanType HuffmanEncodeImage(const ImageInfo *image_info, |
655 | | % Image *image,Image *inject_image,ExceptionInfo *exception) |
656 | | % |
657 | | % A description of each parameter follows: |
658 | | % |
659 | | % o image_info: the image info.. |
660 | | % |
661 | | % o image: the image. |
662 | | % |
663 | | % o inject_image: inject into the image stream. |
664 | | % |
665 | | % o exception: return any errors or warnings in this structure. |
666 | | % |
667 | | */ |
668 | | MagickExport MagickBooleanType HuffmanEncodeImage(const ImageInfo *image_info, |
669 | | Image *image,Image *inject_image,ExceptionInfo *exception) |
670 | 0 | { |
671 | 0 | #define HuffmanOutputCode(entry) \ |
672 | 0 | { \ |
673 | 0 | mask=one << (entry->length-1); \ |
674 | 0 | while (mask != 0) \ |
675 | 0 | { \ |
676 | 0 | OutputBit(((entry->code & mask) != 0 ? 1 : 0)); \ |
677 | 0 | mask>>=1; \ |
678 | 0 | } \ |
679 | 0 | } |
680 | |
|
681 | 0 | #define OutputBit(count) \ |
682 | 0 | { \ |
683 | 0 | DisableMSCWarning(4127) \ |
684 | 0 | if (count > 0) \ |
685 | 0 | byte=byte | bit; \ |
686 | 0 | RestoreMSCWarning \ |
687 | 0 | bit>>=1; \ |
688 | 0 | if ((int) (bit & 0xff) == 0) \ |
689 | 0 | { \ |
690 | 0 | if (LocaleCompare(image_info->magick,"FAX") == 0) \ |
691 | 0 | (void) WriteBlobByte(image,(unsigned char) byte); \ |
692 | 0 | else \ |
693 | 0 | Ascii85Encode(image,byte); \ |
694 | 0 | byte='\0'; \ |
695 | 0 | bit=(unsigned char) 0x80; \ |
696 | 0 | } \ |
697 | 0 | } |
698 | |
|
699 | 0 | const HuffmanTable |
700 | 0 | *entry; |
701 | |
|
702 | 0 | int |
703 | 0 | k, |
704 | 0 | runlength; |
705 | |
|
706 | 0 | Image |
707 | 0 | *huffman_image; |
708 | |
|
709 | 0 | MagickBooleanType |
710 | 0 | proceed; |
711 | |
|
712 | 0 | ssize_t |
713 | 0 | i, |
714 | 0 | x; |
715 | |
|
716 | 0 | const Quantum |
717 | 0 | *p; |
718 | |
|
719 | 0 | unsigned char |
720 | 0 | *q; |
721 | |
|
722 | 0 | size_t |
723 | 0 | mask, |
724 | 0 | one, |
725 | 0 | width; |
726 | |
|
727 | 0 | ssize_t |
728 | 0 | n, |
729 | 0 | y; |
730 | |
|
731 | 0 | unsigned char |
732 | 0 | byte, |
733 | 0 | bit, |
734 | 0 | *scanline; |
735 | | |
736 | | /* |
737 | | Allocate scanline buffer. |
738 | | */ |
739 | 0 | assert(image_info != (ImageInfo *) NULL); |
740 | 0 | assert(image_info->signature == MagickCoreSignature); |
741 | 0 | assert(image != (Image *) NULL); |
742 | 0 | assert(image->signature == MagickCoreSignature); |
743 | 0 | if (IsEventLogging() != MagickFalse) |
744 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
745 | 0 | assert(inject_image != (Image *) NULL); |
746 | 0 | assert(inject_image->signature == MagickCoreSignature); |
747 | 0 | one=1; |
748 | 0 | width=inject_image->columns; |
749 | 0 | if (LocaleCompare(image_info->magick,"FAX") == 0) |
750 | 0 | width=(size_t) MagickMax(inject_image->columns,1728); |
751 | 0 | scanline=(unsigned char *) AcquireQuantumMemory((size_t) width+1UL, |
752 | 0 | sizeof(*scanline)); |
753 | 0 | if (scanline == (unsigned char *) NULL) |
754 | 0 | ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", |
755 | 0 | inject_image->filename); |
756 | 0 | (void) memset(scanline,0,width*sizeof(*scanline)); |
757 | 0 | huffman_image=CloneImage(inject_image,0,0,MagickTrue,exception); |
758 | 0 | if (huffman_image == (Image *) NULL) |
759 | 0 | { |
760 | 0 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
761 | 0 | return(MagickFalse); |
762 | 0 | } |
763 | 0 | (void) SetImageType(huffman_image,BilevelType,exception); |
764 | 0 | byte='\0'; |
765 | 0 | bit=(unsigned char) 0x80; |
766 | 0 | if (LocaleCompare(image_info->magick,"FAX") != 0) |
767 | 0 | Ascii85Initialize(image); |
768 | 0 | else |
769 | 0 | { |
770 | | /* |
771 | | End of line. |
772 | | */ |
773 | 0 | for (k=0; k < 11; k++) |
774 | 0 | OutputBit(0); |
775 | 0 | OutputBit(1); |
776 | 0 | } |
777 | | /* |
778 | | Compress to 1D Huffman pixels. |
779 | | */ |
780 | 0 | q=scanline; |
781 | 0 | for (y=0; y < (ssize_t) huffman_image->rows; y++) |
782 | 0 | { |
783 | 0 | p=GetVirtualPixels(huffman_image,0,y,huffman_image->columns,1,exception); |
784 | 0 | if (p == (const Quantum *) NULL) |
785 | 0 | break; |
786 | 0 | for (x=0; x < (ssize_t) huffman_image->columns; x++) |
787 | 0 | { |
788 | 0 | *q++=(unsigned char) (GetPixelIntensity(huffman_image,p) >= |
789 | 0 | ((double) QuantumRange/2.0) ? 0 : 1); |
790 | 0 | p+=(ptrdiff_t) GetPixelChannels(huffman_image); |
791 | 0 | } |
792 | | /* |
793 | | Huffman encode scanline. |
794 | | */ |
795 | 0 | q=scanline; |
796 | 0 | for (n=(ssize_t) width; n > 0; ) |
797 | 0 | { |
798 | | /* |
799 | | Output white run. |
800 | | */ |
801 | 0 | for (runlength=0; ((n > 0) && (*q == 0)); n--) |
802 | 0 | { |
803 | 0 | q++; |
804 | 0 | runlength++; |
805 | 0 | } |
806 | 0 | if (runlength >= 64) |
807 | 0 | { |
808 | 0 | if (runlength < 1792) |
809 | 0 | entry=MWTable+((runlength/64)-1); |
810 | 0 | else |
811 | 0 | entry=EXTable+(MagickMin((size_t) runlength,2560)-1792)/64; |
812 | 0 | runlength-=(long) entry->count; |
813 | 0 | HuffmanOutputCode(entry); |
814 | 0 | } |
815 | 0 | entry=TWTable+MagickMin((size_t) runlength,63); |
816 | 0 | HuffmanOutputCode(entry); |
817 | 0 | if (n != 0) |
818 | 0 | { |
819 | | /* |
820 | | Output black run. |
821 | | */ |
822 | 0 | for (runlength=0; ((*q != 0) && (n > 0)); n--) |
823 | 0 | { |
824 | 0 | q++; |
825 | 0 | runlength++; |
826 | 0 | } |
827 | 0 | if (runlength >= 64) |
828 | 0 | { |
829 | 0 | entry=MBTable+((runlength/64)-1); |
830 | 0 | if (runlength >= 1792) |
831 | 0 | entry=EXTable+(MagickMin((size_t) runlength,2560)-1792)/64; |
832 | 0 | runlength-=(long) entry->count; |
833 | 0 | HuffmanOutputCode(entry); |
834 | 0 | } |
835 | 0 | entry=TBTable+MagickMin((size_t) runlength,63); |
836 | 0 | HuffmanOutputCode(entry); |
837 | 0 | } |
838 | 0 | } |
839 | | /* |
840 | | End of line. |
841 | | */ |
842 | 0 | for (k=0; k < 11; k++) |
843 | 0 | OutputBit(0); |
844 | 0 | OutputBit(1); |
845 | 0 | q=scanline; |
846 | 0 | if (GetPreviousImageInList(huffman_image) == (Image *) NULL) |
847 | 0 | { |
848 | 0 | proceed=SetImageProgress(huffman_image,LoadImageTag, |
849 | 0 | (MagickOffsetType) y,huffman_image->rows); |
850 | 0 | if (proceed == MagickFalse) |
851 | 0 | break; |
852 | 0 | } |
853 | 0 | } |
854 | | /* |
855 | | End of page. |
856 | | */ |
857 | 0 | for (i=0; i < 6; i++) |
858 | 0 | { |
859 | 0 | for (k=0; k < 11; k++) |
860 | 0 | OutputBit(0); |
861 | 0 | OutputBit(1); |
862 | 0 | } |
863 | | /* |
864 | | Flush bits. |
865 | | */ |
866 | 0 | if (((int) bit != 0x80) != 0) |
867 | 0 | { |
868 | 0 | if (LocaleCompare(image_info->magick,"FAX") == 0) |
869 | 0 | (void) WriteBlobByte(image,byte); |
870 | 0 | else |
871 | 0 | Ascii85Encode(image,byte); |
872 | 0 | } |
873 | 0 | if (LocaleCompare(image_info->magick,"FAX") != 0) |
874 | 0 | Ascii85Flush(image); |
875 | 0 | huffman_image=DestroyImage(huffman_image); |
876 | 0 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
877 | 0 | return(MagickTrue); |
878 | 0 | } |
879 | | |
880 | | /* |
881 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
882 | | % % |
883 | | % % |
884 | | % % |
885 | | % L Z W E n c o d e I m a g e % |
886 | | % % |
887 | | % % |
888 | | % % |
889 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
890 | | % |
891 | | % LZWEncodeImage() compresses an image via LZW-coding specific to Postscript |
892 | | % Level II or Portable Document Format. |
893 | | % |
894 | | % The format of the LZWEncodeImage method is: |
895 | | % |
896 | | % MagickBooleanType LZWEncodeImage(Image *image,const size_t length, |
897 | | % unsigned char *magick_restrict pixels,ExceptionInfo *exception) |
898 | | % |
899 | | % A description of each parameter follows: |
900 | | % |
901 | | % o image: the image. |
902 | | % |
903 | | % o length: A value that specifies the number of pixels to compress. |
904 | | % |
905 | | % o pixels: the address of an unsigned array of characters containing the |
906 | | % pixels to compress. |
907 | | % |
908 | | % o exception: return any errors or warnings in this structure. |
909 | | % |
910 | | */ |
911 | | MagickExport MagickBooleanType LZWEncodeImage(Image *image,const size_t length, |
912 | | unsigned char *magick_restrict pixels,ExceptionInfo *exception) |
913 | 0 | { |
914 | 0 | #define LZWClr 256UL /* Clear Table Marker */ |
915 | 0 | #define LZWEod 257UL /* End of Data marker */ |
916 | 0 | #define OutputCode(code) \ |
917 | 0 | { \ |
918 | 0 | accumulator+=code << (32-code_width-number_bits); \ |
919 | 0 | number_bits+=code_width; \ |
920 | 0 | while (number_bits >= 8) \ |
921 | 0 | { \ |
922 | 0 | (void) WriteBlobByte(image,(unsigned char) (accumulator >> 24)); \ |
923 | 0 | accumulator=accumulator << 8; \ |
924 | 0 | number_bits-=8; \ |
925 | 0 | } \ |
926 | 0 | } |
927 | |
|
928 | 0 | typedef struct _TableType |
929 | 0 | { |
930 | 0 | ssize_t |
931 | 0 | prefix, |
932 | 0 | suffix, |
933 | 0 | next; |
934 | 0 | } TableType; |
935 | |
|
936 | 0 | ssize_t |
937 | 0 | i; |
938 | |
|
939 | 0 | size_t |
940 | 0 | accumulator, |
941 | 0 | number_bits, |
942 | 0 | code_width, |
943 | 0 | last_code, |
944 | 0 | next_index; |
945 | |
|
946 | 0 | ssize_t |
947 | 0 | index; |
948 | |
|
949 | 0 | TableType |
950 | 0 | *table; |
951 | | |
952 | | /* |
953 | | Allocate string table. |
954 | | */ |
955 | 0 | assert(image != (Image *) NULL); |
956 | 0 | assert(image->signature == MagickCoreSignature); |
957 | 0 | assert(pixels != (unsigned char *) NULL); |
958 | 0 | assert(exception != (ExceptionInfo *) NULL); |
959 | 0 | assert(exception->signature == MagickCoreSignature); |
960 | 0 | if (IsEventLogging() != MagickFalse) |
961 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
962 | 0 | table=(TableType *) AcquireQuantumMemory(1UL << 12,sizeof(*table)); |
963 | 0 | if (table == (TableType *) NULL) |
964 | 0 | ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", |
965 | 0 | image->filename); |
966 | | /* |
967 | | Initialize variables. |
968 | | */ |
969 | 0 | accumulator=0; |
970 | 0 | code_width=9; |
971 | 0 | number_bits=0; |
972 | 0 | last_code=0; |
973 | 0 | OutputCode(LZWClr); |
974 | 0 | for (index=0; index < 256; index++) |
975 | 0 | { |
976 | 0 | table[index].prefix=(-1); |
977 | 0 | table[index].suffix=(ssize_t) index; |
978 | 0 | table[index].next=(-1); |
979 | 0 | } |
980 | 0 | next_index=LZWEod+1; |
981 | 0 | code_width=9; |
982 | 0 | last_code=(size_t) pixels[0]; |
983 | 0 | for (i=1; i < (ssize_t) length; i++) |
984 | 0 | { |
985 | | /* |
986 | | Find string. |
987 | | */ |
988 | 0 | index=(ssize_t) last_code; |
989 | 0 | while (index != -1) |
990 | 0 | if ((table[index].prefix != (ssize_t) last_code) || |
991 | 0 | (table[index].suffix != (ssize_t) pixels[i])) |
992 | 0 | index=table[index].next; |
993 | 0 | else |
994 | 0 | { |
995 | 0 | last_code=(size_t) index; |
996 | 0 | break; |
997 | 0 | } |
998 | 0 | if (last_code != (size_t) index) |
999 | 0 | { |
1000 | | /* |
1001 | | Add string. |
1002 | | */ |
1003 | 0 | OutputCode(last_code); |
1004 | 0 | table[next_index].prefix=(ssize_t) last_code; |
1005 | 0 | table[next_index].suffix=(ssize_t) pixels[i]; |
1006 | 0 | table[next_index].next=table[last_code].next; |
1007 | 0 | table[last_code].next=(ssize_t) next_index; |
1008 | 0 | next_index++; |
1009 | | /* |
1010 | | Did we just move up to next bit width? |
1011 | | */ |
1012 | 0 | if ((next_index >> code_width) != 0) |
1013 | 0 | { |
1014 | 0 | code_width++; |
1015 | 0 | if (code_width > 12) |
1016 | 0 | { |
1017 | | /* |
1018 | | Did we overflow the max bit width? |
1019 | | */ |
1020 | 0 | code_width--; |
1021 | 0 | OutputCode(LZWClr); |
1022 | 0 | for (index=0; index < 256; index++) |
1023 | 0 | { |
1024 | 0 | table[index].prefix=(-1); |
1025 | 0 | table[index].suffix=index; |
1026 | 0 | table[index].next=(-1); |
1027 | 0 | } |
1028 | 0 | next_index=LZWEod+1; |
1029 | 0 | code_width=9; |
1030 | 0 | } |
1031 | 0 | } |
1032 | 0 | last_code=(size_t) pixels[i]; |
1033 | 0 | } |
1034 | 0 | } |
1035 | | /* |
1036 | | Flush tables. |
1037 | | */ |
1038 | 0 | OutputCode(last_code); |
1039 | 0 | OutputCode(LZWEod); |
1040 | 0 | if (number_bits != 0) |
1041 | 0 | (void) WriteBlobByte(image,(unsigned char) (accumulator >> 24)); |
1042 | 0 | table=(TableType *) RelinquishMagickMemory(table); |
1043 | 0 | return(MagickTrue); |
1044 | 0 | } |
1045 | | |
1046 | | /* |
1047 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1048 | | % % |
1049 | | % % |
1050 | | % % |
1051 | | % P a c k b i t s E n c o d e I m a g e % |
1052 | | % % |
1053 | | % % |
1054 | | % % |
1055 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1056 | | % |
1057 | | % PackbitsEncodeImage() compresses an image via Macintosh Packbits encoding |
1058 | | % specific to Postscript Level II or Portable Document Format. To ensure |
1059 | | % portability, the binary Packbits bytes are encoded as ASCII Base-85. |
1060 | | % |
1061 | | % The format of the PackbitsEncodeImage method is: |
1062 | | % |
1063 | | % MagickBooleanType PackbitsEncodeImage(Image *image,const size_t length, |
1064 | | % unsigned char *magick_restrict pixels) |
1065 | | % |
1066 | | % A description of each parameter follows: |
1067 | | % |
1068 | | % o image: the image. |
1069 | | % |
1070 | | % o length: A value that specifies the number of pixels to compress. |
1071 | | % |
1072 | | % o pixels: the address of an unsigned array of characters containing the |
1073 | | % pixels to compress. |
1074 | | % |
1075 | | */ |
1076 | | MagickExport MagickBooleanType PackbitsEncodeImage(Image *image, |
1077 | | const size_t length,unsigned char *magick_restrict pixels, |
1078 | | ExceptionInfo *exception) |
1079 | 0 | { |
1080 | 0 | int |
1081 | 0 | count; |
1082 | |
|
1083 | 0 | ssize_t |
1084 | 0 | i, |
1085 | 0 | j; |
1086 | |
|
1087 | 0 | unsigned char |
1088 | 0 | *packbits; |
1089 | | |
1090 | | /* |
1091 | | Compress pixels with Packbits encoding. |
1092 | | */ |
1093 | 0 | assert(image != (Image *) NULL); |
1094 | 0 | assert(image->signature == MagickCoreSignature); |
1095 | 0 | assert(pixels != (unsigned char *) NULL); |
1096 | 0 | if (IsEventLogging() != MagickFalse) |
1097 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
1098 | 0 | packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits)); |
1099 | 0 | if (packbits == (unsigned char *) NULL) |
1100 | 0 | ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", |
1101 | 0 | image->filename); |
1102 | 0 | for (i=(ssize_t) length; i != 0; ) |
1103 | 0 | { |
1104 | 0 | switch (i) |
1105 | 0 | { |
1106 | 0 | case 1: |
1107 | 0 | { |
1108 | 0 | i--; |
1109 | 0 | (void) WriteBlobByte(image,(unsigned char) 0); |
1110 | 0 | (void) WriteBlobByte(image,*pixels); |
1111 | 0 | break; |
1112 | 0 | } |
1113 | 0 | case 2: |
1114 | 0 | { |
1115 | 0 | i-=2; |
1116 | 0 | (void) WriteBlobByte(image,(unsigned char) 1); |
1117 | 0 | (void) WriteBlobByte(image,*pixels); |
1118 | 0 | (void) WriteBlobByte(image,pixels[1]); |
1119 | 0 | break; |
1120 | 0 | } |
1121 | 0 | case 3: |
1122 | 0 | { |
1123 | 0 | i-=3; |
1124 | 0 | if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2))) |
1125 | 0 | { |
1126 | 0 | (void) WriteBlobByte(image,(unsigned char) ((256-3)+1)); |
1127 | 0 | (void) WriteBlobByte(image,*pixels); |
1128 | 0 | break; |
1129 | 0 | } |
1130 | 0 | (void) WriteBlobByte(image,(unsigned char) 2); |
1131 | 0 | (void) WriteBlobByte(image,*pixels); |
1132 | 0 | (void) WriteBlobByte(image,pixels[1]); |
1133 | 0 | (void) WriteBlobByte(image,pixels[2]); |
1134 | 0 | break; |
1135 | 0 | } |
1136 | 0 | default: |
1137 | 0 | { |
1138 | 0 | if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2))) |
1139 | 0 | { |
1140 | | /* |
1141 | | Packed run. |
1142 | | */ |
1143 | 0 | count=3; |
1144 | 0 | while (((ssize_t) count < i) && (*pixels == *(pixels+count))) |
1145 | 0 | { |
1146 | 0 | count++; |
1147 | 0 | if (count >= 127) |
1148 | 0 | break; |
1149 | 0 | } |
1150 | 0 | i-=count; |
1151 | 0 | (void) WriteBlobByte(image,(unsigned char) ((256-count)+1)); |
1152 | 0 | (void) WriteBlobByte(image,*pixels); |
1153 | 0 | pixels+=count; |
1154 | 0 | break; |
1155 | 0 | } |
1156 | | /* |
1157 | | Literal run. |
1158 | | */ |
1159 | 0 | count=0; |
1160 | 0 | while ((*(pixels+count) != *(pixels+count+1)) || |
1161 | 0 | (*(pixels+count+1) != *(pixels+count+2))) |
1162 | 0 | { |
1163 | 0 | packbits[count+1]=pixels[count]; |
1164 | 0 | count++; |
1165 | 0 | if (((ssize_t) count >= (i-3)) || (count >= 127)) |
1166 | 0 | break; |
1167 | 0 | } |
1168 | 0 | i-=count; |
1169 | 0 | *packbits=(unsigned char) (count-1); |
1170 | 0 | for (j=0; j <= (ssize_t) count; j++) |
1171 | 0 | (void) WriteBlobByte(image,packbits[j]); |
1172 | 0 | pixels+=count; |
1173 | 0 | break; |
1174 | 0 | } |
1175 | 0 | } |
1176 | 0 | } |
1177 | 0 | (void) WriteBlobByte(image,(unsigned char) 128); /* EOD marker */ |
1178 | 0 | packbits=(unsigned char *) RelinquishMagickMemory(packbits); |
1179 | 0 | return(MagickTrue); |
1180 | 0 | } |
1181 | | |
1182 | | #if defined(MAGICKCORE_ZLIB_DELEGATE) |
1183 | | /* |
1184 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1185 | | % % |
1186 | | % % |
1187 | | % % |
1188 | | % Z L I B E n c o d e I m a g e % |
1189 | | % % |
1190 | | % % |
1191 | | % % |
1192 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1193 | | % |
1194 | | % ZLIBEncodeImage compresses an image via ZLIB-coding specific to |
1195 | | % Postscript Level II or Portable Document Format. |
1196 | | % |
1197 | | % The format of the ZLIBEncodeImage method is: |
1198 | | % |
1199 | | % MagickBooleanType ZLIBEncodeImage(Image *image,const size_t length, |
1200 | | % unsigned char *magick_restrict pixels,ExceptionInfo *exception) |
1201 | | % |
1202 | | % A description of each parameter follows: |
1203 | | % |
1204 | | % o file: the address of a structure of type FILE. ZLIB encoded pixels |
1205 | | % are written to this file. |
1206 | | % |
1207 | | % o length: A value that specifies the number of pixels to compress. |
1208 | | % |
1209 | | % o pixels: the address of an unsigned array of characters containing the |
1210 | | % pixels to compress. |
1211 | | % |
1212 | | % o exception: return any errors or warnings in this structure. |
1213 | | % |
1214 | | */ |
1215 | | |
1216 | | static voidpf AcquireZIPMemory(voidpf context,unsigned int items, |
1217 | | unsigned int size) |
1218 | 0 | { |
1219 | 0 | (void) context; |
1220 | 0 | return((voidpf) AcquireQuantumMemory(items,size)); |
1221 | 0 | } |
1222 | | |
1223 | | static void RelinquishZIPMemory(voidpf context,voidpf memory) |
1224 | 0 | { |
1225 | 0 | (void) context; |
1226 | 0 | memory=RelinquishMagickMemory(memory); |
1227 | 0 | } |
1228 | | |
1229 | | MagickExport MagickBooleanType ZLIBEncodeImage(Image *image,const size_t length, |
1230 | | unsigned char *magick_restrict pixels,ExceptionInfo *exception) |
1231 | 0 | { |
1232 | 0 | int |
1233 | 0 | status; |
1234 | |
|
1235 | 0 | ssize_t |
1236 | 0 | i; |
1237 | |
|
1238 | 0 | size_t |
1239 | 0 | compress_packets; |
1240 | |
|
1241 | 0 | unsigned char |
1242 | 0 | *compress_pixels; |
1243 | |
|
1244 | 0 | z_stream |
1245 | 0 | stream; |
1246 | |
|
1247 | 0 | assert(image != (Image *) NULL); |
1248 | 0 | assert(image->signature == MagickCoreSignature); |
1249 | 0 | if (IsEventLogging() != MagickFalse) |
1250 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
1251 | 0 | compress_packets=(size_t) (1.001*length+12); |
1252 | 0 | compress_pixels=(unsigned char *) AcquireQuantumMemory(compress_packets, |
1253 | 0 | sizeof(*compress_pixels)); |
1254 | 0 | if (compress_pixels == (unsigned char *) NULL) |
1255 | 0 | ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", |
1256 | 0 | image->filename); |
1257 | 0 | (void) memset(&stream,0,sizeof(stream)); |
1258 | 0 | stream.next_in=pixels; |
1259 | 0 | stream.avail_in=(unsigned int) length; |
1260 | 0 | stream.next_out=compress_pixels; |
1261 | 0 | stream.avail_out=(unsigned int) compress_packets; |
1262 | 0 | stream.zalloc=AcquireZIPMemory; |
1263 | 0 | stream.zfree=RelinquishZIPMemory; |
1264 | 0 | stream.opaque=(voidpf) NULL; |
1265 | 0 | status=deflateInit(&stream,(int) (image->quality == |
1266 | 0 | UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,9))); |
1267 | 0 | if (status == Z_OK) |
1268 | 0 | { |
1269 | 0 | status=deflate(&stream,Z_FINISH); |
1270 | 0 | if (status == Z_STREAM_END) |
1271 | 0 | status=deflateEnd(&stream); |
1272 | 0 | else |
1273 | 0 | (void) deflateEnd(&stream); |
1274 | 0 | compress_packets=(size_t) stream.total_out; |
1275 | 0 | } |
1276 | 0 | if (status != Z_OK) |
1277 | 0 | ThrowBinaryException(CoderError,"UnableToZipCompressImage",image->filename) |
1278 | 0 | for (i=0; i < (ssize_t) compress_packets; i++) |
1279 | 0 | (void) WriteBlobByte(image,compress_pixels[i]); |
1280 | 0 | compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels); |
1281 | 0 | return(MagickTrue); |
1282 | 0 | } |
1283 | | #else |
1284 | | MagickExport MagickBooleanType ZLIBEncodeImage(Image *image, |
1285 | | const size_t magick_unused(length),unsigned char *magick_unused(pixels), |
1286 | | ExceptionInfo *exception) |
1287 | | { |
1288 | | magick_unreferenced(length); |
1289 | | magick_unreferenced(pixels); |
1290 | | assert(image != (Image *) NULL); |
1291 | | assert(image->signature == MagickCoreSignature); |
1292 | | if (IsEventLogging() != MagickFalse) |
1293 | | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
1294 | | (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, |
1295 | | "DelegateLibrarySupportNotBuiltIn","'%s' (ZIP)",image->filename); |
1296 | | return(MagickFalse); |
1297 | | } |
1298 | | #endif |