]> granicus.if.org Git - imagemagick/blob - coders/djvu.c
b5d6960e3b04667e3c5c73c7d9c86e4a0086a359
[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         ddjvu_format_release(format);
385
386
387         if (type == DDJVU_PAGETYPE_BITONAL) {
388                 /*  */
389 #if DEBUG
390                 printf("%s: expanding BITONAL page/image\n", __FUNCTION__);
391 #endif
392                 register IndexPacket *indexes;
393                 size_t bit, byte;
394
395                 for (y=0; y < (ssize_t) image->rows; y++)
396                         {
397                                 PixelPacket * o = QueueAuthenticPixels(image,0,y,image->columns,1,&image->exception);
398                                 if (o == (PixelPacket *) NULL)
399                                         break;
400                                 indexes=GetAuthenticIndexQueue(image);
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                                                 indexes[x]=(IndexPacket) (((byte & 0x01) != 0) ? 0x00 : 0x01);
410                                                 bit++;
411                                                 if (bit == 8)
412                                                         bit=0;
413                                                 byte>>=1;
414                                         }
415                                 if (SyncAuthenticPixels(image,&image->exception) == MagickFalse)
416                                         break;
417                         }
418                 if (!image->ping)
419                   SyncImage(image);
420         } else {
421 #if DEBUG
422                 printf("%s: expanding PHOTO page/image\n", __FUNCTION__);
423 #endif
424                 /* now transfer line-wise: */
425                 ssize_t i;
426 #if 0
427                 /* old: */
428                 char* r;
429 #else
430                 register PixelPacket *r;
431 #endif
432
433                 for (i = 0;i< (ssize_t) lc->image->rows; i++)
434                         {
435 #if DEBUG
436                                if (i % 1000 == 0) printf("%d\n",i);
437 #endif
438                                r = QueueAuthenticPixels(lc->image,0,i,lc->image->columns,1,&image->exception);
439
440                                 ImportQuantumPixels(lc->image,
441                                                     (CacheView *) NULL,
442                                                     quantum_info,
443                                                     RGBQuantum, /*GrayQuantum*/
444                                                     q+i*stride,&image->exception);
445                                 SyncAuthenticPixels(lc->image,&image->exception);
446                         }
447         }
448         q=(unsigned char *) RelinquishMagickMemory(q);
449 }
450
451
452 #if defined(MAGICKCORE_DJVU_DELEGATE)
453
454 #if 0
455 static int
456 get_page_line(LoadContext *lc, int row, QuantumInfo* quantum_info)
457 {
458   ddjvu_format_t
459     *format;
460
461   int
462     ret;
463
464   size_t
465     stride;
466
467   unsigned char
468     *q;
469
470         ddjvu_rect_t rect, pagerect;
471         rect.x = 0;
472         rect.y = row;
473         rect.w = lc->image->columns;             /* /10 */
474         rect.h = 1;             /* /10 */
475
476         pagerect.x = 0;
477         pagerect.y = 0;
478         pagerect.w = lc->image->columns;
479         pagerect.h = lc->image->rows;
480
481
482         format = ddjvu_format_create(
483 #if RGB
484                 DDJVU_FORMAT_RGB24
485 #else
486                 DDJVU_FORMAT_GREY8
487 #endif
488                 ,
489                 0, NULL);
490         ddjvu_format_set_row_order(format, 1);
491         ddjvu_format_set_y_direction(format, 1);
492
493         stride=1;
494 #if RGB
495         stride=3;
496 #endif
497         q = (unsigned char *) AcquireQuantumMemory(lc->image->columns,stride);
498
499         ret = ddjvu_page_render(lc->page,
500                                     DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
501                                     &pagerect,
502                                     &rect,     /* mmc: ?? */
503                                     format,
504                                     pagerect.w * 3, /* ?? */
505                                     (char*)q);
506
507         ImportQuantumPixels(lc->image,
508                             (CacheView *) NULL,
509                             quantum_info,
510 #if RGB
511                             RGBQuantum
512 #else
513                             GrayQuantum
514 #endif
515                             ,q,&lc->image->exception);
516         q=(unsigned char *) RelinquishMagickMemory(q);
517         ddjvu_format_release(format);
518         return ret;
519 }
520 #endif
521 #endif
522
523 /*
524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
525 %                                                                             %
526 %                                                                             %
527 %                                                                             %
528 %   R e a d O n e D J V U I m a g e                                           %
529 %                                                                             %
530 %                                                                             %
531 %                                                                             %
532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
533 %
534 %  ReadOneDJVUImage() reads a Portable Network Graphics (DJVU) image file
535 %  (minus the 8-byte signature)  and returns it.  It allocates the memory
536 %  necessary for the new Image structure and returns a pointer to the new
537 %  image.
538 %
539 %  The format of the ReadOneDJVUImage method is:
540 %
541 %      Image *ReadOneDJVUImage(MngInfo *mng_info, const ImageInfo *image_info,
542 %         ExceptionInfo *exception)
543 %
544 %  A description of each parameter follows:
545 %
546 %    o mng_info: Specifies a pointer to a MngInfo structure.
547 %
548 %    o image_info: the image info.
549 %
550 %    o exception: return any errors or warnings in this structure.
551 %
552 */
553
554 static inline double MagickMax(const double x,const double y)
555 {
556   if (x > y)
557     return(x);
558   return(y);
559 }
560
561 static Image *ReadOneDJVUImage(LoadContext* lc,const int pagenum,
562   const ImageInfo *image_info,ExceptionInfo *exception)
563 {
564   ddjvu_page_type_t
565      type;
566
567   ddjvu_pageinfo_t info;
568   QuantumInfo *quantum_info;
569   ddjvu_message_t *message;
570   Image *image;
571   int logging;
572   int tag;
573
574         /* so, we know that the page is there! Get its dimension, and  */
575
576         /* Read one DJVU image */
577         image = lc->image;
578
579         /* register PixelPacket *q; */
580
581         logging=LogMagickEvent(CoderEvent,GetMagickModule(), "  enter ReadOneDJVUImage()");
582
583 #if DEBUG
584         printf("====  Loading the page %d\n", pagenum);
585 #endif
586         lc->page = ddjvu_page_create_by_pageno(lc->document, pagenum); /*  0? */
587
588         /* pump data untill the page is ready for rendering. */
589         tag=(-1);
590         do {
591                 while ((message = ddjvu_message_peek(lc->context)))
592                         {
593                                 tag=process_message(message);
594                                 if (tag == 0) break;
595                                 ddjvu_message_pop(lc->context);
596                         }
597                 /* fixme: maybe exit? */
598                 /* if (lc->error) break; */
599
600                 message = pump_data_until_message(lc,image);
601                 if (message)
602                         do {
603                                 tag=process_message(message);
604                                 if (tag == 0) break;
605                                 ddjvu_message_pop(lc->context);
606                         } while ((message = ddjvu_message_peek(lc->context)));
607         } while (!ddjvu_page_decoding_done(lc->page));
608
609         ddjvu_document_get_pageinfo(lc->document, pagenum, &info);
610
611         image->x_resolution = (float) info.dpi;
612         image->y_resolution =(float) info.dpi;
613         if (image_info->density != (char *) NULL)
614           {
615             int
616               flags;
617
618             GeometryInfo
619               geometry_info;
620
621             /*
622               Set rendering resolution.
623             */
624             flags=ParseGeometry(image_info->density,&geometry_info);
625             image->x_resolution=geometry_info.rho;
626             image->y_resolution=geometry_info.sigma;
627             if ((flags & SigmaValue) == 0)
628               image->y_resolution=image->x_resolution;
629             info.width*=image->x_resolution/info.dpi;
630             info.height*=image->y_resolution/info.dpi;
631             info.dpi=(ssize_t) MagickMax(image->x_resolution,image->y_resolution);
632           }
633         type = ddjvu_page_get_type(lc->page);
634
635         /* double -> float! */
636         /* image->gamma = (float)ddjvu_page_get_gamma(lc->page); */
637
638         /* mmc:  set  image->depth  */
639         /* mmc:  This from the type */
640
641         image->columns=(size_t) info.width;
642         image->rows=(size_t) info.height;
643
644         /* mmc: bitonal should be palettized, and compressed! */
645         if (type == DDJVU_PAGETYPE_BITONAL){
646                 image->colorspace = GRAYColorspace;
647                 image->storage_class = PseudoClass;
648                 image->depth =  8UL;    /* i only support that? */
649                 image->colors= 2;
650                 if (AcquireImageColormap(image,image->colors) == MagickFalse)
651                   ThrowReaderException(ResourceLimitError,
652                    "MemoryAllocationFailed");
653         } else {
654                 image->colorspace = RGBColorspace;
655                 image->storage_class = DirectClass;
656                 /* fixme:  MAGICKCORE_QUANTUM_DEPTH ?*/
657                 image->depth =  8UL;    /* i only support that? */
658
659                 image->matte = MagickTrue;
660                 /* is this useful? */
661         }
662 #if DEBUG
663         printf("now filling %.20g x %.20g\n",(double) image->columns,(double)
664           image->rows);
665 #endif
666
667
668 #if 1                           /* per_line */
669         quantum_info=AcquireQuantumInfo(image_info,image);
670         if (quantum_info == (QuantumInfo *) NULL)
671           ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
672
673         /* q = QueueAuthenticPixels(image,0,0,image->columns,image->rows); */
674         get_page_image(lc, lc->page, 0, 0, info.width, info.height, quantum_info);
675 #else
676         int i;
677         for (i = 0;i< image->rows; i++)
678                 {
679                         printf("%d\n",i);
680                         q = QueueAuthenticPixels(image,0,i,image->columns,1);
681                         get_page_line(lc, i, quantum_info);
682                         SyncAuthenticPixels(image);
683                 }
684
685 #endif /* per_line */
686
687
688 #if DEBUG
689         printf("END: finished filling %.20g x %.20g\n",(double) image->columns,
690           (double) image->rows);
691 #endif
692
693         if (!image->ping)
694           SyncImage(image);
695         quantum_info=DestroyQuantumInfo(quantum_info);
696         /* indexes=GetAuthenticIndexQueue(image); */
697         /* mmc: ??? Convert PNM pixels to runlength-encoded MIFF packets. */
698         /* image->colors =  */
699
700         /* how is the line padding  / stride? */
701
702         if (lc->page) {
703                 ddjvu_page_release(lc->page);
704                 lc->page = NULL;
705         }
706
707         /* image->page.y=mng_info->y_off[mng_info->object_id]; */
708         if (tag == 0)
709           image=DestroyImage(image);
710         return image;
711         /* end of reading one DJVU page/image */
712 }
713
714 #if 0
715 /* palette */
716   if (AcquireImageColormap(image,2) == MagickFalse)
717     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
718   /*
719     Monochrome colormap.   mmc: this the default!
720   */
721   image->colormap[0].red=QuantumRange;
722   image->colormap[0].green=QuantumRange;
723   image->colormap[0].blue=QuantumRange;
724   image->colormap[1].red=0;
725   image->colormap[1].green=0;
726   image->colormap[1].blue=0;
727 #endif
728
729 static void djvu_close_lc(LoadContext* lc)
730 {
731         if (lc->document)
732                 ddjvu_document_release(lc->document);
733         if (lc->context)
734                 ddjvu_context_release(lc->context);
735         if (lc->page)
736                 ddjvu_page_release(lc->page);
737         RelinquishMagickMemory(lc);
738 }
739
740 static Image *ReadDJVUImage(const ImageInfo *image_info,
741   ExceptionInfo *exception)
742 {
743   const char
744     *url;
745
746   ddjvu_message_t
747     *message;
748
749   Image
750     *image,
751     *images;
752
753   int
754     logging,
755     use_cache;
756
757   LoadContext
758     *lc;
759
760   MagickBooleanType
761     status;
762
763   register ssize_t
764     i;
765
766   /*
767    * Open image file.
768    */
769   assert(image_info != (const ImageInfo *) NULL);
770   assert(image_info->signature == MagickSignature);
771
772
773   if (image_info->debug != MagickFalse)
774     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename);
775
776   assert(exception != (ExceptionInfo *) NULL);
777   assert(exception->signature == MagickSignature);
778
779
780   logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadDJVUImage()");
781
782   image = AcquireImage(image_info); /* mmc: ?? */
783
784
785   lc = (LoadContext *) NULL;
786   status = OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
787   if (status == MagickFalse)
788     ThrowReaderException(FileOpenError,"UnableToOpenFile");
789   /*
790     Verify DJVU signature.
791   */
792 #if 0
793   count = ReadBlob(image,8,(unsigned char *) magic_number);
794
795   /* IsDJVU(const unsigned char *magick,const size_t length) */
796   if (memcmp(magic_number,"AT&TFORM",8) != 0)
797     ThrowReaderException(CorruptImageError,"ImproperImageHeader");
798 #endif
799
800
801   /*
802    * Allocate a LoadContext structure.
803    */
804   lc = (LoadContext *) AcquireMagickMemory(sizeof(*lc));
805   if (lc == NULL)
806     ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
807
808
809   /*
810    * Initialize members of the MngInfo structure.
811    */
812   (void) ResetMagickMemory(lc,0,sizeof(LoadContext));
813
814   lc->image = image;
815   lc->pages = 0;
816   lc->context = ddjvu_context_create("ImageMagick djvu loader"); /* g_program_name */
817
818   ddjvu_cache_set_size(lc->context, 1); /* right? */
819   use_cache = 0;
820   /* document: here we don't have a filename, but, for the sake of generality, a FILE* ! */
821   url="http://www.imagemagick.org/fake.djvu";
822   lc->document = ddjvu_document_create(lc->context, url, use_cache); /* don't cache */
823   ddjvu_document_set_user_data(lc->document, lc);
824
825
826   /* now we wait the message-request for data: */
827   message = ddjvu_message_wait(lc->context);
828
829   if (message->m_any.tag != DDJVU_NEWSTREAM) {
830           /* fixme: the djvu context, document! */
831
832           ddjvu_document_release(lc->document);
833           ddjvu_context_release(lc->context);
834
835           RelinquishMagickMemory(lc);
836
837           ThrowReaderException(ResourceLimitError,"Djvu initial message: unexpected type");
838           return NULL;    /* error! */
839   };
840
841   lc->streamid = message->m_newstream.streamid;
842   ddjvu_message_pop(lc->context);
843
844   message = pump_data_until_message(lc,image);
845   /* now process the messages: */
846
847
848   if (message) do {
849           process_message(message);
850           ddjvu_message_pop(lc->context);
851   } while ((message = ddjvu_message_peek(lc->context)));
852
853   /* fixme: i hope we have not read any messages pertinent(?) related to the page itself!  */
854
855   while (lc->pages == 0) {
856           message = ddjvu_message_wait(lc->context);
857           process_message(message);
858           ddjvu_message_pop(lc->context);
859   }
860
861   images=NewImageList();
862   i=0;
863   if (image_info->number_scenes != 0)
864     i=image_info->scene;
865   for ( ; i < (ssize_t) lc->pages; i++)
866   {
867     image=ReadOneDJVUImage(lc,i,image_info,exception);
868     if (image == (Image *) NULL)
869       break;
870     image->scene=i;
871     AppendImageToList(&images,CloneImageList(image,exception));
872     if (image_info->number_scenes != 0)
873       if (image->scene >= (image_info->scene+image_info->number_scenes-1))
874         break;
875   }
876   djvu_close_lc(lc);
877   (void) CloseBlob(images);
878   if (image != (Image *) NULL)
879     image=DestroyImageList(image);
880
881 #if 0
882   if ((image->page.width == 0) && (image->page.height == 0))
883     {
884       image->page.width = image->columns+image->page.x;
885       image->page.height = image->rows+image->page.y;
886     }
887   if (image->columns == 0 || image->rows == 0)
888     {
889       if (logging != MagickFalse)
890         (void) LogMagickEvent(CoderEvent,GetMagickModule(),
891           "exit ReadDJVUImage() with error.");
892       ThrowReaderException(CorruptImageError,"CorruptImage");
893     }
894
895   if (logging != MagickFalse)
896     (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadDJVUImage()");
897 #endif
898
899
900   return(GetFirstImageInList(images));
901 }
902 #endif
903 \f
904 /*
905 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
906 %                                                                             %
907 %                                                                             %
908 %                                                                             %
909 %   R e g i s t e r D J V U I m a g e                                         %
910 %                                                                             %
911 %                                                                             %
912 %                                                                             %
913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
914 %
915 %  RegisterDJVUImage() adds attributes for the DJVU image format to
916 %  the list of supported formats.  The attributes include the image format
917 %  tag, a method to read and/or write the format, whether the format
918 %  supports the saving of more than one frame to the same file or blob,
919 %  whether the format supports native in-memory I/O, and a brief
920 %  description of the format.
921 %
922 %  The format of the RegisterDJVUImage method is:
923 %
924 %      size_t RegisterDJVUImage(void)
925 %
926 */
927 ModuleExport size_t RegisterDJVUImage(void)
928 {
929   char
930     version[MaxTextExtent];
931
932   MagickInfo
933     *entry;
934
935   static const char
936     *DJVUNote =
937     {
938       "See http://www.djvuzone.org/ for details about the DJVU format.  The\n"
939       "DJVU 1.2 specification is available there and at\n"
940       "ftp://swrinde.nde.swri.edu/pub/djvu/documents/."
941     };
942
943   *version='\0';
944 #if defined(DJVU_LIBDJVU_VER_STRING)
945   (void) ConcatenateMagickString(version,"libdjvu ",MaxTextExtent);
946   (void) ConcatenateMagickString(version,DJVU_LIBDJVU_VER_STRING,MaxTextExtent);
947 #endif
948   entry=SetMagickInfo("DJVU");
949 #if defined(MAGICKCORE_DJVU_DELEGATE)
950   entry->decoder=(DecodeImageHandler *) ReadDJVUImage;
951 #endif
952   entry->raw=MagickTrue;
953   entry->magick=(IsImageFormatHandler *) IsDJVU;
954   entry->adjoin=MagickFalse;
955   entry->thread_support=MagickTrue;
956   entry->description=AcquireString("Déjà vu");
957   entry->module=AcquireString("DJVU");
958   if (*version != '\0')
959     entry->version=AcquireString(version);
960   entry->note=AcquireString(DJVUNote);
961   (void) RegisterMagickInfo(entry);
962   return(MagickImageCoderSignature);
963 }
964 \f
965 /*
966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
967 %                                                                             %
968 %                                                                             %
969 %                                                                             %
970 %   U n r e g i s t e r D J V U I m a g e                                     %
971 %                                                                             %
972 %                                                                             %
973 %                                                                             %
974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975 %
976 %  UnregisterDJVUImage() removes format registrations made by the
977 %  DJVU module from the list of supported formats.
978 %
979 %  The format of the UnregisterDJVUImage method is:
980 %
981 %      UnregisterDJVUImage(void)
982 %
983 */
984 ModuleExport void UnregisterDJVUImage(void)
985 {
986   (void) UnregisterMagickInfo("DJVU");
987 }