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