blob: fad10b6aee1f38601ff1e0f47f180045e5ce93f9 [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"
47#include "magick/colorspace.h"
48#include "magick/constitute.h"
49#include "magick/exception.h"
50#include "magick/exception-private.h"
51#include "magick/geometry.h"
52#include "magick/image.h"
53#include "magick/image-private.h"
54#include "magick/list.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
57#include "magick/monitor.h"
58#include "magick/monitor-private.h"
59#include "magick/nt-feature.h"
60#include "magick/quantum-private.h"
61#include "magick/static.h"
62#include "magick/string_.h"
63#include "magick/module.h"
64#if defined(MAGICKCORE_JBIG_DELEGATE)
65#include "jbig.h"
66#endif
67
68/*
69 Forward declarations.
70*/
71#if defined(MAGICKCORE_JBIG_DELEGATE)
72static MagickBooleanType
73 WriteJBIGImage(const ImageInfo *,Image *);
74#endif
75
76#if defined(MAGICKCORE_JBIG_DELEGATE)
77/*
78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79% %
80% %
81% %
82% R e a d J B I G I m a g e %
83% %
84% %
85% %
86%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87%
88% ReadJBIGImage() reads a JBIG image file and returns it. It
89% allocates the memory necessary for the new Image structure and returns a
90% pointer to the new image.
91%
92% The format of the ReadJBIGImage method is:
93%
94% Image *ReadJBIGImage(const ImageInfo *image_info,
95% ExceptionInfo *exception)
96%
97% A description of each parameter follows:
98%
99% o image_info: the image info.
100%
101% o exception: return any errors or warnings in this structure.
102%
103*/
104static Image *ReadJBIGImage(const ImageInfo *image_info,
105 ExceptionInfo *exception)
106{
107 Image
108 *image;
109
110 IndexPacket
111 index;
112
113 long
114 length,
115 y;
116
117 MagickBooleanType
118 status;
119
120 register IndexPacket
121 *indexes;
122
123 register long
124 x;
125
126 register PixelPacket
127 *q;
128
129 register unsigned char
130 *p;
131
132 ssize_t
133 count;
134
135 struct jbg_dec_state
136 jbig_info;
137
138 unsigned char
139 bit,
140 *buffer,
141 byte;
142
143 /*
144 Open image file.
145 */
146 assert(image_info != (const ImageInfo *) NULL);
147 assert(image_info->signature == MagickSignature);
148 if (image_info->debug != MagickFalse)
149 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
150 image_info->filename);
151 assert(exception != (ExceptionInfo *) NULL);
152 assert(exception->signature == MagickSignature);
153 image=AcquireImage(image_info);
154 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
155 if (status == MagickFalse)
156 {
157 image=DestroyImageList(image);
158 return((Image *) NULL);
159 }
160 /*
161 Initialize JBIG toolkit.
162 */
163 jbg_dec_init(&jbig_info);
164 jbg_dec_maxsize(&jbig_info,(unsigned long) image->columns,(unsigned long)
165 image->rows);
166 image->columns=jbg_dec_getwidth(&jbig_info);
167 image->rows=jbg_dec_getheight(&jbig_info);
168 image->depth=8;
169 image->storage_class=PseudoClass;
170 image->colors=2;
171 /*
172 Read JBIG file.
173 */
174 buffer=(unsigned char *) AcquireQuantumMemory(MagickMaxBufferExtent,
175 sizeof(*buffer));
176 if (buffer == (unsigned char *) NULL)
177 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
178 status=JBG_EAGAIN;
179 do
180 {
181 length=(long) ReadBlob(image,MagickMaxBufferExtent,buffer);
182 if (length == 0)
183 break;
184 p=buffer;
185 count=0;
186 while ((length > 0) && ((status == JBG_EAGAIN) || (status == JBG_EOK)))
187 {
188 size_t
189 count;
190
191 status=jbg_dec_in(&jbig_info,p,length,&count);
192 p+=count;
193 length-=(long) count;
194 }
195 } while ((status == JBG_EAGAIN) || (status == JBG_EOK));
196 /*
197 Create colormap.
198 */
199 image->columns=jbg_dec_getwidth(&jbig_info);
200 image->rows=jbg_dec_getheight(&jbig_info);
201 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);
223 for (y=0; y < (long) image->rows; y++)
224 {
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;
231 for (x=0; x < (long) image->columns; x++)
232 {
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;
240 indexes[x]=index;
241 *q++=image->colormap[(long) index];
242 }
243 if (SyncAuthenticPixels(image,exception) == MagickFalse)
244 break;
245 status=SetImageProgress(image,LoadImageTag,y,image->rows);
246 if (status == MagickFalse)
247 break;
248 }
249 /*
250 Free scale resource.
251 */
252 jbg_dec_free(&jbig_info);
253 buffer=(unsigned char *) RelinquishMagickMemory(buffer);
254 (void) CloseBlob(image);
255 return(GetFirstImageInList(image));
256}
257#endif
258
259/*
260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261% %
262% %
263% %
264% R e g i s t e r J B I G I m a g e %
265% %
266% %
267% %
268%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269%
270% RegisterJBIGImage() adds attributes for the JBIG image format to
271% the list of supported formats. The attributes include the image format
272% tag, a method to read and/or write the format, whether the format
273% supports the saving of more than one frame to the same file or blob,
274% whether the format supports native in-memory I/O, and a brief
275% description of the format.
276%
277% The format of the RegisterJBIGImage method is:
278%
279% unsigned long RegisterJBIGImage(void)
280%
281*/
282ModuleExport unsigned long RegisterJBIGImage(void)
283{
284#define JBIGDescription "Joint Bi-level Image experts Group interchange format"
285
286 char
287 version[MaxTextExtent];
288
289 MagickInfo
290 *entry;
291
292 *version='\0';
293#if defined(JBG_VERSION)
294 (void) CopyMagickString(version,JBG_VERSION,MaxTextExtent);
295#endif
296 entry=SetMagickInfo("BIE");
297#if defined(MAGICKCORE_JBIG_DELEGATE)
298 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
299 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
300#endif
301 entry->adjoin=MagickFalse;
302 entry->description=ConstantString(JBIGDescription);
303 if (*version != '\0')
304 entry->version=ConstantString(version);
305 entry->module=ConstantString("JBIG");
306 (void) RegisterMagickInfo(entry);
307 entry=SetMagickInfo("JBG");
308#if defined(MAGICKCORE_JBIG_DELEGATE)
309 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
310 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
311#endif
312 entry->description=ConstantString(JBIGDescription);
313 if (*version != '\0')
314 entry->version=ConstantString(version);
315 entry->module=ConstantString("JBIG");
316 (void) RegisterMagickInfo(entry);
317 entry=SetMagickInfo("JBIG");
318#if defined(MAGICKCORE_JBIG_DELEGATE)
319 entry->decoder=(DecodeImageHandler *) ReadJBIGImage;
320 entry->encoder=(EncodeImageHandler *) WriteJBIGImage;
321#endif
322 entry->description=ConstantString(JBIGDescription);
323 if (*version != '\0')
324 entry->version=ConstantString(version);
325 entry->module=ConstantString("JBIG");
326 (void) RegisterMagickInfo(entry);
327 return(MagickImageCoderSignature);
328}
329
330/*
331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332% %
333% %
334% %
335% U n r e g i s t e r J B I G I m a g e %
336% %
337% %
338% %
339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340%
341% UnregisterJBIGImage() removes format registrations made by the
342% JBIG module from the list of supported formats.
343%
344% The format of the UnregisterJBIGImage method is:
345%
346% UnregisterJBIGImage(void)
347%
348*/
349ModuleExport void UnregisterJBIGImage(void)
350{
351 (void) UnregisterMagickInfo("BIE");
352 (void) UnregisterMagickInfo("JBG");
353 (void) UnregisterMagickInfo("JBIG");
354}
355
356#if defined(MAGICKCORE_JBIG_DELEGATE)
357/*
358%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
359% %
360% %
361% %
362% W r i t e J B I G I m a g e %
363% %
364% %
365% %
366%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
367%
368% WriteJBIGImage() writes an image in the JBIG encoded image format.
369%
370% The format of the WriteJBIGImage method is:
371%
372% MagickBooleanType WriteJBIGImage(const ImageInfo *image_info,Image *image)
373%
374% A description of each parameter follows.
375%
376% o image_info: the image info.
377%
378% o image: The image.
379%
380%
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,
393 Image *image)
394{
395 double
396 version;
397
398 long
399 y;
400
401 MagickBooleanType
402 status;
403
404 MagickOffsetType
405 scene;
406
407 register const IndexPacket
408 *indexes;
409
410 register const PixelPacket
411 *p;
412
413 register long
414 x;
415
416 register unsigned char
417 *q;
418
419 struct jbg_enc_state
420 jbig_info;
421
422 unsigned char
423 bit,
424 byte,
425 *pixels;
426
427 unsigned long
428 number_packets;
429
430 /*
431 Open image file.
432 */
433 assert(image_info != (const ImageInfo *) NULL);
434 assert(image_info->signature == MagickSignature);
435 assert(image != (Image *) NULL);
436 assert(image->signature == MagickSignature);
437 if (image->debug != MagickFalse)
438 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
439 status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
440 if (status == MagickFalse)
441 return(status);
442 version=strtod(JBG_VERSION,(char **) NULL);
443 scene=0;
444 do
445 {
446 /*
447 Allocate pixel data.
448 */
449 if (image->colorspace != RGBColorspace)
450 (void) TransformImageColorspace(image,RGBColorspace);
451 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 */
459 (void) SetImageType(image,BilevelType);
460 q=pixels;
461 for (y=0; y < (long) image->rows; y++)
462 {
463 p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
464 if (p == (const PixelPacket *) NULL)
465 break;
466 indexes=GetVirtualIndexQueue(image);
467 bit=0;
468 byte=0;
469 for (x=0; x < (long) image->columns; x++)
470 {
471 byte<<=1;
472 if (PixelIntensity(p) < (QuantumRange/2.0))
473 byte|=0x01;
474 bit++;
475 if (bit == 8)
476 {
477 *q++=byte;
478 bit=0;
479 byte=0;
480 }
481 p++;
482 }
483 if (bit != 0)
484 *q++=byte << (8-bit);
485 if (image->previous == (Image *) NULL)
486 {
487 status=SetImageProgress(image,SaveImageTag,y,image->rows);
488 if (status == MagickFalse)
489 break;
490 }
491 }
492 /*
493 Initialize JBIG info structure.
494 */
495 jbg_enc_init(&jbig_info,image->columns,image->rows,1,&pixels,
496 (void (*)(unsigned char *,size_t,void *)) JBIGEncode,image);
497 if (image_info->scene != 0)
498 jbg_enc_layers(&jbig_info,(int) image_info->scene);
499 else
500 {
501 long
502 sans_offset;
503
504 unsigned long
505 x_resolution,
506 y_resolution;
507
508 x_resolution=640;
509 y_resolution=480;
510 sans_offset=0;
511 if (image_info->density != (char *) NULL)
512 {
513 GeometryInfo
514 geometry_info;
515
516 MagickStatusType
517 flags;
518
519 flags=ParseGeometry(image_info->density,&geometry_info);
520 x_resolution=geometry_info.rho;
521 y_resolution=geometry_info.sigma;
522 if ((flags & SigmaValue) == 0)
523 y_resolution=x_resolution;
524 }
525 if (image->units == PixelsPerCentimeterResolution)
526 {
527 x_resolution*=2.54;
528 y_resolution*=2.54;
529 }
530 (void) jbg_enc_lrlmax(&jbig_info,x_resolution,y_resolution);
531 }
532 (void) jbg_enc_lrange(&jbig_info,-1,-1);
533 jbg_enc_options(&jbig_info,JBG_ILEAVE | JBG_SMID,JBG_TPDON | JBG_TPBON |
534 JBG_DPON,version < 1.6 ? -1 : 0,-1,-1);
535 /*
536 Write JBIG image.
537 */
538 jbg_enc_out(&jbig_info);
539 jbg_enc_free(&jbig_info);
540 pixels=(unsigned char *) RelinquishMagickMemory(pixels);
541 if (GetNextImageInList(image) == (Image *) NULL)
542 break;
543 image=SyncNextImageInList(image);
544 status=SetImageProgress(image,SaveImagesTag,scene++,
545 GetImageListLength(image));
546 if (status == MagickFalse)
547 break;
548 } while (image_info->adjoin != MagickFalse);
549 (void) CloseBlob(image);
550 return(MagickTrue);
551}
552#endif