blob: 4f7ad6886b5608e26e2bc0c49951737dbc2010ac [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% %
cristy16af1cb2009-12-11 21:38:29 +000020% Copyright 1999-2010 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
114 long
115 length,
116 y;
117
118 MagickBooleanType
119 status;
120
121 register IndexPacket
122 *indexes;
123
124 register long
125 x;
126
127 register PixelPacket
128 *q;
129
130 register unsigned char
131 *p;
132
133 ssize_t
134 count;
135
136 struct jbg_dec_state
137 jbig_info;
138
139 unsigned char
140 bit,
141 *buffer,
142 byte;
143
144 /*
145 Open image file.
146 */
147 assert(image_info != (const ImageInfo *) NULL);
148 assert(image_info->signature == MagickSignature);
149 if (image_info->debug != MagickFalse)
150 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
151 image_info->filename);
152 assert(exception != (ExceptionInfo *) NULL);
153 assert(exception->signature == MagickSignature);
154 image=AcquireImage(image_info);
155 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
156 if (status == MagickFalse)
157 {
158 image=DestroyImageList(image);
159 return((Image *) NULL);
160 }
161 /*
162 Initialize JBIG toolkit.
163 */
164 jbg_dec_init(&jbig_info);
165 jbg_dec_maxsize(&jbig_info,(unsigned long) image->columns,(unsigned long)
166 image->rows);
167 image->columns=jbg_dec_getwidth(&jbig_info);
168 image->rows=jbg_dec_getheight(&jbig_info);
169 image->depth=8;
170 image->storage_class=PseudoClass;
171 image->colors=2;
172 /*
173 Read JBIG file.
174 */
175 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
176 sizeof(*buffer));
177 if (buffer == (unsigned char *) NULL)
178 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
179 status=JBG_EAGAIN;
180 do
181 {
182 length=(long) ReadBlob(image,MagickMaxBufferExtent,buffer);
183 if (length == 0)
184 break;
185 p=buffer;
186 count=0;
187 while ((length > 0) && ((status == JBG_EAGAIN) || (status == JBG_EOK)))
188 {
189 size_t
190 count;
191
192 status=jbg_dec_in(&jbig_info,p,length,&count);
193 p+=count;
194 length-=(long) count;
195 }
196 } while ((status == JBG_EAGAIN) || (status == JBG_EOK));
197 /*
198 Create colormap.
199 */
200 image->columns=jbg_dec_getwidth(&jbig_info);
201 image->rows=jbg_dec_getheight(&jbig_info);
202 if (AcquireImageColormap(image,2) == MagickFalse)
203 {
204 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
205 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
206 }
207 image->colormap[0].red=0;
208 image->colormap[0].green=0;
209 image->colormap[0].blue=0;
210 image->colormap[1].red=QuantumRange;
211 image->colormap[1].green=QuantumRange;
212 image->colormap[1].blue=QuantumRange;
213 image->x_resolution=300;
214 image->y_resolution=300;
215 if (image_info->ping != MagickFalse)
216 {
217 (void) CloseBlob(image);
218 return(GetFirstImageInList(image));
219 }
220 /*
221 Convert X bitmap image to pixel packets.
222 */
223 p=jbg_dec_getimage(&jbig_info,0);
224 for (y=0; y < (long) image->rows; y++)
225 {
226 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
227 if (q == (PixelPacket *) NULL)
228 break;
229 indexes=GetAuthenticIndexQueue(image);
230 bit=0;
231 byte=0;
232 for (x=0; x < (long) image->columns; x++)
233 {
234 if (bit == 0)
235 byte=(*p++);
236 index=(byte & 0x80) ? 0 : 1;
237 bit++;
238 byte<<=1;
239 if (bit == 8)
240 bit=0;
241 indexes[x]=index;
242 *q++=image->colormap[(long) index];
243 }
244 if (SyncAuthenticPixels(image,exception) == MagickFalse)
245 break;
246 status=SetImageProgress(image,LoadImageTag,y,image->rows);
247 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%
280% unsigned long RegisterJBIGImage(void)
281%
282*/
283ModuleExport unsigned long RegisterJBIGImage(void)
284{
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
399 long
400 y;
401
402 MagickBooleanType
403 status;
404
405 MagickOffsetType
406 scene;
407
408 register const IndexPacket
409 *indexes;
410
411 register const PixelPacket
412 *p;
413
414 register long
415 x;
416
417 register unsigned char
418 *q;
419
420 struct jbg_enc_state
421 jbig_info;
422
423 unsigned char
424 bit,
425 byte,
426 *pixels;
427
428 unsigned long
429 number_packets;
430
431 /*
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;
462 for (y=0; y < (long) image->rows; y++)
463 {
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;
470 for (x=0; x < (long) image->columns; x++)
471 {
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 {
488 status=SetImageProgress(image,SaveImageTag,y,image->rows);
489 if (status == MagickFalse)
490 break;
491 }
492 }
493 /*
494 Initialize JBIG info structure.
495 */
496 jbg_enc_init(&jbig_info,image->columns,image->rows,1,&pixels,
497 (void (*)(unsigned char *,size_t,void *)) JBIGEncode,image);
498 if (image_info->scene != 0)
499 jbg_enc_layers(&jbig_info,(int) image_info->scene);
500 else
501 {
502 long
503 sans_offset;
504
505 unsigned long
506 x_resolution,
507 y_resolution;
508
509 x_resolution=640;
510 y_resolution=480;
511 sans_offset=0;
512 if (image_info->density != (char *) NULL)
513 {
514 GeometryInfo
515 geometry_info;
516
517 MagickStatusType
518 flags;
519
520 flags=ParseGeometry(image_info->density,&geometry_info);
521 x_resolution=geometry_info.rho;
522 y_resolution=geometry_info.sigma;
523 if ((flags & SigmaValue) == 0)
524 y_resolution=x_resolution;
525 }
526 if (image->units == PixelsPerCentimeterResolution)
527 {
cristy0881b522010-04-24 23:45:19 +0000528 x_resolution=(unsigned long) (100.0*2.54*x_resolution+0.5)/100.0;
529 y_resolution=(unsigned long) (100.0*2.54*y_resolution+0.5)/100.0;
cristy3ed852e2009-09-05 21:47:34 +0000530 }
531 (void) jbg_enc_lrlmax(&jbig_info,x_resolution,y_resolution);
532 }
533 (void) jbg_enc_lrange(&jbig_info,-1,-1);
534 jbg_enc_options(&jbig_info,JBG_ILEAVE | JBG_SMID,JBG_TPDON | JBG_TPBON |
535 JBG_DPON,version < 1.6 ? -1 : 0,-1,-1);
536 /*
537 Write JBIG image.
538 */
539 jbg_enc_out(&jbig_info);
540 jbg_enc_free(&jbig_info);
541 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
542 if (GetNextImageInList(image) == (Image *) NULL)
543 break;
544 image=SyncNextImageInList(image);
545 status=SetImageProgress(image,SaveImagesTag,scene++,
546 GetImageListLength(image));
547 if (status == MagickFalse)
548 break;
549 } while (image_info->adjoin != MagickFalse);
550 (void) CloseBlob(image);
551 return(MagickTrue);
552}
553#endif