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