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