blob: 4fc1babedf5e708ccb4f8918a5d15cddd0ba4d3b [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% JJJJJ BBBB IIIII GGGG %
7% J B B I G %
8% J BBBB I G GG %
9% J J B B I G G %
10% JJJ BBBB IIIII GGG %
11% %
12% %
13% Read/Write JBIG Image Format %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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% http://www.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 Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/cache.h"
46#include "magick/color-private.h"
cristyf4cf3072010-04-25 20:07:02 +000047#include "magick/colormap.h"
cristy3ed852e2009-09-05 21:47:34 +000048#include "magick/colorspace.h"
49#include "magick/constitute.h"
50#include "magick/exception.h"
51#include "magick/exception-private.h"
52#include "magick/geometry.h"
53#include "magick/image.h"
54#include "magick/image-private.h"
55#include "magick/list.h"
56#include "magick/magick.h"
57#include "magick/memory_.h"
58#include "magick/monitor.h"
59#include "magick/monitor-private.h"
60#include "magick/nt-feature.h"
61#include "magick/quantum-private.h"
62#include "magick/static.h"
63#include "magick/string_.h"
64#include "magick/module.h"
65#if defined(MAGICKCORE_JBIG_DELEGATE)
66#include "jbig.h"
67#endif
68
69/*
70 Forward declarations.
71*/
72#if defined(MAGICKCORE_JBIG_DELEGATE)
73static MagickBooleanType
74 WriteJBIGImage(const ImageInfo *,Image *);
75#endif
76
77#if defined(MAGICKCORE_JBIG_DELEGATE)
78/*
79%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80% %
81% %
82% %
83% R e a d J B I G I m a g e %
84% %
85% %
86% %
87%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88%
89% ReadJBIGImage() reads a JBIG image file and returns it. It
90% allocates the memory necessary for the new Image structure and returns a
91% pointer to the new image.
92%
93% The format of the ReadJBIGImage method is:
94%
95% Image *ReadJBIGImage(const ImageInfo *image_info,
96% ExceptionInfo *exception)
97%
98% A description of each parameter follows:
99%
100% o image_info: the image info.
101%
102% o exception: return any errors or warnings in this structure.
103%
104*/
105static Image *ReadJBIGImage(const ImageInfo *image_info,
106 ExceptionInfo *exception)
107{
108 Image
109 *image;
110
111 IndexPacket
112 index;
113
cristy3ed852e2009-09-05 21:47:34 +0000114 MagickBooleanType
115 status;
116
117 register IndexPacket
118 *indexes;
119
cristybb503372010-05-27 20:51:26 +0000120 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000121 x;
122
123 register PixelPacket
124 *q;
125
126 register unsigned char
127 *p;
128
129 ssize_t
cristy524222d2011-04-25 00:37:06 +0000130 count,
131 length,
132 y;
cristy3ed852e2009-09-05 21:47:34 +0000133
134 struct jbg_dec_state
135 jbig_info;
136
137 unsigned char
138 bit,
139 *buffer,
140 byte;
141
142 /*
143 Open image file.
144 */
145 assert(image_info != (const ImageInfo *) NULL);
146 assert(image_info->signature == MagickSignature);
147 if (image_info->debug != MagickFalse)
148 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
149 image_info->filename);
150 assert(exception != (ExceptionInfo *) NULL);
151 assert(exception->signature == MagickSignature);
152 image=AcquireImage(image_info);
153 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
154 if (status == MagickFalse)
155 {
156 image=DestroyImageList(image);
157 return((Image *) NULL);
158 }
159 /*
160 Initialize JBIG toolkit.
161 */
162 jbg_dec_init(&jbig_info);
cristyf6fe0a12010-05-30 00:44:47 +0000163 jbg_dec_maxsize(&jbig_info,(unsigned long) image->columns,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +0000164 image->rows);
165 image->columns=jbg_dec_getwidth(&jbig_info);
166 image->rows=jbg_dec_getheight(&jbig_info);
167 image->depth=8;
168 image->storage_class=PseudoClass;
169 image->colors=2;
170 /*
171 Read JBIG file.
172 */
173 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
174 sizeof(*buffer));
175 if (buffer == (unsigned char *) NULL)
176 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
177 status=JBG_EAGAIN;
178 do
179 {
cristybb503372010-05-27 20:51:26 +0000180 length=(ssize_t) ReadBlob(image,MagickMaxBufferExtent,buffer);
cristy3ed852e2009-09-05 21:47:34 +0000181 if (length == 0)
182 break;
183 p=buffer;
184 count=0;
185 while ((length > 0) && ((status == JBG_EAGAIN) || (status == JBG_EOK)))
186 {
187 size_t
188 count;
189
190 status=jbg_dec_in(&jbig_info,p,length,&count);
191 p+=count;
cristybb503372010-05-27 20:51:26 +0000192 length-=(ssize_t) count;
cristy3ed852e2009-09-05 21:47:34 +0000193 }
194 } while ((status == JBG_EAGAIN) || (status == JBG_EOK));
195 /*
196 Create colormap.
197 */
198 image->columns=jbg_dec_getwidth(&jbig_info);
199 image->rows=jbg_dec_getheight(&jbig_info);
cristy6d5e20f2011-04-25 13:48:54 +0000200 image->compression=JBIG2Compression;
cristy3ed852e2009-09-05 21:47:34 +0000201 if (AcquireImageColormap(image,2) == MagickFalse)
202 {
203 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
204 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
205 }
206 image->colormap[0].red=0;
207 image->colormap[0].green=0;
208 image->colormap[0].blue=0;
209 image->colormap[1].red=QuantumRange;
210 image->colormap[1].green=QuantumRange;
211 image->colormap[1].blue=QuantumRange;
212 image->x_resolution=300;
213 image->y_resolution=300;
214 if (image_info->ping != MagickFalse)
215 {
216 (void) CloseBlob(image);
217 return(GetFirstImageInList(image));
218 }
219 /*
220 Convert X bitmap image to pixel packets.
221 */
222 p=jbg_dec_getimage(&jbig_info,0);
cristybb503372010-05-27 20:51:26 +0000223 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000224 {
225 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
226 if (q == (PixelPacket *) NULL)
227 break;
228 indexes=GetAuthenticIndexQueue(image);
229 bit=0;
230 byte=0;
cristybb503372010-05-27 20:51:26 +0000231 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000232 {
233 if (bit == 0)
234 byte=(*p++);
235 index=(byte & 0x80) ? 0 : 1;
236 bit++;
237 byte<<=1;
238 if (bit == 8)
239 bit=0;
cristy524222d2011-04-25 00:37:06 +0000240 SetIndexPixelComponent(indexes+x,index);
cristybb503372010-05-27 20:51:26 +0000241 *q++=image->colormap[(ssize_t) index];
cristy3ed852e2009-09-05 21:47:34 +0000242 }
243 if (SyncAuthenticPixels(image,exception) == MagickFalse)
244 break;
cristycee97112010-05-28 00:44:52 +0000245 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristy524222d2011-04-25 00:37:06 +0000246 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000247 if (status == MagickFalse)
248 break;
249 }
250 /*
251 Free scale resource.
252 */
253 jbg_dec_free(&jbig_info);
254 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
255 (void) CloseBlob(image);
256 return(GetFirstImageInList(image));
257}
258#endif
259
260/*
261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
262% %
263% %
264% %
265% R e g i s t e r J B I G I m a g e %
266% %
267% %
268% %
269%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270%
271% RegisterJBIGImage() adds attributes for the JBIG image format to
272% the list of supported formats. The attributes include the image format
273% tag, a method to read and/or write the format, whether the format
274% supports the saving of more than one frame to the same file or blob,
275% whether the format supports native in-memory I/O, and a brief
276% description of the format.
277%
278% The format of the RegisterJBIGImage method is:
279%
cristybb503372010-05-27 20:51:26 +0000280% size_t RegisterJBIGImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000281%
282*/
cristybb503372010-05-27 20:51:26 +0000283ModuleExport size_t RegisterJBIGImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000284{
285#define JBIGDescription "Joint Bi-level Image experts Group interchange format"
286
287 char
288 version[MaxTextExtent];
289
290 MagickInfo
291 *entry;
292
293 *version='\0';
294#if defined(JBG_VERSION)
295 (void) CopyMagickString(version,JBG_VERSION,MaxTextExtent);
296#endif
297 entry=SetMagickInfo("BIE");
298#if defined(MAGICKCORE_JBIG_DELEGATE)
299 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
300 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
301#endif
302 entry->adjoin=MagickFalse;
303 entry->description=ConstantString(JBIGDescription);
304 if (*version != '\0')
305 entry->version=ConstantString(version);
306 entry->module=ConstantString("JBIG");
307 (void) RegisterMagickInfo(entry);
308 entry=SetMagickInfo("JBG");
309#if defined(MAGICKCORE_JBIG_DELEGATE)
310 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
311 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
312#endif
313 entry->description=ConstantString(JBIGDescription);
314 if (*version != '\0')
315 entry->version=ConstantString(version);
316 entry->module=ConstantString("JBIG");
317 (void) RegisterMagickInfo(entry);
318 entry=SetMagickInfo("JBIG");
319#if defined(MAGICKCORE_JBIG_DELEGATE)
320 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
321 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
322#endif
323 entry->description=ConstantString(JBIGDescription);
324 if (*version != '\0')
325 entry->version=ConstantString(version);
326 entry->module=ConstantString("JBIG");
327 (void) RegisterMagickInfo(entry);
328 return(MagickImageCoderSignature);
329}
330
331/*
332%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333% %
334% %
335% %
336% U n r e g i s t e r J B I G I m a g e %
337% %
338% %
339% %
340%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341%
342% UnregisterJBIGImage() removes format registrations made by the
343% JBIG module from the list of supported formats.
344%
345% The format of the UnregisterJBIGImage method is:
346%
347% UnregisterJBIGImage(void)
348%
349*/
350ModuleExport void UnregisterJBIGImage(void)
351{
352 (void) UnregisterMagickInfo("BIE");
353 (void) UnregisterMagickInfo("JBG");
354 (void) UnregisterMagickInfo("JBIG");
355}
356
357#if defined(MAGICKCORE_JBIG_DELEGATE)
358/*
359%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
360% %
361% %
362% %
363% W r i t e J B I G I m a g e %
364% %
365% %
366% %
367%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
368%
369% WriteJBIGImage() writes an image in the JBIG encoded image format.
370%
371% The format of the WriteJBIGImage method is:
372%
373% MagickBooleanType WriteJBIGImage(const ImageInfo *image_info,Image *image)
374%
375% A description of each parameter follows.
376%
377% o image_info: the image info.
378%
379% o image: The image.
380%
381%
382*/
383
384static void JBIGEncode(unsigned char *pixels,size_t length,void *data)
385{
386 Image
387 *image;
388
389 image=(Image *) data;
390 (void) WriteBlob(image,length,pixels);
391}
392
393static MagickBooleanType WriteJBIGImage(const ImageInfo *image_info,
394 Image *image)
395{
396 double
397 version;
398
cristy3ed852e2009-09-05 21:47:34 +0000399 MagickBooleanType
400 status;
401
402 MagickOffsetType
403 scene;
404
405 register const IndexPacket
406 *indexes;
407
408 register const PixelPacket
409 *p;
410
cristybb503372010-05-27 20:51:26 +0000411 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000412 x;
413
414 register unsigned char
415 *q;
416
cristy524222d2011-04-25 00:37:06 +0000417 size_t
418 number_packets;
419
420 ssize_t
421 y;
422
cristy3ed852e2009-09-05 21:47:34 +0000423 struct jbg_enc_state
424 jbig_info;
425
426 unsigned char
427 bit,
428 byte,
429 *pixels;
430
cristy3ed852e2009-09-05 21:47:34 +0000431 /*
432 Open image file.
433 */
434 assert(image_info != (const ImageInfo *) NULL);
435 assert(image_info->signature == MagickSignature);
436 assert(image != (Image *) NULL);
437 assert(image->signature == MagickSignature);
438 if (image->debug != MagickFalse)
439 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
440 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
441 if (status == MagickFalse)
442 return(status);
443 version=strtod(JBG_VERSION,(char **) NULL);
444 scene=0;
445 do
446 {
447 /*
448 Allocate pixel data.
449 */
450 if (image->colorspace != RGBColorspace)
451 (void) TransformImageColorspace(image,RGBColorspace);
452 number_packets=(image->columns+7)/8;
453 pixels=(unsigned char *) AcquireQuantumMemory(number_packets,
454 image->rows*sizeof(*pixels));
455 if (pixels == (unsigned char *) NULL)
456 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
457 /*
458 Convert pixels to a bitmap.
459 */
460 (void) SetImageType(image,BilevelType);
461 q=pixels;
cristybb503372010-05-27 20:51:26 +0000462 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000463 {
464 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
465 if (p == (const PixelPacket *) NULL)
466 break;
467 indexes=GetVirtualIndexQueue(image);
468 bit=0;
469 byte=0;
cristybb503372010-05-27 20:51:26 +0000470 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000471 {
472 byte<<=1;
473 if (PixelIntensity(p) < (QuantumRange/2.0))
474 byte|=0x01;
475 bit++;
476 if (bit == 8)
477 {
478 *q++=byte;
479 bit=0;
480 byte=0;
481 }
482 p++;
483 }
484 if (bit != 0)
485 *q++=byte << (8-bit);
486 if (image->previous == (Image *) NULL)
487 {
cristycee97112010-05-28 00:44:52 +0000488 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy524222d2011-04-25 00:37:06 +0000489 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000490 if (status == MagickFalse)
491 break;
492 }
493 }
494 /*
495 Initialize JBIG info structure.
496 */
cristyf6fe0a12010-05-30 00:44:47 +0000497 jbg_enc_init(&jbig_info,(unsigned long) image->columns,(unsigned long)
498 image->rows,1,&pixels,(void (*)(unsigned char *,size_t,void *))
499 JBIGEncode,image);
cristy3ed852e2009-09-05 21:47:34 +0000500 if (image_info->scene != 0)
501 jbg_enc_layers(&jbig_info,(int) image_info->scene);
502 else
503 {
cristybb503372010-05-27 20:51:26 +0000504 size_t
cristy3ed852e2009-09-05 21:47:34 +0000505 x_resolution,
506 y_resolution;
507
cristy524222d2011-04-25 00:37:06 +0000508 ssize_t
509 sans_offset;
510
cristy3ed852e2009-09-05 21:47:34 +0000511 x_resolution=640;
512 y_resolution=480;
513 sans_offset=0;
514 if (image_info->density != (char *) NULL)
515 {
516 GeometryInfo
517 geometry_info;
518
519 MagickStatusType
520 flags;
521
522 flags=ParseGeometry(image_info->density,&geometry_info);
523 x_resolution=geometry_info.rho;
524 y_resolution=geometry_info.sigma;
525 if ((flags & SigmaValue) == 0)
526 y_resolution=x_resolution;
527 }
528 if (image->units == PixelsPerCentimeterResolution)
529 {
cristybb503372010-05-27 20:51:26 +0000530 x_resolution=(size_t) (100.0*2.54*x_resolution+0.5)/100.0;
531 y_resolution=(size_t) (100.0*2.54*y_resolution+0.5)/100.0;
cristy3ed852e2009-09-05 21:47:34 +0000532 }
cristyf6fe0a12010-05-30 00:44:47 +0000533 (void) jbg_enc_lrlmax(&jbig_info,(unsigned long) x_resolution,
534 (unsigned long) y_resolution);
cristy3ed852e2009-09-05 21:47:34 +0000535 }
536 (void) jbg_enc_lrange(&jbig_info,-1,-1);
537 jbg_enc_options(&jbig_info,JBG_ILEAVE | JBG_SMID,JBG_TPDON | JBG_TPBON |
538 JBG_DPON,version < 1.6 ? -1 : 0,-1,-1);
539 /*
540 Write JBIG image.
541 */
542 jbg_enc_out(&jbig_info);
543 jbg_enc_free(&jbig_info);
544 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
545 if (GetNextImageInList(image) == (Image *) NULL)
546 break;
547 image=SyncNextImageInList(image);
548 status=SetImageProgress(image,SaveImagesTag,scene++,
549 GetImageListLength(image));
550 if (status == MagickFalse)
551 break;
552 } while (image_info->adjoin != MagickFalse);
553 (void) CloseBlob(image);
554 return(MagickTrue);
555}
556#endif