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