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