/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/script/license.php % |
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 *) AcquireMagickMemory(sizeof(*image->ascii85)); |
269 | 0 | if (image->ascii85 == (Ascii85Info *) NULL) |
270 | 0 | ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); |
271 | 0 | (void) memset(image->ascii85,0,sizeof(*image->ascii85)); |
272 | 0 | image->ascii85->line_break=(ssize_t) (MaxLineExtent << 1); |
273 | 0 | image->ascii85->offset=0; |
274 | 0 | } |
275 | | |
276 | | MagickExport void Ascii85Flush(Image *image) |
277 | 0 | { |
278 | 0 | assert(image != (Image *) NULL); |
279 | 0 | assert(image->signature == MagickCoreSignature); |
280 | 0 | assert(image->ascii85 != (Ascii85Info *) NULL); |
281 | 0 | if (IsEventLogging() != MagickFalse) |
282 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
283 | 0 | if (image->ascii85->offset > 0) |
284 | 0 | { |
285 | 0 | image->ascii85->buffer[image->ascii85->offset]='\0'; |
286 | 0 | image->ascii85->buffer[image->ascii85->offset+1]='\0'; |
287 | 0 | image->ascii85->buffer[image->ascii85->offset+2]='\0'; |
288 | 0 | Ascii85Tuple(image->ascii85,image->ascii85->buffer); |
289 | 0 | (void) WriteBlob(image,(size_t) image->ascii85->offset+1, |
290 | 0 | (const unsigned char *) (*image->ascii85->tuple == 'z' ? "!!!!" : |
291 | 0 | image->ascii85->tuple)); |
292 | 0 | } |
293 | 0 | (void) WriteBlobByte(image,'~'); |
294 | 0 | (void) WriteBlobByte(image,'>'); |
295 | 0 | (void) WriteBlobByte(image,'\n'); |
296 | 0 | } |
297 | | |
298 | | MagickExport void Ascii85Encode(Image *image,const unsigned char code) |
299 | 0 | { |
300 | 0 | char |
301 | 0 | *q; |
302 | |
|
303 | 0 | unsigned char |
304 | 0 | *p; |
305 | |
|
306 | 0 | ssize_t |
307 | 0 | n; |
308 | |
|
309 | 0 | assert(image != (Image *) NULL); |
310 | 0 | assert(image->signature == MagickCoreSignature); |
311 | 0 | assert(image->ascii85 != (Ascii85Info *) NULL); |
312 | 0 | image->ascii85->buffer[image->ascii85->offset]=code; |
313 | 0 | image->ascii85->offset++; |
314 | 0 | if (image->ascii85->offset < 4) |
315 | 0 | return; |
316 | 0 | p=image->ascii85->buffer; |
317 | 0 | for (n=image->ascii85->offset; n >= 4; n-=4) |
318 | 0 | { |
319 | 0 | Ascii85Tuple(image->ascii85,p); |
320 | 0 | for (q=image->ascii85->tuple; *q != '\0'; q++) |
321 | 0 | { |
322 | 0 | image->ascii85->line_break--; |
323 | 0 | if ((image->ascii85->line_break < 0) && (*q != '%')) |
324 | 0 | { |
325 | 0 | (void) WriteBlobByte(image,'\n'); |
326 | 0 | image->ascii85->line_break=2*MaxLineExtent; |
327 | 0 | } |
328 | 0 | (void) WriteBlobByte(image,(unsigned char) *q); |
329 | 0 | } |
330 | 0 | p+=(ptrdiff_t) 8; |
331 | 0 | } |
332 | 0 | image->ascii85->offset=n; |
333 | 0 | p-=(ptrdiff_t)4; |
334 | 0 | for (n=0; n < 4; n++) |
335 | 0 | image->ascii85->buffer[n]=(*p++); |
336 | 0 | } |
337 | | |
338 | | /* |
339 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
340 | | % % |
341 | | % % |
342 | | % % |
343 | | % H u f f m a n D e c o d e I m a g e % |
344 | | % % |
345 | | % % |
346 | | % % |
347 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
348 | | % |
349 | | % HuffmanDecodeImage() uncompresses an image via Huffman-coding. |
350 | | % |
351 | | % The format of the HuffmanDecodeImage method is: |
352 | | % |
353 | | % MagickBooleanType HuffmanDecodeImage(Image *image, |
354 | | % ExceptionInfo *exception) |
355 | | % |
356 | | % A description of each parameter follows: |
357 | | % |
358 | | % o image: the image. |
359 | | % |
360 | | % o exception: return any errors or warnings in this structure. |
361 | | % |
362 | | */ |
363 | | MagickExport MagickBooleanType HuffmanDecodeImage(Image *image, |
364 | | ExceptionInfo *exception) |
365 | 26 | { |
366 | 52 | #define HashSize 1021L |
367 | 26 | #define MBHashA 293L |
368 | 26 | #define MBHashB 2695L |
369 | 26 | #define MWHashA 3510L |
370 | 26 | #define MWHashB 1178L |
371 | | |
372 | 26 | #define InitializeHashTable(hash,table,a,b) \ |
373 | 0 | { \ |
374 | 0 | entry=table; \ |
375 | 0 | while (entry->code != 0) \ |
376 | 0 | { \ |
377 | 0 | hash[((entry->length+a)*(entry->code+b)) % HashSize]=(HuffmanTable *) entry; \ |
378 | 0 | entry++; \ |
379 | 0 | } \ |
380 | 0 | } |
381 | | |
382 | 26 | #define InputBit(bit) \ |
383 | 0 | { \ |
384 | 0 | if ((mask & 0xff) == 0) \ |
385 | 0 | { \ |
386 | 0 | byte=ReadBlobByte(image); \ |
387 | 0 | if (byte == EOF) \ |
388 | 0 | break; \ |
389 | 0 | mask=0x80; \ |
390 | 0 | } \ |
391 | 0 | runlength++; \ |
392 | 0 | bit=(size_t) ((byte & mask) != 0 ? 0x01 : 0x00); \ |
393 | 0 | mask>>=1; \ |
394 | 0 | if (bit != 0) \ |
395 | 0 | runlength=0; \ |
396 | 0 | } |
397 | | |
398 | 26 | CacheView |
399 | 26 | *image_view; |
400 | | |
401 | 26 | const HuffmanTable |
402 | 26 | *entry; |
403 | | |
404 | 26 | HuffmanTable |
405 | 26 | **mb_hash, |
406 | 26 | **mw_hash; |
407 | | |
408 | 26 | int |
409 | 26 | byte, |
410 | 26 | mask; |
411 | | |
412 | 26 | MagickBooleanType |
413 | 26 | proceed; |
414 | | |
415 | 26 | Quantum |
416 | 26 | index; |
417 | | |
418 | 26 | size_t |
419 | 26 | bit, |
420 | 26 | code, |
421 | 26 | length, |
422 | 26 | null_lines, |
423 | 26 | runlength; |
424 | | |
425 | 26 | ssize_t |
426 | 26 | count, |
427 | 26 | i, |
428 | 26 | y; |
429 | | |
430 | 26 | unsigned char |
431 | 26 | *p, |
432 | 26 | *scanline; |
433 | | |
434 | 26 | unsigned int |
435 | 26 | bail, |
436 | 26 | color; |
437 | | |
438 | | /* |
439 | | Allocate buffers. |
440 | | */ |
441 | 26 | assert(image != (Image *) NULL); |
442 | 26 | assert(image->signature == MagickCoreSignature); |
443 | 26 | if (IsEventLogging() != MagickFalse) |
444 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
445 | 26 | if (image->blob == (BlobInfo *) NULL) |
446 | 26 | ThrowBinaryException(BlobError,"UnableToOpenBlob",image->filename); |
447 | 26 | mb_hash=(HuffmanTable **) AcquireQuantumMemory(HashSize,sizeof(*mb_hash)); |
448 | 26 | mw_hash=(HuffmanTable **) AcquireQuantumMemory(HashSize,sizeof(*mw_hash)); |
449 | 26 | scanline=(unsigned char *) AcquireQuantumMemory((size_t) image->columns, |
450 | 26 | sizeof(*scanline)); |
451 | 26 | if ((mb_hash == (HuffmanTable **) NULL) || |
452 | 26 | (mw_hash == (HuffmanTable **) NULL) || |
453 | 26 | (scanline == (unsigned char *) NULL)) |
454 | 26 | { |
455 | 26 | if (mb_hash != (HuffmanTable **) NULL) |
456 | 26 | mb_hash=(HuffmanTable **) RelinquishMagickMemory(mb_hash); |
457 | 26 | if (mw_hash != (HuffmanTable **) NULL) |
458 | 26 | mw_hash=(HuffmanTable **) RelinquishMagickMemory(mw_hash); |
459 | 26 | if (scanline != (unsigned char *) NULL) |
460 | 0 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
461 | 26 | ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", |
462 | 26 | image->filename); |
463 | 0 | } |
464 | | /* |
465 | | Initialize Huffman tables. |
466 | | */ |
467 | 0 | for (i=0; i < HashSize; i++) |
468 | 0 | { |
469 | 0 | mb_hash[i]=(HuffmanTable *) NULL; |
470 | 0 | mw_hash[i]=(HuffmanTable *) NULL; |
471 | 0 | } |
472 | 0 | InitializeHashTable(mw_hash,TWTable,MWHashA,MWHashB); |
473 | 0 | InitializeHashTable(mw_hash,MWTable,MWHashA,MWHashB); |
474 | 0 | InitializeHashTable(mw_hash,EXTable,MWHashA,MWHashB); |
475 | 0 | InitializeHashTable(mb_hash,TBTable,MBHashA,MBHashB); |
476 | 0 | InitializeHashTable(mb_hash,MBTable,MBHashA,MBHashB); |
477 | 0 | InitializeHashTable(mb_hash,EXTable,MBHashA,MBHashB); |
478 | | /* |
479 | | Uncompress 1D Huffman to runlength encoded pixels. |
480 | | */ |
481 | 0 | byte=0; |
482 | 0 | mask=0; |
483 | 0 | null_lines=0; |
484 | 0 | runlength=0; |
485 | 0 | while (runlength < 11) |
486 | 0 | InputBit(bit); |
487 | 0 | do { InputBit(bit); } while ((int) bit == 0); |
488 | 0 | image->resolution.x=204.0; |
489 | 0 | image->resolution.y=196.0; |
490 | 0 | image->units=PixelsPerInchResolution; |
491 | 0 | image_view=AcquireAuthenticCacheView(image,exception); |
492 | 0 | for (y=0; ((y < (ssize_t) image->rows) && (null_lines < 3)); ) |
493 | 0 | { |
494 | 0 | Quantum |
495 | 0 | *magick_restrict q; |
496 | |
|
497 | 0 | ssize_t |
498 | 0 | x; |
499 | | |
500 | | /* |
501 | | Initialize scanline to white. |
502 | | */ |
503 | 0 | memset(scanline,0,sizeof(*scanline)*image->columns); |
504 | | /* |
505 | | Decode Huffman encoded scanline. |
506 | | */ |
507 | 0 | color=MagickTrue; |
508 | 0 | code=0; |
509 | 0 | count=0; |
510 | 0 | length=0; |
511 | 0 | runlength=0; |
512 | 0 | x=0; |
513 | 0 | for ( ; ; ) |
514 | 0 | { |
515 | 0 | if (byte == EOF) |
516 | 0 | break; |
517 | 0 | if (x >= (ssize_t) image->columns) |
518 | 0 | { |
519 | 0 | while (runlength < 11) |
520 | 0 | InputBit(bit); |
521 | 0 | do { InputBit(bit); } while ((int) bit == 0); |
522 | 0 | break; |
523 | 0 | } |
524 | 0 | bail=MagickFalse; |
525 | 0 | do |
526 | 0 | { |
527 | 0 | if (runlength < 11) |
528 | 0 | InputBit(bit) |
529 | 0 | else |
530 | 0 | { |
531 | 0 | InputBit(bit); |
532 | 0 | if ((int) bit != 0) |
533 | 0 | { |
534 | 0 | null_lines++; |
535 | 0 | if (x != 0) |
536 | 0 | null_lines=0; |
537 | 0 | bail=MagickTrue; |
538 | 0 | break; |
539 | 0 | } |
540 | 0 | } |
541 | 0 | code=(code << 1)+(size_t) bit; |
542 | 0 | length++; |
543 | 0 | } while (code == 0); |
544 | 0 | if (bail != MagickFalse) |
545 | 0 | break; |
546 | 0 | if (length > 13) |
547 | 0 | { |
548 | 0 | while (runlength < 11) |
549 | 0 | InputBit(bit); |
550 | 0 | do { InputBit(bit); } while ((int) bit == 0); |
551 | 0 | break; |
552 | 0 | } |
553 | 0 | if (color != MagickFalse) |
554 | 0 | { |
555 | 0 | if (length < 4) |
556 | 0 | continue; |
557 | 0 | entry=mw_hash[((length+MWHashA)*(code+MWHashB)) % HashSize]; |
558 | 0 | } |
559 | 0 | else |
560 | 0 | { |
561 | 0 | if (length < 2) |
562 | 0 | continue; |
563 | 0 | entry=mb_hash[((length+MBHashA)*(code+MBHashB)) % HashSize]; |
564 | 0 | } |
565 | 0 | if (entry == (const HuffmanTable *) NULL) |
566 | 0 | continue; |
567 | 0 | if ((entry->length != length) || (entry->code != code)) |
568 | 0 | continue; |
569 | 0 | switch (entry->id) |
570 | 0 | { |
571 | 0 | case TWId: |
572 | 0 | case TBId: |
573 | 0 | { |
574 | 0 | count+=(ssize_t) entry->count; |
575 | 0 | if ((x+count) > (ssize_t) image->columns) |
576 | 0 | count=(ssize_t) image->columns-x; |
577 | 0 | if (count > 0) |
578 | 0 | { |
579 | 0 | if (color != MagickFalse) |
580 | 0 | { |
581 | 0 | x+=count; |
582 | 0 | count=0; |
583 | 0 | } |
584 | 0 | else |
585 | 0 | for ( ; count > 0; count--) |
586 | 0 | if ((x >= 0) && (x < (ssize_t) image->columns)) |
587 | 0 | scanline[x++]=(unsigned char) 1; |
588 | 0 | } |
589 | 0 | color=(unsigned int) |
590 | 0 | ((color == MagickFalse) ? MagickTrue : MagickFalse); |
591 | 0 | break; |
592 | 0 | } |
593 | 0 | case MWId: |
594 | 0 | case MBId: |
595 | 0 | case EXId: |
596 | 0 | { |
597 | 0 | count+=(ssize_t) entry->count; |
598 | 0 | break; |
599 | 0 | } |
600 | 0 | default: |
601 | 0 | break; |
602 | 0 | } |
603 | 0 | code=0; |
604 | 0 | length=0; |
605 | 0 | } |
606 | | /* |
607 | | Transfer scanline to image pixels. |
608 | | */ |
609 | 0 | p=scanline; |
610 | 0 | q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception); |
611 | 0 | if (q == (Quantum *) NULL) |
612 | 0 | break; |
613 | 0 | for (x=0; x < (ssize_t) image->columns; x++) |
614 | 0 | { |
615 | 0 | index=(Quantum) (*p++); |
616 | 0 | SetPixelIndex(image,index,q); |
617 | 0 | SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q); |
618 | 0 | q+=(ptrdiff_t) GetPixelChannels(image); |
619 | 0 | } |
620 | 0 | if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse) |
621 | 0 | break; |
622 | 0 | proceed=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, |
623 | 0 | image->rows); |
624 | 0 | if (proceed == MagickFalse) |
625 | 0 | break; |
626 | 0 | y++; |
627 | 0 | } |
628 | 0 | image_view=DestroyCacheView(image_view); |
629 | 0 | image->rows=(size_t) MagickMax((size_t) y-3,1); |
630 | 0 | image->compression=FaxCompression; |
631 | | /* |
632 | | Free decoder memory. |
633 | | */ |
634 | 0 | mw_hash=(HuffmanTable **) RelinquishMagickMemory(mw_hash); |
635 | 0 | mb_hash=(HuffmanTable **) RelinquishMagickMemory(mb_hash); |
636 | 0 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
637 | 0 | return(MagickTrue); |
638 | 0 | } |
639 | | |
640 | | /* |
641 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
642 | | % % |
643 | | % % |
644 | | % % |
645 | | % H u f f m a n E n c o d e I m a g e % |
646 | | % % |
647 | | % % |
648 | | % % |
649 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
650 | | % |
651 | | % HuffmanEncodeImage() compresses an image via Huffman-coding. |
652 | | % |
653 | | % The format of the HuffmanEncodeImage method is: |
654 | | % |
655 | | % MagickBooleanType HuffmanEncodeImage(const ImageInfo *image_info, |
656 | | % Image *image,Image *inject_image,ExceptionInfo *exception) |
657 | | % |
658 | | % A description of each parameter follows: |
659 | | % |
660 | | % o image_info: the image info.. |
661 | | % |
662 | | % o image: the image. |
663 | | % |
664 | | % o inject_image: inject into the image stream. |
665 | | % |
666 | | % o exception: return any errors or warnings in this structure. |
667 | | % |
668 | | */ |
669 | | MagickExport MagickBooleanType HuffmanEncodeImage(const ImageInfo *image_info, |
670 | | Image *image,Image *inject_image,ExceptionInfo *exception) |
671 | 0 | { |
672 | 0 | #define HuffmanOutputCode(entry) \ |
673 | 0 | { \ |
674 | 0 | mask=one << (entry->length-1); \ |
675 | 0 | while (mask != 0) \ |
676 | 0 | { \ |
677 | 0 | OutputBit(((entry->code & mask) != 0 ? 1 : 0)); \ |
678 | 0 | mask>>=1; \ |
679 | 0 | } \ |
680 | 0 | } |
681 | |
|
682 | 0 | #define OutputBit(count) \ |
683 | 0 | { \ |
684 | 0 | DisableMSCWarning(4127) \ |
685 | 0 | if (count > 0) \ |
686 | 0 | byte=byte | bit; \ |
687 | 0 | RestoreMSCWarning \ |
688 | 0 | bit>>=1; \ |
689 | 0 | if ((int) (bit & 0xff) == 0) \ |
690 | 0 | { \ |
691 | 0 | if (LocaleCompare(image_info->magick,"FAX") == 0) \ |
692 | 0 | (void) WriteBlobByte(image,(unsigned char) byte); \ |
693 | 0 | else \ |
694 | 0 | Ascii85Encode(image,byte); \ |
695 | 0 | byte='\0'; \ |
696 | 0 | bit=(unsigned char) 0x80; \ |
697 | 0 | } \ |
698 | 0 | } |
699 | |
|
700 | 0 | const HuffmanTable |
701 | 0 | *entry; |
702 | |
|
703 | 0 | int |
704 | 0 | k, |
705 | 0 | runlength; |
706 | |
|
707 | 0 | Image |
708 | 0 | *huffman_image; |
709 | |
|
710 | 0 | MagickBooleanType |
711 | 0 | proceed; |
712 | |
|
713 | 0 | ssize_t |
714 | 0 | i, |
715 | 0 | x; |
716 | |
|
717 | 0 | const Quantum |
718 | 0 | *p; |
719 | |
|
720 | 0 | unsigned char |
721 | 0 | *q; |
722 | |
|
723 | 0 | size_t |
724 | 0 | mask, |
725 | 0 | one, |
726 | 0 | width; |
727 | |
|
728 | 0 | ssize_t |
729 | 0 | n, |
730 | 0 | y; |
731 | |
|
732 | 0 | unsigned char |
733 | 0 | byte, |
734 | 0 | bit, |
735 | 0 | *scanline; |
736 | | |
737 | | /* |
738 | | Allocate scanline buffer. |
739 | | */ |
740 | 0 | assert(image_info != (ImageInfo *) NULL); |
741 | 0 | assert(image_info->signature == MagickCoreSignature); |
742 | 0 | assert(image != (Image *) NULL); |
743 | 0 | assert(image->signature == MagickCoreSignature); |
744 | 0 | if (IsEventLogging() != MagickFalse) |
745 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
746 | 0 | assert(inject_image != (Image *) NULL); |
747 | 0 | assert(inject_image->signature == MagickCoreSignature); |
748 | 0 | one=1; |
749 | 0 | width=inject_image->columns; |
750 | 0 | if (LocaleCompare(image_info->magick,"FAX") == 0) |
751 | 0 | width=(size_t) MagickMax(inject_image->columns,1728); |
752 | 0 | scanline=(unsigned char *) AcquireQuantumMemory((size_t) width+1UL, |
753 | 0 | sizeof(*scanline)); |
754 | 0 | if (scanline == (unsigned char *) NULL) |
755 | 0 | ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", |
756 | 0 | inject_image->filename); |
757 | 0 | (void) memset(scanline,0,width*sizeof(*scanline)); |
758 | 0 | huffman_image=CloneImage(inject_image,0,0,MagickTrue,exception); |
759 | 0 | if (huffman_image == (Image *) NULL) |
760 | 0 | { |
761 | 0 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
762 | 0 | return(MagickFalse); |
763 | 0 | } |
764 | 0 | (void) SetImageType(huffman_image,BilevelType,exception); |
765 | 0 | byte='\0'; |
766 | 0 | bit=(unsigned char) 0x80; |
767 | 0 | if (LocaleCompare(image_info->magick,"FAX") != 0) |
768 | 0 | Ascii85Initialize(image); |
769 | 0 | else |
770 | 0 | { |
771 | | /* |
772 | | End of line. |
773 | | */ |
774 | 0 | for (k=0; k < 11; k++) |
775 | 0 | OutputBit(0); |
776 | 0 | OutputBit(1); |
777 | 0 | } |
778 | | /* |
779 | | Compress to 1D Huffman pixels. |
780 | | */ |
781 | 0 | q=scanline; |
782 | 0 | for (y=0; y < (ssize_t) huffman_image->rows; y++) |
783 | 0 | { |
784 | 0 | p=GetVirtualPixels(huffman_image,0,y,huffman_image->columns,1,exception); |
785 | 0 | if (p == (const Quantum *) NULL) |
786 | 0 | break; |
787 | 0 | for (x=0; x < (ssize_t) huffman_image->columns; x++) |
788 | 0 | { |
789 | 0 | *q++=(unsigned char) (GetPixelIntensity(huffman_image,p) >= |
790 | 0 | ((double) QuantumRange/2.0) ? 0 : 1); |
791 | 0 | p+=(ptrdiff_t) GetPixelChannels(huffman_image); |
792 | 0 | } |
793 | | /* |
794 | | Huffman encode scanline. |
795 | | */ |
796 | 0 | q=scanline; |
797 | 0 | for (n=(ssize_t) width; n > 0; ) |
798 | 0 | { |
799 | | /* |
800 | | Output white run. |
801 | | */ |
802 | 0 | for (runlength=0; ((n > 0) && (*q == 0)); n--) |
803 | 0 | { |
804 | 0 | q++; |
805 | 0 | runlength++; |
806 | 0 | } |
807 | 0 | if (runlength >= 64) |
808 | 0 | { |
809 | 0 | if (runlength < 1792) |
810 | 0 | entry=MWTable+((runlength/64)-1); |
811 | 0 | else |
812 | 0 | entry=EXTable+(MagickMin((size_t) runlength,2560)-1792)/64; |
813 | 0 | runlength-=(long) entry->count; |
814 | 0 | HuffmanOutputCode(entry); |
815 | 0 | } |
816 | 0 | entry=TWTable+MagickMin((size_t) runlength,63); |
817 | 0 | HuffmanOutputCode(entry); |
818 | 0 | if (n != 0) |
819 | 0 | { |
820 | | /* |
821 | | Output black run. |
822 | | */ |
823 | 0 | for (runlength=0; ((*q != 0) && (n > 0)); n--) |
824 | 0 | { |
825 | 0 | q++; |
826 | 0 | runlength++; |
827 | 0 | } |
828 | 0 | if (runlength >= 64) |
829 | 0 | { |
830 | 0 | entry=MBTable+((runlength/64)-1); |
831 | 0 | if (runlength >= 1792) |
832 | 0 | entry=EXTable+(MagickMin((size_t) runlength,2560)-1792)/64; |
833 | 0 | runlength-=(long) entry->count; |
834 | 0 | HuffmanOutputCode(entry); |
835 | 0 | } |
836 | 0 | entry=TBTable+MagickMin((size_t) runlength,63); |
837 | 0 | HuffmanOutputCode(entry); |
838 | 0 | } |
839 | 0 | } |
840 | | /* |
841 | | End of line. |
842 | | */ |
843 | 0 | for (k=0; k < 11; k++) |
844 | 0 | OutputBit(0); |
845 | 0 | OutputBit(1); |
846 | 0 | q=scanline; |
847 | 0 | if (GetPreviousImageInList(huffman_image) == (Image *) NULL) |
848 | 0 | { |
849 | 0 | proceed=SetImageProgress(huffman_image,LoadImageTag, |
850 | 0 | (MagickOffsetType) y,huffman_image->rows); |
851 | 0 | if (proceed == MagickFalse) |
852 | 0 | break; |
853 | 0 | } |
854 | 0 | } |
855 | | /* |
856 | | End of page. |
857 | | */ |
858 | 0 | for (i=0; i < 6; i++) |
859 | 0 | { |
860 | 0 | for (k=0; k < 11; k++) |
861 | 0 | OutputBit(0); |
862 | 0 | OutputBit(1); |
863 | 0 | } |
864 | | /* |
865 | | Flush bits. |
866 | | */ |
867 | 0 | if (((int) bit != 0x80) != 0) |
868 | 0 | { |
869 | 0 | if (LocaleCompare(image_info->magick,"FAX") == 0) |
870 | 0 | (void) WriteBlobByte(image,byte); |
871 | 0 | else |
872 | 0 | Ascii85Encode(image,byte); |
873 | 0 | } |
874 | 0 | if (LocaleCompare(image_info->magick,"FAX") != 0) |
875 | 0 | Ascii85Flush(image); |
876 | 0 | huffman_image=DestroyImage(huffman_image); |
877 | 0 | scanline=(unsigned char *) RelinquishMagickMemory(scanline); |
878 | 0 | return(MagickTrue); |
879 | 0 | } |
880 | | |
881 | | /* |
882 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
883 | | % % |
884 | | % % |
885 | | % % |
886 | | % L Z W E n c o d e I m a g e % |
887 | | % % |
888 | | % % |
889 | | % % |
890 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
891 | | % |
892 | | % LZWEncodeImage() compresses an image via LZW-coding specific to Postscript |
893 | | % Level II or Portable Document Format. |
894 | | % |
895 | | % The format of the LZWEncodeImage method is: |
896 | | % |
897 | | % MagickBooleanType LZWEncodeImage(Image *image,const size_t length, |
898 | | % unsigned char *magick_restrict pixels,ExceptionInfo *exception) |
899 | | % |
900 | | % A description of each parameter follows: |
901 | | % |
902 | | % o image: the image. |
903 | | % |
904 | | % o length: A value that specifies the number of pixels to compress. |
905 | | % |
906 | | % o pixels: the address of an unsigned array of characters containing the |
907 | | % pixels to compress. |
908 | | % |
909 | | % o exception: return any errors or warnings in this structure. |
910 | | % |
911 | | */ |
912 | | MagickExport MagickBooleanType LZWEncodeImage(Image *image,const size_t length, |
913 | | unsigned char *magick_restrict pixels,ExceptionInfo *exception) |
914 | 0 | { |
915 | 0 | #define LZWClr 256UL /* Clear Table Marker */ |
916 | 0 | #define LZWEod 257UL /* End of Data marker */ |
917 | 0 | #define OutputCode(code) \ |
918 | 0 | { \ |
919 | 0 | accumulator+=code << (32-code_width-number_bits); \ |
920 | 0 | number_bits+=code_width; \ |
921 | 0 | while (number_bits >= 8) \ |
922 | 0 | { \ |
923 | 0 | (void) WriteBlobByte(image,(unsigned char) (accumulator >> 24)); \ |
924 | 0 | accumulator=accumulator << 8; \ |
925 | 0 | number_bits-=8; \ |
926 | 0 | } \ |
927 | 0 | } |
928 | |
|
929 | 0 | typedef struct _TableType |
930 | 0 | { |
931 | 0 | ssize_t |
932 | 0 | prefix, |
933 | 0 | suffix, |
934 | 0 | next; |
935 | 0 | } TableType; |
936 | |
|
937 | 0 | ssize_t |
938 | 0 | i; |
939 | |
|
940 | 0 | size_t |
941 | 0 | accumulator, |
942 | 0 | number_bits, |
943 | 0 | code_width, |
944 | 0 | last_code, |
945 | 0 | next_index; |
946 | |
|
947 | 0 | ssize_t |
948 | 0 | index; |
949 | |
|
950 | 0 | TableType |
951 | 0 | *table; |
952 | | |
953 | | /* |
954 | | Allocate string table. |
955 | | */ |
956 | 0 | assert(image != (Image *) NULL); |
957 | 0 | assert(image->signature == MagickCoreSignature); |
958 | 0 | assert(pixels != (unsigned char *) NULL); |
959 | 0 | assert(exception != (ExceptionInfo *) NULL); |
960 | 0 | assert(exception->signature == MagickCoreSignature); |
961 | 0 | if (IsEventLogging() != MagickFalse) |
962 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
963 | 0 | table=(TableType *) AcquireQuantumMemory(1UL << 12,sizeof(*table)); |
964 | 0 | if (table == (TableType *) NULL) |
965 | 0 | ThrowBinaryException(ResourceLimitWarning,"MemoryAllocationFailed", |
966 | 0 | image->filename); |
967 | | /* |
968 | | Initialize variables. |
969 | | */ |
970 | 0 | accumulator=0; |
971 | 0 | code_width=9; |
972 | 0 | number_bits=0; |
973 | 0 | last_code=0; |
974 | 0 | OutputCode(LZWClr); |
975 | 0 | for (index=0; index < 256; index++) |
976 | 0 | { |
977 | 0 | table[index].prefix=(-1); |
978 | 0 | table[index].suffix=(ssize_t) index; |
979 | 0 | table[index].next=(-1); |
980 | 0 | } |
981 | 0 | next_index=LZWEod+1; |
982 | 0 | code_width=9; |
983 | 0 | last_code=(size_t) pixels[0]; |
984 | 0 | for (i=1; i < (ssize_t) length; i++) |
985 | 0 | { |
986 | | /* |
987 | | Find string. |
988 | | */ |
989 | 0 | index=(ssize_t) last_code; |
990 | 0 | while (index != -1) |
991 | 0 | if ((table[index].prefix != (ssize_t) last_code) || |
992 | 0 | (table[index].suffix != (ssize_t) pixels[i])) |
993 | 0 | index=table[index].next; |
994 | 0 | else |
995 | 0 | { |
996 | 0 | last_code=(size_t) index; |
997 | 0 | break; |
998 | 0 | } |
999 | 0 | if (last_code != (size_t) index) |
1000 | 0 | { |
1001 | | /* |
1002 | | Add string. |
1003 | | */ |
1004 | 0 | OutputCode(last_code); |
1005 | 0 | table[next_index].prefix=(ssize_t) last_code; |
1006 | 0 | table[next_index].suffix=(ssize_t) pixels[i]; |
1007 | 0 | table[next_index].next=table[last_code].next; |
1008 | 0 | table[last_code].next=(ssize_t) next_index; |
1009 | 0 | next_index++; |
1010 | | /* |
1011 | | Did we just move up to next bit width? |
1012 | | */ |
1013 | 0 | if ((next_index >> code_width) != 0) |
1014 | 0 | { |
1015 | 0 | code_width++; |
1016 | 0 | if (code_width > 12) |
1017 | 0 | { |
1018 | | /* |
1019 | | Did we overflow the max bit width? |
1020 | | */ |
1021 | 0 | code_width--; |
1022 | 0 | OutputCode(LZWClr); |
1023 | 0 | for (index=0; index < 256; index++) |
1024 | 0 | { |
1025 | 0 | table[index].prefix=(-1); |
1026 | 0 | table[index].suffix=index; |
1027 | 0 | table[index].next=(-1); |
1028 | 0 | } |
1029 | 0 | next_index=LZWEod+1; |
1030 | 0 | code_width=9; |
1031 | 0 | } |
1032 | 0 | } |
1033 | 0 | last_code=(size_t) pixels[i]; |
1034 | 0 | } |
1035 | 0 | } |
1036 | | /* |
1037 | | Flush tables. |
1038 | | */ |
1039 | 0 | OutputCode(last_code); |
1040 | 0 | OutputCode(LZWEod); |
1041 | 0 | if (number_bits != 0) |
1042 | 0 | (void) WriteBlobByte(image,(unsigned char) (accumulator >> 24)); |
1043 | 0 | table=(TableType *) RelinquishMagickMemory(table); |
1044 | 0 | return(MagickTrue); |
1045 | 0 | } |
1046 | | |
1047 | | /* |
1048 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1049 | | % % |
1050 | | % % |
1051 | | % % |
1052 | | % P a c k b i t s E n c o d e I m a g e % |
1053 | | % % |
1054 | | % % |
1055 | | % % |
1056 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1057 | | % |
1058 | | % PackbitsEncodeImage() compresses an image via Macintosh Packbits encoding |
1059 | | % specific to Postscript Level II or Portable Document Format. To ensure |
1060 | | % portability, the binary Packbits bytes are encoded as ASCII Base-85. |
1061 | | % |
1062 | | % The format of the PackbitsEncodeImage method is: |
1063 | | % |
1064 | | % MagickBooleanType PackbitsEncodeImage(Image *image,const size_t length, |
1065 | | % unsigned char *magick_restrict pixels) |
1066 | | % |
1067 | | % A description of each parameter follows: |
1068 | | % |
1069 | | % o image: the image. |
1070 | | % |
1071 | | % o length: A value that specifies the number of pixels to compress. |
1072 | | % |
1073 | | % o pixels: the address of an unsigned array of characters containing the |
1074 | | % pixels to compress. |
1075 | | % |
1076 | | */ |
1077 | | MagickExport MagickBooleanType PackbitsEncodeImage(Image *image, |
1078 | | const size_t length,unsigned char *magick_restrict pixels, |
1079 | | ExceptionInfo *exception) |
1080 | 0 | { |
1081 | 0 | int |
1082 | 0 | count; |
1083 | |
|
1084 | 0 | ssize_t |
1085 | 0 | i, |
1086 | 0 | j; |
1087 | |
|
1088 | 0 | unsigned char |
1089 | 0 | *packbits; |
1090 | | |
1091 | | /* |
1092 | | Compress pixels with Packbits encoding. |
1093 | | */ |
1094 | 0 | assert(image != (Image *) NULL); |
1095 | 0 | assert(image->signature == MagickCoreSignature); |
1096 | 0 | assert(pixels != (unsigned char *) NULL); |
1097 | 0 | if (IsEventLogging() != MagickFalse) |
1098 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
1099 | 0 | packbits=(unsigned char *) AcquireQuantumMemory(128UL,sizeof(*packbits)); |
1100 | 0 | if (packbits == (unsigned char *) NULL) |
1101 | 0 | ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", |
1102 | 0 | image->filename); |
1103 | 0 | for (i=(ssize_t) length; i != 0; ) |
1104 | 0 | { |
1105 | 0 | switch (i) |
1106 | 0 | { |
1107 | 0 | case 1: |
1108 | 0 | { |
1109 | 0 | i--; |
1110 | 0 | (void) WriteBlobByte(image,(unsigned char) 0); |
1111 | 0 | (void) WriteBlobByte(image,*pixels); |
1112 | 0 | break; |
1113 | 0 | } |
1114 | 0 | case 2: |
1115 | 0 | { |
1116 | 0 | i-=2; |
1117 | 0 | (void) WriteBlobByte(image,(unsigned char) 1); |
1118 | 0 | (void) WriteBlobByte(image,*pixels); |
1119 | 0 | (void) WriteBlobByte(image,pixels[1]); |
1120 | 0 | break; |
1121 | 0 | } |
1122 | 0 | case 3: |
1123 | 0 | { |
1124 | 0 | i-=3; |
1125 | 0 | if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2))) |
1126 | 0 | { |
1127 | 0 | (void) WriteBlobByte(image,(unsigned char) ((256-3)+1)); |
1128 | 0 | (void) WriteBlobByte(image,*pixels); |
1129 | 0 | break; |
1130 | 0 | } |
1131 | 0 | (void) WriteBlobByte(image,(unsigned char) 2); |
1132 | 0 | (void) WriteBlobByte(image,*pixels); |
1133 | 0 | (void) WriteBlobByte(image,pixels[1]); |
1134 | 0 | (void) WriteBlobByte(image,pixels[2]); |
1135 | 0 | break; |
1136 | 0 | } |
1137 | 0 | default: |
1138 | 0 | { |
1139 | 0 | if ((*pixels == *(pixels+1)) && (*(pixels+1) == *(pixels+2))) |
1140 | 0 | { |
1141 | | /* |
1142 | | Packed run. |
1143 | | */ |
1144 | 0 | count=3; |
1145 | 0 | while (((ssize_t) count < i) && (*pixels == *(pixels+count))) |
1146 | 0 | { |
1147 | 0 | count++; |
1148 | 0 | if (count >= 127) |
1149 | 0 | break; |
1150 | 0 | } |
1151 | 0 | i-=count; |
1152 | 0 | (void) WriteBlobByte(image,(unsigned char) ((256-count)+1)); |
1153 | 0 | (void) WriteBlobByte(image,*pixels); |
1154 | 0 | pixels+=count; |
1155 | 0 | break; |
1156 | 0 | } |
1157 | | /* |
1158 | | Literal run. |
1159 | | */ |
1160 | 0 | count=0; |
1161 | 0 | while ((*(pixels+count) != *(pixels+count+1)) || |
1162 | 0 | (*(pixels+count+1) != *(pixels+count+2))) |
1163 | 0 | { |
1164 | 0 | packbits[count+1]=pixels[count]; |
1165 | 0 | count++; |
1166 | 0 | if (((ssize_t) count >= (i-3)) || (count >= 127)) |
1167 | 0 | break; |
1168 | 0 | } |
1169 | 0 | i-=count; |
1170 | 0 | *packbits=(unsigned char) (count-1); |
1171 | 0 | for (j=0; j <= (ssize_t) count; j++) |
1172 | 0 | (void) WriteBlobByte(image,packbits[j]); |
1173 | 0 | pixels+=count; |
1174 | 0 | break; |
1175 | 0 | } |
1176 | 0 | } |
1177 | 0 | } |
1178 | 0 | (void) WriteBlobByte(image,(unsigned char) 128); /* EOD marker */ |
1179 | 0 | packbits=(unsigned char *) RelinquishMagickMemory(packbits); |
1180 | 0 | return(MagickTrue); |
1181 | 0 | } |
1182 | | |
1183 | | #if defined(MAGICKCORE_ZLIB_DELEGATE) |
1184 | | /* |
1185 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1186 | | % % |
1187 | | % % |
1188 | | % % |
1189 | | % Z L I B E n c o d e I m a g e % |
1190 | | % % |
1191 | | % % |
1192 | | % % |
1193 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1194 | | % |
1195 | | % ZLIBEncodeImage compresses an image via ZLIB-coding specific to |
1196 | | % Postscript Level II or Portable Document Format. |
1197 | | % |
1198 | | % The format of the ZLIBEncodeImage method is: |
1199 | | % |
1200 | | % MagickBooleanType ZLIBEncodeImage(Image *image,const size_t length, |
1201 | | % unsigned char *magick_restrict pixels,ExceptionInfo *exception) |
1202 | | % |
1203 | | % A description of each parameter follows: |
1204 | | % |
1205 | | % o file: the address of a structure of type FILE. ZLIB encoded pixels |
1206 | | % are written to this file. |
1207 | | % |
1208 | | % o length: A value that specifies the number of pixels to compress. |
1209 | | % |
1210 | | % o pixels: the address of an unsigned array of characters containing the |
1211 | | % pixels to compress. |
1212 | | % |
1213 | | % o exception: return any errors or warnings in this structure. |
1214 | | % |
1215 | | */ |
1216 | | |
1217 | | static voidpf AcquireZIPMemory(voidpf context,unsigned int items, |
1218 | | unsigned int size) |
1219 | 0 | { |
1220 | 0 | (void) context; |
1221 | 0 | return((voidpf) AcquireQuantumMemory(items,size)); |
1222 | 0 | } |
1223 | | |
1224 | | static void RelinquishZIPMemory(voidpf context,voidpf memory) |
1225 | 0 | { |
1226 | 0 | (void) context; |
1227 | 0 | memory=RelinquishMagickMemory(memory); |
1228 | 0 | } |
1229 | | |
1230 | | MagickExport MagickBooleanType ZLIBEncodeImage(Image *image,const size_t length, |
1231 | | unsigned char *magick_restrict pixels,ExceptionInfo *exception) |
1232 | 0 | { |
1233 | 0 | int |
1234 | 0 | status; |
1235 | |
|
1236 | 0 | ssize_t |
1237 | 0 | i; |
1238 | |
|
1239 | 0 | size_t |
1240 | 0 | compress_packets; |
1241 | |
|
1242 | 0 | unsigned char |
1243 | 0 | *compress_pixels; |
1244 | |
|
1245 | 0 | z_stream |
1246 | 0 | stream; |
1247 | |
|
1248 | 0 | assert(image != (Image *) NULL); |
1249 | 0 | assert(image->signature == MagickCoreSignature); |
1250 | 0 | if (IsEventLogging() != MagickFalse) |
1251 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
1252 | 0 | compress_packets=(size_t) (1.001*length+12); |
1253 | 0 | compress_pixels=(unsigned char *) AcquireQuantumMemory(compress_packets, |
1254 | 0 | sizeof(*compress_pixels)); |
1255 | 0 | if (compress_pixels == (unsigned char *) NULL) |
1256 | 0 | ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", |
1257 | 0 | image->filename); |
1258 | 0 | (void) memset(&stream,0,sizeof(stream)); |
1259 | 0 | stream.next_in=pixels; |
1260 | 0 | stream.avail_in=(unsigned int) length; |
1261 | 0 | stream.next_out=compress_pixels; |
1262 | 0 | stream.avail_out=(unsigned int) compress_packets; |
1263 | 0 | stream.zalloc=AcquireZIPMemory; |
1264 | 0 | stream.zfree=RelinquishZIPMemory; |
1265 | 0 | stream.opaque=(voidpf) NULL; |
1266 | 0 | status=deflateInit(&stream,(int) (image->quality == |
1267 | 0 | UndefinedCompressionQuality ? 7 : MagickMin(image->quality/10,9))); |
1268 | 0 | if (status == Z_OK) |
1269 | 0 | { |
1270 | 0 | status=deflate(&stream,Z_FINISH); |
1271 | 0 | if (status == Z_STREAM_END) |
1272 | 0 | status=deflateEnd(&stream); |
1273 | 0 | else |
1274 | 0 | (void) deflateEnd(&stream); |
1275 | 0 | compress_packets=(size_t) stream.total_out; |
1276 | 0 | } |
1277 | 0 | if (status != Z_OK) |
1278 | 0 | ThrowBinaryException(CoderError,"UnableToZipCompressImage",image->filename) |
1279 | 0 | for (i=0; i < (ssize_t) compress_packets; i++) |
1280 | 0 | (void) WriteBlobByte(image,compress_pixels[i]); |
1281 | 0 | compress_pixels=(unsigned char *) RelinquishMagickMemory(compress_pixels); |
1282 | 0 | return(MagickTrue); |
1283 | 0 | } |
1284 | | #else |
1285 | | MagickExport MagickBooleanType ZLIBEncodeImage(Image *image, |
1286 | | const size_t magick_unused(length),unsigned char *magick_unused(pixels), |
1287 | | ExceptionInfo *exception) |
1288 | | { |
1289 | | magick_unreferenced(length); |
1290 | | magick_unreferenced(pixels); |
1291 | | assert(image != (Image *) NULL); |
1292 | | assert(image->signature == MagickCoreSignature); |
1293 | | if (IsEventLogging() != MagickFalse) |
1294 | | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); |
1295 | | (void) ThrowMagickException(exception,GetMagickModule(),MissingDelegateError, |
1296 | | "DelegateLibrarySupportNotBuiltIn","'%s' (ZIP)",image->filename); |
1297 | | return(MagickFalse); |
1298 | | } |
1299 | | #endif |