blob: 0048cf84c7d99eeedfc9dd3fe8fb7f508f645e18 [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"
66#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000067#if defined(MAGICKCORE_JBIG_DELEGATE)
68#include "jbig.h"
69#endif
70
71/*
72 Forward declarations.
73*/
74#if defined(MAGICKCORE_JBIG_DELEGATE)
75static MagickBooleanType
cristy1e178e72011-08-28 19:44:34 +000076 WriteJBIGImage(const ImageInfo *,Image *,ExceptionInfo *);
cristy3ed852e2009-09-05 21:47:34 +000077#endif
78
79#if defined(MAGICKCORE_JBIG_DELEGATE)
80/*
81%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82% %
83% %
84% %
85% R e a d J B I G I m a g e %
86% %
87% %
88% %
89%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
90%
91% ReadJBIGImage() reads a JBIG image file and returns it. It
92% allocates the memory necessary for the new Image structure and returns a
93% pointer to the new image.
94%
95% The format of the ReadJBIGImage method is:
96%
97% Image *ReadJBIGImage(const ImageInfo *image_info,
98% ExceptionInfo *exception)
99%
100% A description of each parameter follows:
101%
102% o image_info: the image info.
103%
104% o exception: return any errors or warnings in this structure.
105%
106*/
107static Image *ReadJBIGImage(const ImageInfo *image_info,
108 ExceptionInfo *exception)
109{
110 Image
111 *image;
112
cristy50f1ebc2011-06-05 01:35:34 +0000113 MagickStatusType
cristy3ed852e2009-09-05 21:47:34 +0000114 status;
115
cristy4c08aed2011-07-01 19:47:50 +0000116 Quantum
117 index;
cristy3ed852e2009-09-05 21:47:34 +0000118
cristybb503372010-05-27 20:51:26 +0000119 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000120 x;
121
cristy4c08aed2011-07-01 19:47:50 +0000122 register Quantum
cristy3ed852e2009-09-05 21:47:34 +0000123 *q;
124
125 register unsigned char
126 *p;
127
128 ssize_t
cristy524222d2011-04-25 00:37:06 +0000129 length,
130 y;
cristy3ed852e2009-09-05 21:47:34 +0000131
132 struct jbg_dec_state
133 jbig_info;
134
135 unsigned char
136 bit,
137 *buffer,
138 byte;
139
140 /*
141 Open image file.
142 */
143 assert(image_info != (const ImageInfo *) NULL);
144 assert(image_info->signature == MagickSignature);
145 if (image_info->debug != MagickFalse)
146 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
147 image_info->filename);
148 assert(exception != (ExceptionInfo *) NULL);
149 assert(exception->signature == MagickSignature);
cristy9950d572011-10-01 18:22:35 +0000150 image=AcquireImage(image_info,exception);
cristy3ed852e2009-09-05 21:47:34 +0000151 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
152 if (status == MagickFalse)
153 {
154 image=DestroyImageList(image);
155 return((Image *) NULL);
156 }
157 /*
158 Initialize JBIG toolkit.
159 */
160 jbg_dec_init(&jbig_info);
cristyf6fe0a12010-05-30 00:44:47 +0000161 jbg_dec_maxsize(&jbig_info,(unsigned long) image->columns,(unsigned long)
cristy3ed852e2009-09-05 21:47:34 +0000162 image->rows);
163 image->columns=jbg_dec_getwidth(&jbig_info);
164 image->rows=jbg_dec_getheight(&jbig_info);
165 image->depth=8;
166 image->storage_class=PseudoClass;
167 image->colors=2;
168 /*
169 Read JBIG file.
170 */
171 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
172 sizeof(*buffer));
173 if (buffer == (unsigned char *) NULL)
174 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
175 status=JBG_EAGAIN;
176 do
177 {
cristybb503372010-05-27 20:51:26 +0000178 length=(ssize_t) ReadBlob(image,MagickMaxBufferExtent,buffer);
cristy3ed852e2009-09-05 21:47:34 +0000179 if (length == 0)
180 break;
181 p=buffer;
cristy3ed852e2009-09-05 21:47:34 +0000182 while ((length > 0) && ((status == JBG_EAGAIN) || (status == JBG_EOK)))
183 {
184 size_t
185 count;
186
187 status=jbg_dec_in(&jbig_info,p,length,&count);
188 p+=count;
cristybb503372010-05-27 20:51:26 +0000189 length-=(ssize_t) count;
cristy3ed852e2009-09-05 21:47:34 +0000190 }
191 } while ((status == JBG_EAGAIN) || (status == JBG_EOK));
192 /*
193 Create colormap.
194 */
195 image->columns=jbg_dec_getwidth(&jbig_info);
196 image->rows=jbg_dec_getheight(&jbig_info);
cristy6d5e20f2011-04-25 13:48:54 +0000197 image->compression=JBIG2Compression;
cristy018f07f2011-09-04 21:15:19 +0000198 if (AcquireImageColormap(image,2,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000199 {
200 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
201 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
202 }
203 image->colormap[0].red=0;
204 image->colormap[0].green=0;
205 image->colormap[0].blue=0;
206 image->colormap[1].red=QuantumRange;
207 image->colormap[1].green=QuantumRange;
208 image->colormap[1].blue=QuantumRange;
209 image->x_resolution=300;
210 image->y_resolution=300;
211 if (image_info->ping != MagickFalse)
212 {
213 (void) CloseBlob(image);
214 return(GetFirstImageInList(image));
215 }
216 /*
217 Convert X bitmap image to pixel packets.
218 */
219 p=jbg_dec_getimage(&jbig_info,0);
cristybb503372010-05-27 20:51:26 +0000220 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000221 {
222 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristyacd2ed22011-08-30 01:44:23 +0000223 if (q == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000224 break;
cristy3ed852e2009-09-05 21:47:34 +0000225 bit=0;
226 byte=0;
cristybb503372010-05-27 20:51:26 +0000227 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000228 {
229 if (bit == 0)
230 byte=(*p++);
231 index=(byte & 0x80) ? 0 : 1;
232 bit++;
233 byte<<=1;
234 if (bit == 8)
235 bit=0;
cristy4c08aed2011-07-01 19:47:50 +0000236 SetPixelIndex(image,index,q);
cristy101ab702011-10-13 13:06:32 +0000237 SetPixelPixelInfo(image,image->colormap+(ssize_t) index,q);
cristyed231572011-07-14 02:18:59 +0000238 q+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000239 }
240 if (SyncAuthenticPixels(image,exception) == MagickFalse)
241 break;
cristycee97112010-05-28 00:44:52 +0000242 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
cristy524222d2011-04-25 00:37:06 +0000243 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000244 if (status == MagickFalse)
245 break;
246 }
247 /*
248 Free scale resource.
249 */
250 jbg_dec_free(&jbig_info);
251 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
252 (void) CloseBlob(image);
253 return(GetFirstImageInList(image));
254}
255#endif
256
257/*
258%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259% %
260% %
261% %
262% R e g i s t e r J B I G I m a g e %
263% %
264% %
265% %
266%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267%
268% RegisterJBIGImage() adds attributes for the JBIG image format to
269% the list of supported formats. The attributes include the image format
270% tag, a method to read and/or write the format, whether the format
271% supports the saving of more than one frame to the same file or blob,
272% whether the format supports native in-memory I/O, and a brief
273% description of the format.
274%
275% The format of the RegisterJBIGImage method is:
276%
cristybb503372010-05-27 20:51:26 +0000277% size_t RegisterJBIGImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000278%
279*/
cristybb503372010-05-27 20:51:26 +0000280ModuleExport size_t RegisterJBIGImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000281{
282#define JBIGDescription "Joint Bi-level Image experts Group interchange format"
283
284 char
285 version[MaxTextExtent];
286
287 MagickInfo
288 *entry;
289
290 *version='\0';
291#if defined(JBG_VERSION)
292 (void) CopyMagickString(version,JBG_VERSION,MaxTextExtent);
293#endif
294 entry=SetMagickInfo("BIE");
295#if defined(MAGICKCORE_JBIG_DELEGATE)
296 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
297 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
298#endif
299 entry->adjoin=MagickFalse;
300 entry->description=ConstantString(JBIGDescription);
301 if (*version != '\0')
302 entry->version=ConstantString(version);
303 entry->module=ConstantString("JBIG");
304 (void) RegisterMagickInfo(entry);
305 entry=SetMagickInfo("JBG");
306#if defined(MAGICKCORE_JBIG_DELEGATE)
307 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
308 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
309#endif
310 entry->description=ConstantString(JBIGDescription);
311 if (*version != '\0')
312 entry->version=ConstantString(version);
313 entry->module=ConstantString("JBIG");
314 (void) RegisterMagickInfo(entry);
315 entry=SetMagickInfo("JBIG");
316#if defined(MAGICKCORE_JBIG_DELEGATE)
317 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
318 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
319#endif
320 entry->description=ConstantString(JBIGDescription);
321 if (*version != '\0')
322 entry->version=ConstantString(version);
323 entry->module=ConstantString("JBIG");
324 (void) RegisterMagickInfo(entry);
325 return(MagickImageCoderSignature);
326}
327
328/*
329%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330% %
331% %
332% %
333% U n r e g i s t e r J B I G I m a g e %
334% %
335% %
336% %
337%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338%
339% UnregisterJBIGImage() removes format registrations made by the
340% JBIG module from the list of supported formats.
341%
342% The format of the UnregisterJBIGImage method is:
343%
344% UnregisterJBIGImage(void)
345%
346*/
347ModuleExport void UnregisterJBIGImage(void)
348{
349 (void) UnregisterMagickInfo("BIE");
350 (void) UnregisterMagickInfo("JBG");
351 (void) UnregisterMagickInfo("JBIG");
352}
353
354#if defined(MAGICKCORE_JBIG_DELEGATE)
355/*
356%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357% %
358% %
359% %
360% W r i t e J B I G I m a g e %
361% %
362% %
363% %
364%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365%
366% WriteJBIGImage() writes an image in the JBIG encoded image format.
367%
368% The format of the WriteJBIGImage method is:
369%
cristy1e178e72011-08-28 19:44:34 +0000370% MagickBooleanType WriteJBIGImage(const ImageInfo *image_info,
371% Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000372%
373% A description of each parameter follows.
374%
375% o image_info: the image info.
376%
377% o image: The image.
378%
cristy1e178e72011-08-28 19:44:34 +0000379% o exception: return any errors or warnings in this structure.
cristy3ed852e2009-09-05 21:47:34 +0000380%
381*/
382
383static void JBIGEncode(unsigned char *pixels,size_t length,void *data)
384{
385 Image
386 *image;
387
388 image=(Image *) data;
389 (void) WriteBlob(image,length,pixels);
390}
391
392static MagickBooleanType WriteJBIGImage(const ImageInfo *image_info,
cristy1e178e72011-08-28 19:44:34 +0000393 Image *image,ExceptionInfo *exception)
cristy3ed852e2009-09-05 21:47:34 +0000394{
395 double
396 version;
397
cristy3ed852e2009-09-05 21:47:34 +0000398 MagickBooleanType
399 status;
400
401 MagickOffsetType
402 scene;
403
cristy4c08aed2011-07-01 19:47:50 +0000404 register const Quantum
cristy3ed852e2009-09-05 21:47:34 +0000405 *p;
406
cristybb503372010-05-27 20:51:26 +0000407 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000408 x;
409
410 register unsigned char
411 *q;
412
cristy524222d2011-04-25 00:37:06 +0000413 size_t
414 number_packets;
415
416 ssize_t
417 y;
418
cristy3ed852e2009-09-05 21:47:34 +0000419 struct jbg_enc_state
420 jbig_info;
421
422 unsigned char
423 bit,
424 byte,
425 *pixels;
426
cristy3ed852e2009-09-05 21:47:34 +0000427 /*
428 Open image file.
429 */
430 assert(image_info != (const ImageInfo *) NULL);
431 assert(image_info->signature == MagickSignature);
432 assert(image != (Image *) NULL);
433 assert(image->signature == MagickSignature);
434 if (image->debug != MagickFalse)
435 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
cristy3a37efd2011-08-28 20:31:03 +0000436 assert(exception != (ExceptionInfo *) NULL);
437 assert(exception->signature == MagickSignature);
cristy1e178e72011-08-28 19:44:34 +0000438 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
cristy3ed852e2009-09-05 21:47:34 +0000439 if (status == MagickFalse)
440 return(status);
cristyc1acd842011-05-19 23:05:47 +0000441 version=InterpretLocaleValue(JBG_VERSION,(char **) NULL);
cristy3ed852e2009-09-05 21:47:34 +0000442 scene=0;
443 do
444 {
445 /*
446 Allocate pixel data.
447 */
cristy510d06a2011-07-06 23:43:54 +0000448 if (IsRGBColorspace(image->colorspace) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000449 (void) TransformImageColorspace(image,RGBColorspace);
450 number_packets=(image->columns+7)/8;
451 pixels=(unsigned char *) AcquireQuantumMemory(number_packets,
452 image->rows*sizeof(*pixels));
453 if (pixels == (unsigned char *) NULL)
454 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
455 /*
456 Convert pixels to a bitmap.
457 */
cristy018f07f2011-09-04 21:15:19 +0000458 (void) SetImageType(image,BilevelType,exception);
cristy3ed852e2009-09-05 21:47:34 +0000459 q=pixels;
cristybb503372010-05-27 20:51:26 +0000460 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000461 {
cristy1e178e72011-08-28 19:44:34 +0000462 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000463 if (p == (const Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000464 break;
cristy3ed852e2009-09-05 21:47:34 +0000465 bit=0;
466 byte=0;
cristybb503372010-05-27 20:51:26 +0000467 for (x=0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000468 {
469 byte<<=1;
cristy4c08aed2011-07-01 19:47:50 +0000470 if (GetPixelIntensity(image,p) < (QuantumRange/2.0))
cristy3ed852e2009-09-05 21:47:34 +0000471 byte|=0x01;
472 bit++;
473 if (bit == 8)
474 {
475 *q++=byte;
476 bit=0;
477 byte=0;
478 }
cristyed231572011-07-14 02:18:59 +0000479 p+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000480 }
481 if (bit != 0)
482 *q++=byte << (8-bit);
483 if (image->previous == (Image *) NULL)
484 {
cristycee97112010-05-28 00:44:52 +0000485 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
cristy524222d2011-04-25 00:37:06 +0000486 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000487 if (status == MagickFalse)
488 break;
489 }
490 }
491 /*
492 Initialize JBIG info structure.
493 */
cristyf6fe0a12010-05-30 00:44:47 +0000494 jbg_enc_init(&jbig_info,(unsigned long) image->columns,(unsigned long)
495 image->rows,1,&pixels,(void (*)(unsigned char *,size_t,void *))
496 JBIGEncode,image);
cristy3ed852e2009-09-05 21:47:34 +0000497 if (image_info->scene != 0)
498 jbg_enc_layers(&jbig_info,(int) image_info->scene);
499 else
500 {
cristybb503372010-05-27 20:51:26 +0000501 size_t
cristy3ed852e2009-09-05 21:47:34 +0000502 x_resolution,
503 y_resolution;
504
505 x_resolution=640;
506 y_resolution=480;
cristy3ed852e2009-09-05 21:47:34 +0000507 if (image_info->density != (char *) NULL)
508 {
509 GeometryInfo
510 geometry_info;
511
512 MagickStatusType
513 flags;
514
515 flags=ParseGeometry(image_info->density,&geometry_info);
516 x_resolution=geometry_info.rho;
517 y_resolution=geometry_info.sigma;
518 if ((flags & SigmaValue) == 0)
519 y_resolution=x_resolution;
520 }
521 if (image->units == PixelsPerCentimeterResolution)
522 {
cristybb503372010-05-27 20:51:26 +0000523 x_resolution=(size_t) (100.0*2.54*x_resolution+0.5)/100.0;
524 y_resolution=(size_t) (100.0*2.54*y_resolution+0.5)/100.0;
cristy3ed852e2009-09-05 21:47:34 +0000525 }
cristyf6fe0a12010-05-30 00:44:47 +0000526 (void) jbg_enc_lrlmax(&jbig_info,(unsigned long) x_resolution,
527 (unsigned long) y_resolution);
cristy3ed852e2009-09-05 21:47:34 +0000528 }
529 (void) jbg_enc_lrange(&jbig_info,-1,-1);
530 jbg_enc_options(&jbig_info,JBG_ILEAVE | JBG_SMID,JBG_TPDON | JBG_TPBON |
531 JBG_DPON,version < 1.6 ? -1 : 0,-1,-1);
532 /*
533 Write JBIG image.
534 */
535 jbg_enc_out(&jbig_info);
536 jbg_enc_free(&jbig_info);
537 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
538 if (GetNextImageInList(image) == (Image *) NULL)
539 break;
540 image=SyncNextImageInList(image);
541 status=SetImageProgress(image,SaveImagesTag,scene++,
542 GetImageListLength(image));
543 if (status == MagickFalse)
544 break;
545 } while (image_info->adjoin != MagickFalse);
546 (void) CloseBlob(image);
547 return(MagickTrue);
548}
549#endif