blob: 9395e9494a3cb148e06d37b1a3cba678d3f026e9 [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*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/blob.h"
44#include "MagickCore/blob-private.h"
45#include "MagickCore/cache.h"
46#include "MagickCore/color-private.h"
47#include "MagickCore/colormap.h"
48#include "MagickCore/colorspace.h"
cristyd15d8e02011-07-07 00:17:15 +000049#include "MagickCore/colorspace-private.h"
cristy4c08aed2011-07-01 19:47:50 +000050#include "MagickCore/constitute.h"
51#include "MagickCore/exception.h"
52#include "MagickCore/exception-private.h"
53#include "MagickCore/geometry.h"
54#include "MagickCore/image.h"
55#include "MagickCore/image-private.h"
56#include "MagickCore/list.h"
57#include "MagickCore/magick.h"
58#include "MagickCore/memory_.h"
59#include "MagickCore/monitor.h"
60#include "MagickCore/monitor-private.h"
cristyc3e97de2011-10-13 17:45:09 +000061#include "MagickCore/nt-base-private.h"
cristy4c08aed2011-07-01 19:47:50 +000062#include "MagickCore/pixel-accessor.h"
63#include "MagickCore/quantum-private.h"
64#include "MagickCore/static.h"
65#include "MagickCore/string_.h"
cristy196372d2011-11-05 00:07:32 +000066#include "MagickCore/string-private.h"
cristy4c08aed2011-07-01 19:47:50 +000067#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000068#if defined(MAGICKCORE_JBIG_DELEGATE)
69#include "jbig.h"
70#endif
71
72/*
73 Forward declarations.
74*/
75#if defined(MAGICKCORE_JBIG_DELEGATE)
76static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000077 WriteJBIGImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000078#endif
79
80#if defined(MAGICKCORE_JBIG_DELEGATE)
81/*
82%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83% %
84% %
85% %
86% R e a d J B I G I m a g e %
87% %
88% %
89% %
90%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91%
92% ReadJBIGImage() reads a JBIG image file and returns it. It
93% allocates the memory necessary for the new Image structure and returns a
94% pointer to the new image.
95%
96% The format of the ReadJBIGImage method is:
97%
98% Image *ReadJBIGImage(const ImageInfo *image_info,
99% ExceptionInfo *exception)
100%
101% A description of each parameter follows:
102%
103% o image_info: the image info.
104%
105% o exception: return any errors or warnings in this structure.
106%
107*/
108static Image *ReadJBIGImage(const ImageInfo *image_info,
109 ExceptionInfo *exception)
110{
111 Image
112 *image;
113
cristy50f1ebc2011-06-05 01:35:34 +0000114 MagickStatusType
cristy3ed852e2009-09-05 21:47:34 +0000115 status;
116
cristy4c08aed2011-07-01 19:47:50 +0000117 Quantum
118 index;
cristy3ed852e2009-09-05 21:47:34 +0000119
cristybb503372010-05-27 20:51:26 +0000120 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000121 x;
122
cristy4c08aed2011-07-01 19:47:50 +0000123 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000124 *q;
125
126 register unsigned char
127 *p;
128
129 ssize_t
cristy524222d2011-04-25 00:37:06 +0000130 length,
131 y;
cristy3ed852e2009-09-05 21:47:34 +0000132
133 struct jbg_dec_state
134 jbig_info;
135
136 unsigned char
137 bit,
138 *buffer,
139 byte;
140
141 /*
142 Open image file.
143 */
144 assert(image_info != (const ImageInfo *) NULL);
145 assert(image_info->signature == MagickSignature);
146 if (image_info->debug != MagickFalse)
147 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
148 image_info->filename);
149 assert(exception != (ExceptionInfo *) NULL);
150 assert(exception->signature == MagickSignature);
cristy9950d572011-10-01 18:22:35 +0000151 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000152 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
153 if (status == MagickFalse)
154 {
155 image=DestroyImageList(image);
156 return((Image *) NULL);
157 }
158 /*
159 Initialize JBIG toolkit.
160 */
161 jbg_dec_init(&jbig_info);
cristyf6fe0a12010-05-30 00:44:47 +0000162 jbg_dec_maxsize(&jbig_info,(unsigned long) image->columns,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +0000163 image->rows);
164 image->columns=jbg_dec_getwidth(&jbig_info);
165 image->rows=jbg_dec_getheight(&jbig_info);
166 image->depth=8;
167 image->storage_class=PseudoClass;
168 image->colors=2;
169 /*
170 Read JBIG file.
171 */
172 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
173 sizeof(*buffer));
174 if (buffer == (unsigned char *) NULL)
175 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
176 status=JBG_EAGAIN;
177 do
178 {
cristybb503372010-05-27 20:51:26 +0000179 length=(ssize_t) ReadBlob(image,MagickMaxBufferExtent,buffer);
cristy3ed852e2009-09-05 21:47:34 +0000180 if (length == 0)
181 break;
182 p=buffer;
cristy3ed852e2009-09-05 21:47:34 +0000183 while ((length > 0) && ((status == JBG_EAGAIN) || (status == JBG_EOK)))
184 {
185 size_t
186 count;
187
188 status=jbg_dec_in(&jbig_info,p,length,&count);
189 p+=count;
cristybb503372010-05-27 20:51:26 +0000190 length-=(ssize_t) count;
cristy3ed852e2009-09-05 21:47:34 +0000191 }
192 } while ((status == JBG_EAGAIN) || (status == JBG_EOK));
193 /*
194 Create colormap.
195 */
196 image->columns=jbg_dec_getwidth(&jbig_info);
197 image->rows=jbg_dec_getheight(&jbig_info);
cristy6d5e20f2011-04-25 13:48:54 +0000198 image->compression=JBIG2Compression;
cristy018f07f2011-09-04 21:15:19 +0000199 if (AcquireImageColormap(image,2,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000200 {
201 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
202 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
203 }
204 image->colormap[0].red=0;
205 image->colormap[0].green=0;
206 image->colormap[0].blue=0;
207 image->colormap[1].red=QuantumRange;
208 image->colormap[1].green=QuantumRange;
209 image->colormap[1].blue=QuantumRange;
cristy2a11bef2011-10-28 18:33:11 +0000210 image->resolution.x=300;
211 image->resolution.y=300;
cristy3ed852e2009-09-05 21:47:34 +0000212 if (image_info->ping != MagickFalse)
213 {
214 (void) CloseBlob(image);
215 return(GetFirstImageInList(image));
216 }
217 /*
218 Convert X bitmap image to pixel packets.
219 */
220 p=jbg_dec_getimage(&jbig_info,0);
cristybb503372010-05-27 20:51:26 +0000221 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000222 {
223 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000224 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000225 break;
cristy3ed852e2009-09-05 21:47:34 +0000226 bit=0;
227 byte=0;
cristybb503372010-05-27 20:51:26 +0000228 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000229 {
230 if (bit == 0)
231 byte=(*p++);
232 index=(byte & 0x80) ? 0 : 1;
233 bit++;
234 byte<<=1;
235 if (bit == 8)
236 bit=0;
cristy4c08aed2011-07-01 19:47:50 +0000237 SetPixelIndex(image,index,q);
cristy803640d2011-11-17 02:11:32 +0000238 SetPixelInfoPixel(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000239 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000240 }
241 if (SyncAuthenticPixels(image,exception) == MagickFalse)
242 break;
cristycee97112010-05-28 00:44:52 +0000243 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristy524222d2011-04-25 00:37:06 +0000244 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000245 if (status == MagickFalse)
246 break;
247 }
248 /*
249 Free scale resource.
250 */
251 jbg_dec_free(&jbig_info);
252 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
253 (void) CloseBlob(image);
254 return(GetFirstImageInList(image));
255}
256#endif
257
258/*
259%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260% %
261% %
262% %
263% R e g i s t e r J B I G I m a g e %
264% %
265% %
266% %
267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
268%
269% RegisterJBIGImage() adds attributes for the JBIG image format to
270% the list of supported formats. The attributes include the image format
271% tag, a method to read and/or write the format, whether the format
272% supports the saving of more than one frame to the same file or blob,
273% whether the format supports native in-memory I/O, and a brief
274% description of the format.
275%
276% The format of the RegisterJBIGImage method is:
277%
cristybb503372010-05-27 20:51:26 +0000278% size_t RegisterJBIGImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000279%
280*/
cristybb503372010-05-27 20:51:26 +0000281ModuleExport size_t RegisterJBIGImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000282{
283#define JBIGDescription "Joint Bi-level Image experts Group interchange format"
284
285 char
286 version[MaxTextExtent];
287
288 MagickInfo
289 *entry;
290
291 *version='\0';
292#if defined(JBG_VERSION)
293 (void) CopyMagickString(version,JBG_VERSION,MaxTextExtent);
294#endif
295 entry=SetMagickInfo("BIE");
296#if defined(MAGICKCORE_JBIG_DELEGATE)
297 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
298 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
299#endif
300 entry->adjoin=MagickFalse;
301 entry->description=ConstantString(JBIGDescription);
302 if (*version != '\0')
303 entry->version=ConstantString(version);
304 entry->module=ConstantString("JBIG");
305 (void) RegisterMagickInfo(entry);
306 entry=SetMagickInfo("JBG");
307#if defined(MAGICKCORE_JBIG_DELEGATE)
308 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
309 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
310#endif
311 entry->description=ConstantString(JBIGDescription);
312 if (*version != '\0')
313 entry->version=ConstantString(version);
314 entry->module=ConstantString("JBIG");
315 (void) RegisterMagickInfo(entry);
316 entry=SetMagickInfo("JBIG");
317#if defined(MAGICKCORE_JBIG_DELEGATE)
318 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
319 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
320#endif
321 entry->description=ConstantString(JBIGDescription);
322 if (*version != '\0')
323 entry->version=ConstantString(version);
324 entry->module=ConstantString("JBIG");
325 (void) RegisterMagickInfo(entry);
326 return(MagickImageCoderSignature);
327}
328
329/*
330%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331% %
332% %
333% %
334% U n r e g i s t e r J B I G I m a g e %
335% %
336% %
337% %
338%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339%
340% UnregisterJBIGImage() removes format registrations made by the
341% JBIG module from the list of supported formats.
342%
343% The format of the UnregisterJBIGImage method is:
344%
345% UnregisterJBIGImage(void)
346%
347*/
348ModuleExport void UnregisterJBIGImage(void)
349{
350 (void) UnregisterMagickInfo("BIE");
351 (void) UnregisterMagickInfo("JBG");
352 (void) UnregisterMagickInfo("JBIG");
353}
354
355#if defined(MAGICKCORE_JBIG_DELEGATE)
356/*
357%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358% %
359% %
360% %
361% W r i t e J B I G I m a g e %
362% %
363% %
364% %
365%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
366%
367% WriteJBIGImage() writes an image in the JBIG encoded image format.
368%
369% The format of the WriteJBIGImage method is:
370%
cristy1e178e72011-08-28 19:44:34 +0000371% MagickBooleanType WriteJBIGImage(const ImageInfo *image_info,
372% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000373%
374% A description of each parameter follows.
375%
376% o image_info: the image info.
377%
378% o image: The image.
379%
cristy1e178e72011-08-28 19:44:34 +0000380% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +0000381%
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,
cristy1e178e72011-08-28 19:44:34 +0000394 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000395{
396 double
397 version;
398
cristy3ed852e2009-09-05 21:47:34 +0000399 MagickBooleanType
400 status;
401
402 MagickOffsetType
403 scene;
404
cristy4c08aed2011-07-01 19:47:50 +0000405 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000406 *p;
407
cristybb503372010-05-27 20:51:26 +0000408 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000409 x;
410
411 register unsigned char
412 *q;
413
cristy524222d2011-04-25 00:37:06 +0000414 size_t
415 number_packets;
416
417 ssize_t
418 y;
419
cristy3ed852e2009-09-05 21:47:34 +0000420 struct jbg_enc_state
421 jbig_info;
422
423 unsigned char
424 bit,
425 byte,
426 *pixels;
427
cristy3ed852e2009-09-05 21:47:34 +0000428 /*
429 Open image file.
430 */
431 assert(image_info != (const ImageInfo *) NULL);
432 assert(image_info->signature == MagickSignature);
433 assert(image != (Image *) NULL);
434 assert(image->signature == MagickSignature);
435 if (image->debug != MagickFalse)
436 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000437 assert(exception != (ExceptionInfo *) NULL);
438 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000439 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000440 if (status == MagickFalse)
441 return(status);
cristydbdd0e32011-11-04 23:29:40 +0000442 version=StringToDouble(JBG_VERSION,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000443 scene=0;
444 do
445 {
446 /*
447 Allocate pixel data.
448 */
cristy510d06a2011-07-06 23:43:54 +0000449 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristye941a752011-10-15 01:52:48 +0000450 (void) TransformImageColorspace(image,RGBColorspace,exception);
cristy3ed852e2009-09-05 21:47:34 +0000451 number_packets=(image->columns+7)/8;
452 pixels=(unsigned char *) AcquireQuantumMemory(number_packets,
453 image->rows*sizeof(*pixels));
454 if (pixels == (unsigned char *) NULL)
455 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
456 /*
457 Convert pixels to a bitmap.
458 */
cristy018f07f2011-09-04 21:15:19 +0000459 (void) SetImageType(image,BilevelType,exception);
cristy3ed852e2009-09-05 21:47:34 +0000460 q=pixels;
cristybb503372010-05-27 20:51:26 +0000461 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000462 {
cristy1e178e72011-08-28 19:44:34 +0000463 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000464 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000465 break;
cristy3ed852e2009-09-05 21:47:34 +0000466 bit=0;
467 byte=0;
cristybb503372010-05-27 20:51:26 +0000468 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000469 {
470 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +0000471 if (GetPixelIntensity(image,p) < (QuantumRange/2.0))
cristy3ed852e2009-09-05 21:47:34 +0000472 byte|=0x01;
473 bit++;
474 if (bit == 8)
475 {
476 *q++=byte;
477 bit=0;
478 byte=0;
479 }
cristyed231572011-07-14 02:18:59 +0000480 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000481 }
482 if (bit != 0)
483 *q++=byte << (8-bit);
484 if (image->previous == (Image *) NULL)
485 {
cristycee97112010-05-28 00:44:52 +0000486 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy524222d2011-04-25 00:37:06 +0000487 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000488 if (status == MagickFalse)
489 break;
490 }
491 }
492 /*
493 Initialize JBIG info structure.
494 */
cristyf6fe0a12010-05-30 00:44:47 +0000495 jbg_enc_init(&jbig_info,(unsigned long) image->columns,(unsigned long)
496 image->rows,1,&pixels,(void (*)(unsigned char *,size_t,void *))
497 JBIGEncode,image);
cristy3ed852e2009-09-05 21:47:34 +0000498 if (image_info->scene != 0)
499 jbg_enc_layers(&jbig_info,(int) image_info->scene);
500 else
501 {
cristybb503372010-05-27 20:51:26 +0000502 size_t
cristy3ed852e2009-09-05 21:47:34 +0000503 x_resolution,
504 y_resolution;
505
506 x_resolution=640;
507 y_resolution=480;
cristy3ed852e2009-09-05 21:47:34 +0000508 if (image_info->density != (char *) NULL)
509 {
510 GeometryInfo
511 geometry_info;
512
513 MagickStatusType
514 flags;
515
516 flags=ParseGeometry(image_info->density,&geometry_info);
517 x_resolution=geometry_info.rho;
518 y_resolution=geometry_info.sigma;
519 if ((flags & SigmaValue) == 0)
520 y_resolution=x_resolution;
521 }
522 if (image->units == PixelsPerCentimeterResolution)
523 {
cristybb503372010-05-27 20:51:26 +0000524 x_resolution=(size_t) (100.0*2.54*x_resolution+0.5)/100.0;
525 y_resolution=(size_t) (100.0*2.54*y_resolution+0.5)/100.0;
cristy3ed852e2009-09-05 21:47:34 +0000526 }
cristyf6fe0a12010-05-30 00:44:47 +0000527 (void) jbg_enc_lrlmax(&jbig_info,(unsigned long) x_resolution,
528 (unsigned long) y_resolution);
cristy3ed852e2009-09-05 21:47:34 +0000529 }
530 (void) jbg_enc_lrange(&jbig_info,-1,-1);
531 jbg_enc_options(&jbig_info,JBG_ILEAVE | JBG_SMID,JBG_TPDON | JBG_TPBON |
532 JBG_DPON,version < 1.6 ? -1 : 0,-1,-1);
533 /*
534 Write JBIG image.
535 */
536 jbg_enc_out(&jbig_info);
537 jbg_enc_free(&jbig_info);
538 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
539 if (GetNextImageInList(image) == (Image *) NULL)
540 break;
541 image=SyncNextImageInList(image);
542 status=SetImageProgress(image,SaveImagesTag,scene++,
543 GetImageListLength(image));
544 if (status == MagickFalse)
545 break;
546 } while (image_info->adjoin != MagickFalse);
547 (void) CloseBlob(image);
548 return(MagickTrue);
549}
550#endif