]> granicus.if.org Git - imagemagick/blob - coders/djvu.c
(no commit message)
[imagemagick] / coders / djvu.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                         DDDD       J  V   V  U   U                          %
7 %                         D   D      J  V   V  U   U                          %
8 %                         D   D      J  V   V  U   U                          %
9 %                         D   D  J   J   V V   U   U                          %
10 %                         DDDD    JJJ     V     UUU                           %
11 %                                                                             %
12 %                                                                             %
13 %                             Read DjVu Images.                               %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                   Cristy                                    %
17 %                                 July 1992                                   %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2015 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 %    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 \f
39 /*
40   Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/cache.h"
46 #include "MagickCore/colormap.h"
47 #include "MagickCore/constitute.h"
48 #include "MagickCore/exception.h"
49 #include "MagickCore/exception-private.h"
50 #include "MagickCore/list.h"
51 #include "MagickCore/magick.h"
52 #include "MagickCore/memory_.h"
53 #include "MagickCore/monitor.h"
54 #include "MagickCore/monitor-private.h"
55 #include "MagickCore/pixel-accessor.h"
56 #include "MagickCore/quantum-private.h"
57 #include "MagickCore/static.h"
58 #include "MagickCore/string_.h"
59 #include "MagickCore/module.h"
60 #if defined(MAGICKCORE_DJVU_DELEGATE)
61 #include <libdjvu/ddjvuapi.h>
62 #endif
63 \f
64 /*
65 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66 %                                                                             %
67 %                                                                             %
68 %                                                                             %
69 %   I s D J V U                                                               %
70 %                                                                             %
71 %                                                                             %
72 %                                                                             %
73 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74 %
75 %  IsDJVU() returns MagickTrue if the image format type, identified by the
76 %  magick string, is DJVU.
77 %
78 %  The format of the IsDJVU method is:
79 %
80 %      MagickBooleanType IsDJVU(const unsigned char *magick,const size_t length)
81 %
82 %  A description of each parameter follows:
83 %
84 %    o magick: compare image format pattern against these bytes.
85 %
86 %    o length: Specifies the length of the magick string.
87 %
88 */
89 static MagickBooleanType IsDJVU(const unsigned char *magick,const size_t length)
90 {
91   if (length < 8)
92     return(MagickFalse);
93   if (memcmp(magick,"AT&TFORM",8) == 0)
94     return(MagickTrue);
95   return(MagickFalse);
96 }
97 \f
98 #if defined(MAGICKCORE_DJVU_DELEGATE)
99 /*
100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101 %                                                                             %
102 %                                                                             %
103 %                                                                             %
104 %   R e a d D J V U I m a g e                                                 %
105 %                                                                             %
106 %                                                                             %
107 %                                                                             %
108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109 %
110 %  ReadDJVUImage() reads DJVU image and returns it.  It allocates the memory
111 %  necessary for the new Image structure and returns a pointer to the new
112 %  image or set of images.
113 %
114 %  The format of the ReadDJVUImage method is:
115 %
116 %      Image *ReadDJVUImage(const ImageInfo *image_info,
117 %        ExceptionInfo *exception)
118 %
119 %  A description of each parameter follows:
120 %
121 %    o image_info: the image info.
122 %
123 %    o exception: return any errors or warnings in this structure.
124 %
125 */
126
127 #if defined(__cplusplus) || defined(c_plusplus)
128 extern "C" {
129 #endif
130
131 typedef struct _LoadContext
132    LoadContext;
133
134 struct _LoadContext
135 {
136   ddjvu_context_t* context;
137   ddjvu_document_t *document;
138   ddjvu_page_t *page;
139   int streamid;
140   int pages;
141   Image *image;
142 };
143
144 #define BLOCKSIZE  65536
145 #if 0
146 static void
147 pump_data(Image *image, LoadContext* lc)
148 {
149         int blocksize = BLOCKSIZE;
150         char data[BLOCKSIZE];
151         int size;
152
153         /* i might check for a condition! */
154         while ((size = (size_t) ReadBlob(image,(size_t) blocksize,data)) == blocksize) {
155                 ddjvu_stream_write(lc->document, lc->streamid, data, size);
156         }
157         if (size)
158                 ddjvu_stream_write(lc->document, lc->streamid, data, size);
159         ddjvu_stream_close(lc->document, lc->streamid, 0);
160 }
161 #endif
162
163 /* returns NULL only after all is delivered! */
164 static ddjvu_message_t*
165 pump_data_until_message(LoadContext *lc,Image *image) /* ddjvu_context_t *context, type ddjvu_document_type_t */
166 {
167         size_t blocksize = BLOCKSIZE;
168         unsigned char data[BLOCKSIZE];
169         size_t size;
170         ddjvu_message_t *message;
171
172         /* i might check for a condition! */
173         size=0;
174         while (!(message = ddjvu_message_peek(lc->context))
175                && (size = (size_t) ReadBlob(image,(size_t) blocksize,data)) == blocksize) {
176                 ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
177         }
178         if (message)
179                 return message;
180         if (size)
181                 ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
182         ddjvu_stream_close(lc->document, lc->streamid, 0);
183         return NULL;
184 }
185 #define DEBUG 0
186
187 #if DEBUG
188 static const char*
189 message_tag_name(ddjvu_message_tag_t tag)
190 {
191    static char* names[] =
192       {
193          "ERROR",
194          "INFO",
195          "NEWSTREAM",
196          "DOCINFO",
197          "PAGEINFO",
198          "RELAYOUT",
199          "REDISPLAY",
200          "CHUNK",
201          "THUMBNAIL",
202          "PROGRESS",
203       };
204    if (tag <= DDJVU_PROGRESS)
205       return names[tag];
206    else {
207       /* bark! */
208       return 0;
209    }
210 }
211 #endif
212
213 /* write out nice info on the message,
214  * and store in *user* data the info on progress.
215  * */
216 int
217 process_message(ddjvu_message_t *message)
218 {
219
220 #if 0
221    ddjvu_context_t* context= message->m_any.context;
222 #endif
223
224    if (! message)
225       return(-1);
226 #if DEBUG
227    printf("*** %s: %s.\n",__FUNCTION__, message_tag_name(message->m_any.tag));
228 #endif
229
230
231    switch (message->m_any.tag){
232    case DDJVU_DOCINFO:
233    {
234       ddjvu_document_t* document= message->m_any.document;
235       /* ddjvu_document_decoding_status  is set by libdjvu! */
236       /* we have some info on the document  */
237       LoadContext *lc = (LoadContext *) ddjvu_document_get_user_data(document);
238       lc->pages = ddjvu_document_get_pagenum(document);
239 #if DEBUG
240       printf("the doc has %d pages\n", ddjvu_document_get_pagenum(document));
241 #endif
242       break;
243    }
244    case DDJVU_CHUNK:
245 #if DEBUG
246            printf("the name of the chunk is: %s\n", message->m_chunk.chunkid);
247 #endif
248            break;
249
250
251    case DDJVU_RELAYOUT:
252    case DDJVU_PAGEINFO:
253    {
254 #if 0
255       ddjvu_page_t* page = message->m_any.page;
256       page_info* info = ddjvu_page_get_user_data(page);
257
258       printf("page decoding status: %d %s%s%s\n",
259              ddjvu_page_decoding_status(page),
260              status_color, status_name(ddjvu_page_decoding_status(page)), color_reset);
261
262       printf("the page LAYOUT changed: width x height: %d x %d @ %d dpi. Version %d, type %d\n",
263              // printf("page info:\n width x height: %d x %d @ %d dpi, version %d, type %d\n",
264              ddjvu_page_get_width(page),
265              ddjvu_page_get_height(page),
266              ddjvu_page_get_resolution(page),
267              ddjvu_page_get_version(page),
268              /* DDJVU_PAGETYPE_BITONAL */
269              ddjvu_page_get_type(page));
270
271       info->info = 1;
272 #endif
273       break;
274    }
275
276    case DDJVU_REDISPLAY:
277    {
278
279 #if 0
280     ddjvu_page_t* page = message->m_any.page;
281       page_info* info = ddjvu_page_get_user_data(page);
282
283       printf("the page can/should be REDISPLAYED\n");
284       info->display = 1;
285 #endif
286       break;
287    }
288
289    case DDJVU_PROGRESS:
290 #if DEBUG
291            printf("PROGRESS:\n");
292 #endif
293            break;
294    case DDJVU_ERROR:
295            printf("simply ERROR!\n message:\t%s\nfunction:\t%s(file %s)\nlineno:\t%d\n",
296                   message->m_error.message,
297                   message->m_error.function,
298                   message->m_error.filename,
299                   message->m_error.lineno);
300            break;
301    case DDJVU_INFO:
302 #if DEBUG
303            printf("INFO: %s!\n", message->m_info.message);
304 #endif
305            break;
306    default:
307       printf("unexpected\n");
308    };
309   return(message->m_any.tag);
310 }
311
312
313 #if defined(__cplusplus) || defined(c_plusplus)
314 }
315 #endif
316
317
318 #define RGB 1
319
320 /*
321  * DjVu advertised readiness to provide bitmap: So get it!
322  * we use the RGB format!
323  */
324 static void
325 get_page_image(LoadContext *lc, ddjvu_page_t *page, int x, int y, int w, int h, ExceptionInfo *exception ) {
326   ddjvu_format_t
327     *format;
328
329   ddjvu_page_type_t
330     type;
331
332   Image
333     *image;
334
335   int
336     ret,
337     stride;
338
339   unsigned char
340     *q;
341
342         ddjvu_rect_t rect;
343         rect.x = x;
344         rect.y = y;
345         rect.w = (unsigned int) w;             /* /10 */
346         rect.h = (unsigned int) h;             /* /10 */
347
348         image = lc->image;
349         type = ddjvu_page_get_type(lc->page);
350
351         /* stride of this temporary buffer: */
352         stride = (type == DDJVU_PAGETYPE_BITONAL)?
353                 (image->columns + 7)/8 : image->columns *3;
354
355         q = (unsigned char *) AcquireQuantumMemory(image->rows,stride);
356         if (q == (unsigned char *) NULL)
357           return;
358
359         format = ddjvu_format_create(
360                 (type == DDJVU_PAGETYPE_BITONAL)?DDJVU_FORMAT_LSBTOMSB : DDJVU_FORMAT_RGB24,
361                 /* DDJVU_FORMAT_RGB24
362                  * DDJVU_FORMAT_RGBMASK32*/
363                 /* DDJVU_FORMAT_RGBMASK32 */
364                 0, NULL);
365
366 #if 0
367         /* fixme:  ThrowReaderException is a macro, which uses  `exception' variable */
368         if (format == NULL)
369                 {
370                         abort();
371                         /* ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); */
372                 }
373
374 #endif
375         ddjvu_format_set_row_order(format, 1);
376         ddjvu_format_set_y_direction(format, 1);
377
378         ret = ddjvu_page_render(page,
379                                     DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
380                                     &rect,
381                                     &rect,     /* mmc: ?? */
382                                     format,
383                                     stride, /* ?? */
384                                     (char*)q);
385         (void) ret;
386         ddjvu_format_release(format);
387
388
389         if (type == DDJVU_PAGETYPE_BITONAL) {
390                 /*  */
391 #if DEBUG
392                 printf("%s: expanding BITONAL page/image\n", __FUNCTION__);
393 #endif
394                 size_t bit, byte;
395
396                 for (y=0; y < (ssize_t) image->rows; y++)
397                         {
398                                 Quantum * o = QueueAuthenticPixels(image,0,y,image->columns,1,exception);
399                                 if (o == (Quantum *) NULL)
400                                         break;
401                                 bit=0;
402                                 byte=0;
403
404                                 /* fixme:  the non-aligned, last =<7 bits ! that's ok!!!*/
405                                 for (x= 0; x < (ssize_t) image->columns; x++)
406                                         {
407                                                 if (bit == 0) byte= (size_t) q[(y * stride) + (x / 8)];
408
409                                                 SetPixelIndex(image,(Quantum) (((byte & 0x01) != 0) ? 0x00 : 0x01),o);
410                                                 bit++;
411                                                 if (bit == 8)
412                                                         bit=0;
413                                                 byte>>=1;
414                                           o+=GetPixelChannels(image);
415                                         }
416                                 if (SyncAuthenticPixels(image,exception) == MagickFalse)
417                                         break;
418                         }
419                 if (!image->ping)
420                   SyncImage(image,exception);
421         } else {
422 #if DEBUG
423                 printf("%s: expanding PHOTO page/image\n", __FUNCTION__);
424 #endif
425                 /* now transfer line-wise: */
426                 ssize_t i;
427 #if 0
428                 /* old: */
429                 char* r;
430 #else
431                 register Quantum *r;
432                 unsigned char *s;
433 #endif
434                 s=q;
435                 for (i = 0;i< (ssize_t) image->rows; i++)
436                         {
437 #if DEBUG
438                                if (i % 1000 == 0) printf("%d\n",i);
439 #endif
440                                r = QueueAuthenticPixels(image,0,i,image->columns,1,exception);
441                                if (r == (Quantum *) NULL)
442                                  break;
443                   for (x=0; x < (ssize_t) image->columns; x++)
444                   {
445                     SetPixelRed(image,ScaleCharToQuantum(*s++),r);
446                     SetPixelGreen(image,ScaleCharToQuantum(*s++),r);
447                     SetPixelBlue(image,ScaleCharToQuantum(*s++),r);
448                     r+=GetPixelChannels(image);
449                   }
450
451                               (void) SyncAuthenticPixels(image,exception);
452                         }
453         }
454         q=(unsigned char *) RelinquishMagickMemory(q);
455 }
456
457
458 #if defined(MAGICKCORE_DJVU_DELEGATE)
459
460 #if 0
461 static int
462 get_page_line(LoadContext *lc, int row, QuantumInfo* quantum_info)
463 {
464   ddjvu_format_t
465     *format;
466
467   int
468     ret;
469
470   size_t
471     stride;
472
473   unsigned char
474     *q;
475
476         ddjvu_rect_t rect, pagerect;
477         rect.x = 0;
478         rect.y = row;
479         rect.w = lc->image->columns;             /* /10 */
480         rect.h = 1;             /* /10 */
481
482         pagerect.x = 0;
483         pagerect.y = 0;
484         pagerect.w = lc->image->columns;
485         pagerect.h = lc->image->rows;
486
487
488         format = ddjvu_format_create(
489 #if RGB
490                 DDJVU_FORMAT_RGB24
491 #else
492                 DDJVU_FORMAT_GREY8
493 #endif
494                 ,
495                 0, NULL);
496         ddjvu_format_set_row_order(format, 1);
497         ddjvu_format_set_y_direction(format, 1);
498
499         stride=1;
500 #if RGB
501         stride=3;
502 #endif
503         q = (unsigned char *) AcquireQuantumMemory(lc->image->columns,stride);
504
505         ret = ddjvu_page_render(lc->page,
506                                     DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
507                                     &pagerect,
508                                     &rect,     /* mmc: ?? */
509                                     format,
510                                     pagerect.w * 3, /* ?? */
511                                     (char*)q);
512
513         ImportQuantumPixels(lc->image,
514                             (CacheView *) NULL,
515                             quantum_info,
516 #if RGB
517                             RGBQuantum
518 #else
519                             GrayQuantum
520 #endif
521                             ,q,&lc->image->exception);
522         q=(unsigned char *) RelinquishMagickMemory(q);
523         ddjvu_format_release(format);
524         return ret;
525 }
526 #endif
527 #endif
528
529 /*
530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
531 %                                                                             %
532 %                                                                             %
533 %                                                                             %
534 %   R e a d O n e D J V U I m a g e                                           %
535 %                                                                             %
536 %                                                                             %
537 %                                                                             %
538 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539 %
540 %  ReadOneDJVUImage() reads a Portable Network Graphics (DJVU) image file
541 %  (minus the 8-byte signature)  and returns it.  It allocates the memory
542 %  necessary for the new Image structure and returns a pointer to the new
543 %  image.
544 %
545 %  The format of the ReadOneDJVUImage method is:
546 %
547 %      Image *ReadOneDJVUImage(MngInfo *mng_info, const ImageInfo *image_info,
548 %         ExceptionInfo *exception)
549 %
550 %  A description of each parameter follows:
551 %
552 %    o mng_info: Specifies a pointer to a MngInfo structure.
553 %
554 %    o image_info: the image info.
555 %
556 %    o exception: return any errors or warnings in this structure.
557 %
558 */
559
560 static inline double MagickMax(const double x,const double y)
561 {
562   if (x > y)
563     return(x);
564   return(y);
565 }
566
567 static Image *ReadOneDJVUImage(LoadContext* lc,const int pagenum,
568   const ImageInfo *image_info,ExceptionInfo *exception)
569 {
570   ddjvu_page_type_t
571      type;
572
573   ddjvu_pageinfo_t info;
574   ddjvu_message_t *message;
575   Image *image;
576   int logging;
577   int tag;
578   MagickBooleanType status;
579
580         /* so, we know that the page is there! Get its dimension, and  */
581
582         /* Read one DJVU image */
583         image = lc->image;
584
585         /* register Quantum *q; */
586
587         logging=LogMagickEvent(CoderEvent,GetMagickModule(), "  enter ReadOneDJVUImage()");
588         (void) logging;
589
590 #if DEBUG
591         printf("====  Loading the page %d\n", pagenum);
592 #endif
593         lc->page = ddjvu_page_create_by_pageno(lc->document, pagenum); /*  0? */
594
595         /* pump data untill the page is ready for rendering. */
596         tag=(-1);
597         do {
598                 while ((message = ddjvu_message_peek(lc->context)))
599                         {
600                                 tag=process_message(message);
601                                 if (tag == 0) break;
602                                 ddjvu_message_pop(lc->context);
603                         }
604                 /* fixme: maybe exit? */
605                 /* if (lc->error) break; */
606
607                 message = pump_data_until_message(lc,image);
608                 if (message)
609                         do {
610                                 tag=process_message(message);
611                                 if (tag == 0) break;
612                                 ddjvu_message_pop(lc->context);
613                         } while ((message = ddjvu_message_peek(lc->context)));
614         } while (!ddjvu_page_decoding_done(lc->page));
615
616         ddjvu_document_get_pageinfo(lc->document, pagenum, &info);
617
618         image->resolution.x = (float) info.dpi;
619         image->resolution.y =(float) info.dpi;
620         if (image_info->density != (char *) NULL)
621           {
622             int
623               flags;
624
625             GeometryInfo
626               geometry_info;
627
628             /*
629               Set rendering resolution.
630             */
631             flags=ParseGeometry(image_info->density,&geometry_info);
632             image->resolution.x=geometry_info.rho;
633             image->resolution.y=geometry_info.sigma;
634             if ((flags & SigmaValue) == 0)
635               image->resolution.y=image->resolution.x;
636             info.width*=image->resolution.x/info.dpi;
637             info.height*=image->resolution.y/info.dpi;
638             info.dpi=(ssize_t) MagickMax(image->resolution.x,image->resolution.y);
639           }
640         type = ddjvu_page_get_type(lc->page);
641
642         /* double -> float! */
643         /* image->gamma = (float)ddjvu_page_get_gamma(lc->page); */
644
645         /* mmc:  set  image->depth  */
646         /* mmc:  This from the type */
647
648         image->columns=(size_t) info.width;
649         image->rows=(size_t) info.height;
650
651         /* mmc: bitonal should be palettized, and compressed! */
652         if (type == DDJVU_PAGETYPE_BITONAL){
653                 image->colorspace = GRAYColorspace;
654                 image->storage_class = PseudoClass;
655                 image->depth =  8UL;    /* i only support that? */
656                 image->colors= 2;
657                 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
658                   ThrowReaderException(ResourceLimitError,
659                    "MemoryAllocationFailed");
660         } else {
661                 image->colorspace = RGBColorspace;
662                 image->storage_class = DirectClass;
663                 /* fixme:  MAGICKCORE_QUANTUM_DEPTH ?*/
664                 image->depth =  8UL;    /* i only support that? */
665
666                 image->alpha_trait = BlendPixelTrait;
667                 /* is this useful? */
668         }
669         status=SetImageExtent(image,image->columns,image->rows,exception);
670         if (status == MagickFalse)
671           return(DestroyImageList(image));
672 #if DEBUG
673         printf("now filling %.20g x %.20g\n",(double) image->columns,(double)
674           image->rows);
675 #endif
676
677
678 #if 1                           /* per_line */
679
680         /* q = QueueAuthenticPixels(image,0,0,image->columns,image->rows); */
681         get_page_image(lc, lc->page, 0, 0, info.width, info.height, exception);
682 #else
683         int i;
684         for (i = 0;i< image->rows; i++)
685                 {
686                         printf("%d\n",i);
687                         q = QueueAuthenticPixels(image,0,i,image->columns,1);
688                         get_page_line(lc, i, quantum_info);
689                         SyncAuthenticPixels(image);
690                 }
691
692 #endif /* per_line */
693
694
695 #if DEBUG
696         printf("END: finished filling %.20g x %.20g\n",(double) image->columns,
697           (double) image->rows);
698 #endif
699
700         if (!image->ping)
701           SyncImage(image,exception);
702         /* mmc: ??? Convert PNM pixels to runlength-encoded MIFF packets. */
703         /* image->colors =  */
704
705         /* how is the line padding  / stride? */
706
707         if (lc->page) {
708                 ddjvu_page_release(lc->page);
709                 lc->page = NULL;
710         }
711
712         /* image->page.y=mng_info->y_off[mng_info->object_id]; */
713         if (tag == 0)
714           image=DestroyImage(image);
715         return image;
716         /* end of reading one DJVU page/image */
717 }
718
719 #if 0
720 /* palette */
721   if (AcquireImageColormap(image,2,exception) == MagickFalse)
722     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
723   /*
724     Monochrome colormap.   mmc: this the default!
725   */
726   image->colormap[0].red=QuantumRange;
727   image->colormap[0].green=QuantumRange;
728   image->colormap[0].blue=QuantumRange;
729   image->colormap[1].red=0;
730   image->colormap[1].green=0;
731   image->colormap[1].blue=0;
732 #endif
733
734 static void djvu_close_lc(LoadContext* lc)
735 {
736         if (lc->document)
737                 ddjvu_document_release(lc->document);
738         if (lc->context)
739                 ddjvu_context_release(lc->context);
740         if (lc->page)
741                 ddjvu_page_release(lc->page);
742         RelinquishMagickMemory(lc);
743 }
744
745 static Image *ReadDJVUImage(const ImageInfo *image_info,
746   ExceptionInfo *exception)
747 {
748   const char
749     *url;
750
751   ddjvu_message_t
752     *message;
753
754   Image
755     *image,
756     *images;
757
758   int
759     logging,
760     use_cache;
761
762   LoadContext
763     *lc;
764
765   MagickBooleanType
766     status;
767
768   register ssize_t
769     i;
770
771   /*
772    * Open image file.
773    */
774   assert(image_info != (const ImageInfo *) NULL);
775   assert(image_info->signature == MagickSignature);
776
777
778   if (image_info->debug != MagickFalse)
779     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename);
780
781   assert(exception != (ExceptionInfo *) NULL);
782   assert(exception->signature == MagickSignature);
783
784
785   logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadDJVUImage()");
786   (void) logging;
787
788   image = AcquireImage(image_info,exception); /* mmc: ?? */
789
790
791   lc = (LoadContext *) NULL;
792   status = OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
793   if (status == MagickFalse)
794     ThrowReaderException(FileOpenError,"UnableToOpenFile");
795   /*
796     Verify DJVU signature.
797   */
798 #if 0
799   count = ReadBlob(image,8,(unsigned char *) magic_number);
800
801   /* IsDJVU(const unsigned char *magick,const size_t length) */
802   if (memcmp(magic_number,"AT&TFORM",8) != 0)
803     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
804 #endif
805
806
807   /*
808    * Allocate a LoadContext structure.
809    */
810   lc = (LoadContext *) AcquireMagickMemory(sizeof(*lc));
811   if (lc == NULL)
812     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
813
814
815   /*
816    * Initialize members of the MngInfo structure.
817    */
818   (void) ResetMagickMemory(lc,0,sizeof(LoadContext));
819
820   lc->image = image;
821   lc->pages = 0;
822   lc->context = ddjvu_context_create("ImageMagick djvu loader"); /* g_program_name */
823
824   ddjvu_cache_set_size(lc->context, 1); /* right? */
825   use_cache = 0;
826   /* document: here we don't have a filename, but, for the sake of generality, a FILE* ! */
827   url="http://www.imagemagick.org/fake.djvu";
828   lc->document = ddjvu_document_create(lc->context, url, use_cache); /* don't cache */
829   ddjvu_document_set_user_data(lc->document, lc);
830
831
832   /* now we wait the message-request for data: */
833   message = ddjvu_message_wait(lc->context);
834
835   if (message->m_any.tag != DDJVU_NEWSTREAM) {
836           /* fixme: the djvu context, document! */
837
838           ddjvu_document_release(lc->document);
839           ddjvu_context_release(lc->context);
840
841           RelinquishMagickMemory(lc);
842
843           ThrowReaderException(ResourceLimitError,"Djvu initial message: unexpected type");
844           return NULL;    /* error! */
845   };
846
847   lc->streamid = message->m_newstream.streamid;
848   ddjvu_message_pop(lc->context);
849
850   message = pump_data_until_message(lc,image);
851   /* now process the messages: */
852
853
854   if (message) do {
855           process_message(message);
856           ddjvu_message_pop(lc->context);
857   } while ((message = ddjvu_message_peek(lc->context)));
858
859   /* fixme: i hope we have not read any messages pertinent(?) related to the page itself!  */
860
861   while (lc->pages == 0) {
862           message = ddjvu_message_wait(lc->context);
863           process_message(message);
864           ddjvu_message_pop(lc->context);
865   }
866
867   images=NewImageList();
868   i=0;
869   if (image_info->number_scenes != 0)
870     i=image_info->scene;
871   for ( ; i < (ssize_t) lc->pages; i++)
872   {
873     image=ReadOneDJVUImage(lc,i,image_info,exception);
874     if (image == (Image *) NULL)
875       break;
876     image->scene=i;
877     AppendImageToList(&images,CloneImageList(image,exception));
878     images->extent=GetBlobSize(image);
879     if (image_info->number_scenes != 0)
880       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
881         break;
882   }
883   djvu_close_lc(lc);
884   (void) CloseBlob(images);
885   if (image != (Image *) NULL)
886     image=DestroyImageList(image);
887
888 #if 0
889   if ((image->page.width == 0) && (image->page.height == 0))
890     {
891       image->page.width = image->columns+image->page.x;
892       image->page.height = image->rows+image->page.y;
893     }
894   if (image->columns == 0 || image->rows == 0)
895     {
896       if (logging != MagickFalse)
897         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
898           "exit ReadDJVUImage() with error.");
899       ThrowReaderException(CorruptImageError,"CorruptImage");
900     }
901
902   if (logging != MagickFalse)
903     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadDJVUImage()");
904 #endif
905
906
907   return(GetFirstImageInList(images));
908 }
909 #endif
910 \f
911 /*
912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
913 %                                                                             %
914 %                                                                             %
915 %                                                                             %
916 %   R e g i s t e r D J V U I m a g e                                         %
917 %                                                                             %
918 %                                                                             %
919 %                                                                             %
920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
921 %
922 %  RegisterDJVUImage() adds attributes for the DJVU image format to
923 %  the list of supported formats.  The attributes include the image format
924 %  tag, a method to read and/or write the format, whether the format
925 %  supports the saving of more than one frame to the same file or blob,
926 %  whether the format supports native in-memory I/O, and a brief
927 %  description of the format.
928 %
929 %  The format of the RegisterDJVUImage method is:
930 %
931 %      size_t RegisterDJVUImage(void)
932 %
933 */
934 ModuleExport size_t RegisterDJVUImage(void)
935 {
936   char
937     version[MaxTextExtent];
938
939   MagickInfo
940     *entry;
941
942   static const char
943     *DJVUNote =
944     {
945       "See http://www.djvuzone.org/ for details about the DJVU format.  The\n"
946       "DJVU 1.2 specification is available there and at\n"
947       "ftp://swrinde.nde.swri.edu/pub/djvu/documents/."
948     };
949
950   *version='\0';
951 #if defined(DJVU_LIBDJVU_VER_STRING)
952   (void) ConcatenateMagickString(version,"libdjvu ",MaxTextExtent);
953   (void) ConcatenateMagickString(version,DJVU_LIBDJVU_VER_STRING,MaxTextExtent);
954 #endif
955   entry=SetMagickInfo("DJVU");
956 #if defined(MAGICKCORE_DJVU_DELEGATE)
957   entry->decoder=(DecodeImageHandler *) ReadDJVUImage;
958 #endif
959   entry->raw=MagickTrue;
960   entry->magick=(IsImageFormatHandler *) IsDJVU;
961   entry->adjoin=MagickFalse;
962   entry->thread_support=MagickTrue;
963   entry->description=AcquireString("Déjà vu");
964   entry->module=AcquireString("DJVU");
965   if (*version != '\0')
966     entry->version=AcquireString(version);
967   entry->note=AcquireString(DJVUNote);
968   (void) RegisterMagickInfo(entry);
969   return(MagickImageCoderSignature);
970 }
971 \f
972 /*
973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
974 %                                                                             %
975 %                                                                             %
976 %                                                                             %
977 %   U n r e g i s t e r D J V U I m a g e                                     %
978 %                                                                             %
979 %                                                                             %
980 %                                                                             %
981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
982 %
983 %  UnregisterDJVUImage() removes format registrations made by the
984 %  DJVU module from the list of supported formats.
985 %
986 %  The format of the UnregisterDJVUImage method is:
987 %
988 %      UnregisterDJVUImage(void)
989 %
990 */
991 ModuleExport void UnregisterDJVUImage(void)
992 {
993   (void) UnregisterMagickInfo("DJVU");
994 }