/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%                         DDDD       J  V   V  U   U                          %
%                         D   D      J  V   V  U   U                          %
%                         D   D      J  V   V  U   U                          %
%                         D   D  J   J   V V   U   U                          %
%                         DDDD    JJJ     V     UUU                           %
%                                                                             %
%                                                                             %
%                             Read DjVu Images.                               %
%                                                                             %
%                              Software Design                                %
%                                   Cristy                                    %
%                                 July 1992                                   %
%                                                                             %
%                                                                             %
%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
%  dedicated to making software imaging solutions freely available.           %
%                                                                             %
%  You may not use this file except in compliance with the License.  You may  %
%  obtain a copy of the License at                                            %
%                                                                             %
%    http://www.imagemagick.org/script/license.php                            %
%                                                                             %
%  Unless required by applicable law or agreed to in writing, software        %
%  distributed under the License is distributed on an "AS IS" BASIS,          %
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
%  See the License for the specific language governing permissions and        %
%  limitations under the License.                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/

/*
  Include declarations.
*/
#include "MagickCore/studio.h"
#include "MagickCore/blob.h"
#include "MagickCore/blob-private.h"
#include "MagickCore/cache.h"
#include "MagickCore/colormap.h"
#include "MagickCore/constitute.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/image-private.h"
#include "MagickCore/list.h"
#include "MagickCore/magick.h"
#include "MagickCore/memory_.h"
#include "MagickCore/monitor.h"
#include "MagickCore/monitor-private.h"
#include "MagickCore/pixel-accessor.h"
#include "MagickCore/quantum-private.h"
#include "MagickCore/static.h"
#include "MagickCore/string_.h"
#include "MagickCore/module.h"
#if defined(MAGICKCORE_DJVU_DELEGATE)
#include <libdjvu/ddjvuapi.h>
#endif

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   I s D J V U                                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  IsDJVU() returns MagickTrue if the image format type, identified by the
%  magick string, is DJVU.
%
%  The format of the IsDJVU method is:
%
%      MagickBooleanType IsDJVU(const unsigned char *magick,const size_t length)
%
%  A description of each parameter follows:
%
%    o magick: compare image format pattern against these bytes.
%
%    o length: Specifies the length of the magick string.
%
*/
static MagickBooleanType IsDJVU(const unsigned char *magick,const size_t length)
{
  if (length < 8)
    return(MagickFalse);
  if (memcmp(magick,"AT&TFORM",8) == 0)
    return(MagickTrue);
  return(MagickFalse);
}

#if defined(MAGICKCORE_DJVU_DELEGATE)
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e a d D J V U I m a g e                                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ReadDJVUImage() reads DJVU image and returns it.  It allocates the memory
%  necessary for the new Image structure and returns a pointer to the new
%  image or set of images.
%
%  The format of the ReadDJVUImage method is:
%
%      Image *ReadDJVUImage(const ImageInfo *image_info,
%        ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o image_info: the image info.
%
%    o exception: return any errors or warnings in this structure.
%
*/

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

typedef struct _LoadContext
   LoadContext;

struct _LoadContext
{
  ddjvu_context_t* context;
  ddjvu_document_t *document;
  ddjvu_page_t *page;
  int streamid;
  int pages;
  Image *image;
};

#define BLOCKSIZE  65536
#if 0
static void
pump_data(Image *image, LoadContext* lc)
{
        int blocksize = BLOCKSIZE;
        char data[BLOCKSIZE];
        int size;

        /* i might check for a condition! */
        while ((size = (size_t) ReadBlob(image,(size_t) blocksize,data)) == blocksize) {
                ddjvu_stream_write(lc->document, lc->streamid, data, size);
        }
        if (size)
                ddjvu_stream_write(lc->document, lc->streamid, data, size);
        ddjvu_stream_close(lc->document, lc->streamid, 0);
}
#endif

/* returns NULL only after all is delivered! */
static ddjvu_message_t*
pump_data_until_message(LoadContext *lc,Image *image) /* ddjvu_context_t *context, type ddjvu_document_type_t */
{
        size_t blocksize = BLOCKSIZE;
        unsigned char data[BLOCKSIZE];
        size_t size;
        ddjvu_message_t *message;

        /* i might check for a condition! */
        size=0;
        while (!(message = ddjvu_message_peek(lc->context))
               && (size = (size_t) ReadBlob(image,(size_t) blocksize,data)) == blocksize) {
                ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
        }
        if (message)
                return message;
        if (size)
                ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
        ddjvu_stream_close(lc->document, lc->streamid, 0);
        return NULL;
}
#define DEBUG 0

#if DEBUG
static const char*
message_tag_name(ddjvu_message_tag_t tag)
{
   static char* names[] =
      {
         "ERROR",
         "INFO",
         "NEWSTREAM",
         "DOCINFO",
         "PAGEINFO",
         "RELAYOUT",
         "REDISPLAY",
         "CHUNK",
         "THUMBNAIL",
         "PROGRESS",
      };
   if (tag <= DDJVU_PROGRESS)
      return names[tag];
   else {
      /* bark! */
      return 0;
   }
}
#endif

/* write out nice info on the message,
 * and store in *user* data the info on progress.
 * */
int
process_message(ddjvu_message_t *message)
{

#if 0
   ddjvu_context_t* context= message->m_any.context;
#endif

   if (! message)
      return(-1);
#if DEBUG
   printf("*** %s: %s.\n",__FUNCTION__, message_tag_name(message->m_any.tag));
#endif


   switch (message->m_any.tag){
   case DDJVU_DOCINFO:
   {
      ddjvu_document_t* document= message->m_any.document;
      /* ddjvu_document_decoding_status  is set by libdjvu! */
      /* we have some info on the document  */
      LoadContext *lc = (LoadContext *) ddjvu_document_get_user_data(document);
      lc->pages = ddjvu_document_get_pagenum(document);
#if DEBUG
      printf("the doc has %d pages\n", ddjvu_document_get_pagenum(document));
#endif
      break;
   }
   case DDJVU_CHUNK:
#if DEBUG
           printf("the name of the chunk is: %s\n", message->m_chunk.chunkid);
#endif
           break;


   case DDJVU_RELAYOUT:
   case DDJVU_PAGEINFO:
   {
#if 0
      ddjvu_page_t* page = message->m_any.page;
      page_info* info = ddjvu_page_get_user_data(page);

      printf("page decoding status: %d %s%s%s\n",
             ddjvu_page_decoding_status(page),
             status_color, status_name(ddjvu_page_decoding_status(page)), color_reset);

      printf("the page LAYOUT changed: width x height: %d x %d @ %d dpi. Version %d, type %d\n",
             // printf("page info:\n width x height: %d x %d @ %d dpi, version %d, type %d\n",
             ddjvu_page_get_width(page),
             ddjvu_page_get_height(page),
             ddjvu_page_get_resolution(page),
             ddjvu_page_get_version(page),
             /* DDJVU_PAGETYPE_BITONAL */
             ddjvu_page_get_type(page));

      info->info = 1;
#endif
      break;
   }

   case DDJVU_REDISPLAY:
   {

#if 0
    ddjvu_page_t* page = message->m_any.page;
      page_info* info = ddjvu_page_get_user_data(page);

      printf("the page can/should be REDISPLAYED\n");
      info->display = 1;
#endif
      break;
   }

   case DDJVU_PROGRESS:
#if DEBUG
           printf("PROGRESS:\n");
#endif
           break;
   case DDJVU_ERROR:
           printf("simply ERROR!\n message:\t%s\nfunction:\t%s(file %s)\nlineno:\t%d\n",
                  message->m_error.message,
                  message->m_error.function,
                  message->m_error.filename,
                  message->m_error.lineno);
           break;
   case DDJVU_INFO:
#if DEBUG
           printf("INFO: %s!\n", message->m_info.message);
#endif
           break;
   default:
      printf("unexpected\n");
   };
  return(message->m_any.tag);
}


#if defined(__cplusplus) || defined(c_plusplus)
}
#endif


#define RGB 1

/*
 * DjVu advertised readiness to provide bitmap: So get it!
 * we use the RGB format!
 */
static void
get_page_image(LoadContext *lc, ddjvu_page_t *page, int x, int y, int w, int h, ExceptionInfo *exception ) {
  ddjvu_format_t
    *format;

  ddjvu_page_type_t
    type;

  Image
    *image;

  int
    ret,
    stride;

  unsigned char
    *q;

        ddjvu_rect_t rect;
        rect.x = x;
        rect.y = y;
        rect.w = (unsigned int) w;             /* /10 */
        rect.h = (unsigned int) h;             /* /10 */

        image = lc->image;
        type = ddjvu_page_get_type(lc->page);

        /* stride of this temporary buffer: */
        stride = (type == DDJVU_PAGETYPE_BITONAL)?
                (image->columns + 7)/8 : image->columns *3;

        q = (unsigned char *) AcquireQuantumMemory(image->rows,stride);
        if (q == (unsigned char *) NULL)
          return;

        format = ddjvu_format_create(
                (type == DDJVU_PAGETYPE_BITONAL)?DDJVU_FORMAT_LSBTOMSB : DDJVU_FORMAT_RGB24,
                /* DDJVU_FORMAT_RGB24
                 * DDJVU_FORMAT_RGBMASK32*/
                /* DDJVU_FORMAT_RGBMASK32 */
                0, NULL);

#if 0
        /* fixme:  ThrowReaderException is a macro, which uses  `exception' variable */
        if (format == NULL)
                {
                        abort();
                        /* ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); */
                }

#endif
        ddjvu_format_set_row_order(format, 1);
        ddjvu_format_set_y_direction(format, 1);

        ret = ddjvu_page_render(page,
                                    DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
                                    &rect,
                                    &rect,     /* mmc: ?? */
                                    format,
                                    stride, /* ?? */
                                    (char*)q);
        (void) ret;
        ddjvu_format_release(format);


        if (type == DDJVU_PAGETYPE_BITONAL) {
                /*  */
#if DEBUG
                printf("%s: expanding BITONAL page/image\n", __FUNCTION__);
#endif
                size_t bit, byte;

                for (y=0; y < (ssize_t) image->rows; y++)
                        {
                                Quantum * o = QueueAuthenticPixels(image,0,y,image->columns,1,exception);
                                if (o == (Quantum *) NULL)
                                        break;
                                bit=0;
                                byte=0;

                                /* fixme:  the non-aligned, last =<7 bits ! that's ok!!!*/
                                for (x= 0; x < (ssize_t) image->columns; x++)
                                        {
                                                if (bit == 0) byte= (size_t) q[(y * stride) + (x / 8)];

                                                SetPixelIndex(image,(Quantum) (((byte & 0x01) != 0) ? 0x00 : 0x01),o);
                                                bit++;
                                                if (bit == 8)
                                                        bit=0;
                                                byte>>=1;
                                          o+=GetPixelChannels(image);
                                        }
                                if (SyncAuthenticPixels(image,exception) == MagickFalse)
                                        break;
                        }
                if (!image->ping)
                  SyncImage(image,exception);
        } else {
#if DEBUG
                printf("%s: expanding PHOTO page/image\n", __FUNCTION__);
#endif
                /* now transfer line-wise: */
                ssize_t i;
#if 0
                /* old: */
                char* r;
#else
                register Quantum *r;
                unsigned char *s;
#endif
                s=q;
                for (i = 0;i< (ssize_t) image->rows; i++)
                        {
#if DEBUG
                               if (i % 1000 == 0) printf("%d\n",i);
#endif
                               r = QueueAuthenticPixels(image,0,i,image->columns,1,exception);
                               if (r == (Quantum *) NULL)
                                 break;
                  for (x=0; x < (ssize_t) image->columns; x++)
                  {
                    SetPixelRed(image,ScaleCharToQuantum(*s++),r);
                    SetPixelGreen(image,ScaleCharToQuantum(*s++),r);
                    SetPixelBlue(image,ScaleCharToQuantum(*s++),r);
                    r+=GetPixelChannels(image);
                  }

                              (void) SyncAuthenticPixels(image,exception);
                        }
        }
        q=(unsigned char *) RelinquishMagickMemory(q);
}


#if defined(MAGICKCORE_DJVU_DELEGATE)

#if 0
static int
get_page_line(LoadContext *lc, int row, QuantumInfo* quantum_info)
{
  ddjvu_format_t
    *format;

  int
    ret;

  size_t
    stride;

  unsigned char
    *q;

        ddjvu_rect_t rect, pagerect;
        rect.x = 0;
        rect.y = row;
        rect.w = lc->image->columns;             /* /10 */
        rect.h = 1;             /* /10 */

        pagerect.x = 0;
        pagerect.y = 0;
        pagerect.w = lc->image->columns;
        pagerect.h = lc->image->rows;


        format = ddjvu_format_create(
#if RGB
                DDJVU_FORMAT_RGB24
#else
                DDJVU_FORMAT_GREY8
#endif
                ,
                0, NULL);
        ddjvu_format_set_row_order(format, 1);
        ddjvu_format_set_y_direction(format, 1);

        stride=1;
#if RGB
        stride=3;
#endif
        q = (unsigned char *) AcquireQuantumMemory(lc->image->columns,stride);

        ret = ddjvu_page_render(lc->page,
                                    DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
                                    &pagerect,
                                    &rect,     /* mmc: ?? */
                                    format,
                                    pagerect.w * 3, /* ?? */
                                    (char*)q);

        ImportQuantumPixels(lc->image,
                            (CacheView *) NULL,
                            quantum_info,
#if RGB
                            RGBQuantum
#else
                            GrayQuantum
#endif
                            ,q,&lc->image->exception);
        q=(unsigned char *) RelinquishMagickMemory(q);
        ddjvu_format_release(format);
        return ret;
}
#endif
#endif

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e a d O n e D J V U I m a g e                                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ReadOneDJVUImage() reads a Portable Network Graphics (DJVU) image file
%  (minus the 8-byte signature)  and returns it.  It allocates the memory
%  necessary for the new Image structure and returns a pointer to the new
%  image.
%
%  The format of the ReadOneDJVUImage method is:
%
%      Image *ReadOneDJVUImage(MngInfo *mng_info, const ImageInfo *image_info,
%         ExceptionInfo *exception)
%
%  A description of each parameter follows:
%
%    o mng_info: Specifies a pointer to a MngInfo structure.
%
%    o image_info: the image info.
%
%    o exception: return any errors or warnings in this structure.
%
*/

static Image *ReadOneDJVUImage(LoadContext* lc,const int pagenum,
  const ImageInfo *image_info,ExceptionInfo *exception)
{
  ddjvu_page_type_t
     type;

  ddjvu_pageinfo_t info;
  ddjvu_message_t *message;
  Image *image;
  int logging;
  int tag;
  MagickBooleanType status;

        /* so, we know that the page is there! Get its dimension, and  */

        /* Read one DJVU image */
        image = lc->image;

        /* register Quantum *q; */

        logging=LogMagickEvent(CoderEvent,GetMagickModule(), "  enter ReadOneDJVUImage()");
        (void) logging;

#if DEBUG
        printf("====  Loading the page %d\n", pagenum);
#endif
        lc->page = ddjvu_page_create_by_pageno(lc->document, pagenum); /*  0? */

        /* pump data untill the page is ready for rendering. */
        tag=(-1);
        do {
                while ((message = ddjvu_message_peek(lc->context)))
                        {
                                tag=process_message(message);
                                if (tag == 0) break;
                                ddjvu_message_pop(lc->context);
                        }
                /* fixme: maybe exit? */
                /* if (lc->error) break; */

                message = pump_data_until_message(lc,image);
                if (message)
                        do {
                                tag=process_message(message);
                                if (tag == 0) break;
                                ddjvu_message_pop(lc->context);
                        } while ((message = ddjvu_message_peek(lc->context)));
        } while (!ddjvu_page_decoding_done(lc->page));

        ddjvu_document_get_pageinfo(lc->document, pagenum, &info);

        image->resolution.x = (float) info.dpi;
        image->resolution.y =(float) info.dpi;
        if (image_info->density != (char *) NULL)
          {
            int
              flags;

            GeometryInfo
              geometry_info;

            /*
              Set rendering resolution.
            */
            flags=ParseGeometry(image_info->density,&geometry_info);
            image->resolution.x=geometry_info.rho;
            image->resolution.y=geometry_info.sigma;
            if ((flags & SigmaValue) == 0)
              image->resolution.y=image->resolution.x;
            info.width*=image->resolution.x/info.dpi;
            info.height*=image->resolution.y/info.dpi;
            info.dpi=(ssize_t) MagickMax(image->resolution.x,image->resolution.y);
          }
        type = ddjvu_page_get_type(lc->page);

        /* double -> float! */
        /* image->gamma = (float)ddjvu_page_get_gamma(lc->page); */

        /* mmc:  set  image->depth  */
        /* mmc:  This from the type */

        image->columns=(size_t) info.width;
        image->rows=(size_t) info.height;

        /* mmc: bitonal should be palettized, and compressed! */
        if (type == DDJVU_PAGETYPE_BITONAL){
                image->colorspace = GRAYColorspace;
                image->storage_class = PseudoClass;
                image->depth =  8UL;    /* i only support that? */
                image->colors= 2;
                if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
                  ThrowReaderException(ResourceLimitError,
                   "MemoryAllocationFailed");
        } else {
                image->colorspace = RGBColorspace;
                image->storage_class = DirectClass;
                /* fixme:  MAGICKCORE_QUANTUM_DEPTH ?*/
                image->depth =  8UL;    /* i only support that? */

                image->alpha_trait = BlendPixelTrait;
                /* is this useful? */
        }
        status=SetImageExtent(image,image->columns,image->rows,exception);
        if (status == MagickFalse)
          return(DestroyImageList(image));
#if DEBUG
        printf("now filling %.20g x %.20g\n",(double) image->columns,(double)
          image->rows);
#endif


#if 1                           /* per_line */

        /* q = QueueAuthenticPixels(image,0,0,image->columns,image->rows); */
        get_page_image(lc, lc->page, 0, 0, info.width, info.height, exception);
#else
        int i;
        for (i = 0;i< image->rows; i++)
                {
                        printf("%d\n",i);
                        q = QueueAuthenticPixels(image,0,i,image->columns,1);
                        get_page_line(lc, i, quantum_info);
                        SyncAuthenticPixels(image);
                }

#endif /* per_line */


#if DEBUG
        printf("END: finished filling %.20g x %.20g\n",(double) image->columns,
          (double) image->rows);
#endif

        if (!image->ping)
          SyncImage(image,exception);
        /* mmc: ??? Convert PNM pixels to runlength-encoded MIFF packets. */
        /* image->colors =  */

        /* how is the line padding  / stride? */

        if (lc->page) {
                ddjvu_page_release(lc->page);
                lc->page = NULL;
        }

        /* image->page.y=mng_info->y_off[mng_info->object_id]; */
        if (tag == 0)
          image=DestroyImage(image);
        return image;
        /* end of reading one DJVU page/image */
}

#if 0
/* palette */
  if (AcquireImageColormap(image,2,exception) == MagickFalse)
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
  /*
    Monochrome colormap.   mmc: this the default!
  */
  image->colormap[0].red=QuantumRange;
  image->colormap[0].green=QuantumRange;
  image->colormap[0].blue=QuantumRange;
  image->colormap[1].red=0;
  image->colormap[1].green=0;
  image->colormap[1].blue=0;
#endif

static void djvu_close_lc(LoadContext* lc)
{
        if (lc->document)
                ddjvu_document_release(lc->document);
        if (lc->context)
                ddjvu_context_release(lc->context);
        if (lc->page)
                ddjvu_page_release(lc->page);
        RelinquishMagickMemory(lc);
}

static Image *ReadDJVUImage(const ImageInfo *image_info,
  ExceptionInfo *exception)
{
  const char
    *url;

  ddjvu_message_t
    *message;

  Image
    *image,
    *images;

  int
    logging,
    use_cache;

  LoadContext
    *lc;

  MagickBooleanType
    status;

  register ssize_t
    i;

  /*
   * Open image file.
   */
  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);


  if (image_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename);

  assert(exception != (ExceptionInfo *) NULL);
  assert(exception->signature == MagickCoreSignature);


  logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadDJVUImage()");
  (void) logging;

  image = AcquireImage(image_info,exception); /* mmc: ?? */


  lc = (LoadContext *) NULL;
  status = OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
  if (status == MagickFalse)
    ThrowReaderException(FileOpenError,"UnableToOpenFile");
  /*
    Verify DJVU signature.
  */
#if 0
  count = ReadBlob(image,8,(unsigned char *) magic_number);

  /* IsDJVU(const unsigned char *magick,const size_t length) */
  if (memcmp(magic_number,"AT&TFORM",8) != 0)
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
#endif


  /*
   * Allocate a LoadContext structure.
   */
  lc = (LoadContext *) AcquireMagickMemory(sizeof(*lc));
  if (lc == NULL)
    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");


  /*
   * Initialize members of the MngInfo structure.
   */
  (void) ResetMagickMemory(lc,0,sizeof(LoadContext));

  lc->image = image;
  lc->pages = 0;
  lc->context = ddjvu_context_create("ImageMagick djvu loader"); /* g_program_name */

  ddjvu_cache_set_size(lc->context, 1); /* right? */
  use_cache = 0;
  /* document: here we don't have a filename, but, for the sake of generality, a FILE* ! */
  url="http://www.imagemagick.org/fake.djvu";
  lc->document = ddjvu_document_create(lc->context, url, use_cache); /* don't cache */
  ddjvu_document_set_user_data(lc->document, lc);


  /* now we wait the message-request for data: */
  message = ddjvu_message_wait(lc->context);

  if (message->m_any.tag != DDJVU_NEWSTREAM) {
          /* fixme: the djvu context, document! */

          ddjvu_document_release(lc->document);
          ddjvu_context_release(lc->context);

          RelinquishMagickMemory(lc);

          ThrowReaderException(ResourceLimitError,"Djvu initial message: unexpected type");
          return NULL;    /* error! */
  };

  lc->streamid = message->m_newstream.streamid;
  ddjvu_message_pop(lc->context);

  message = pump_data_until_message(lc,image);
  /* now process the messages: */


  if (message) do {
          process_message(message);
          ddjvu_message_pop(lc->context);
  } while ((message = ddjvu_message_peek(lc->context)));

  /* fixme: i hope we have not read any messages pertinent(?) related to the page itself!  */

  while (lc->pages == 0) {
          message = ddjvu_message_wait(lc->context);
          process_message(message);
          ddjvu_message_pop(lc->context);
  }

  images=NewImageList();
  i=0;
  if (image_info->number_scenes != 0)
    i=image_info->scene;
  for ( ; i < (ssize_t) lc->pages; i++)
  {
    image=ReadOneDJVUImage(lc,i,image_info,exception);
    if (image == (Image *) NULL)
      break;
    image->scene=i;
    AppendImageToList(&images,CloneImageList(image,exception));
    images->extent=GetBlobSize(image);
    if (image_info->number_scenes != 0)
      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
        break;
  }
  djvu_close_lc(lc);
  (void) CloseBlob(images);
  if (image != (Image *) NULL)
    image=DestroyImageList(image);

#if 0
  if ((image->page.width == 0) && (image->page.height == 0))
    {
      image->page.width = image->columns+image->page.x;
      image->page.height = image->rows+image->page.y;
    }
  if (image->columns == 0 || image->rows == 0)
    {
      if (logging != MagickFalse)
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
          "exit ReadDJVUImage() with error.");
      ThrowReaderException(CorruptImageError,"CorruptImage");
    }

  if (logging != MagickFalse)
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadDJVUImage()");
#endif


  return(GetFirstImageInList(images));
}
#endif

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e g i s t e r D J V U I m a g e                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  RegisterDJVUImage() adds attributes for the DJVU image format to
%  the list of supported formats.  The attributes include the image format
%  tag, a method to read and/or write the format, whether the format
%  supports the saving of more than one frame to the same file or blob,
%  whether the format supports native in-memory I/O, and a brief
%  description of the format.
%
%  The format of the RegisterDJVUImage method is:
%
%      size_t RegisterDJVUImage(void)
%
*/
ModuleExport size_t RegisterDJVUImage(void)
{
  char
    version[MagickPathExtent];

  MagickInfo
    *entry;

  static const char
    *DJVUNote =
    {
      "See http://www.djvuzone.org/ for details about the DJVU format.  The\n"
      "DJVU 1.2 specification is available there and at\n"
      "ftp://swrinde.nde.swri.edu/pub/djvu/documents/."
    };

  *version='\0';
#if defined(DJVU_LIBDJVU_VER_STRING)
  (void) ConcatenateMagickString(version,"libdjvu ",MagickPathExtent);
  (void) ConcatenateMagickString(version,DJVU_LIBDJVU_VER_STRING,MagickPathExtent);
#endif
  entry=AcquireMagickInfo("DJVU","DJVU","Deja vu");
#if defined(MAGICKCORE_DJVU_DELEGATE)
  entry->decoder=(DecodeImageHandler *) ReadDJVUImage;
#endif
  entry->magick=(IsImageFormatHandler *) IsDJVU;
  entry->flags|=CoderRawSupportFlag;
  entry->flags^=CoderAdjoinFlag;
  if (*version != '\0')
    entry->version=AcquireString(version);
  entry->note=AcquireString(DJVUNote);
  (void) RegisterMagickInfo(entry);
  return(MagickImageCoderSignature);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   U n r e g i s t e r D J V U I m a g e                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  UnregisterDJVUImage() removes format registrations made by the
%  DJVU module from the list of supported formats.
%
%  The format of the UnregisterDJVUImage method is:
%
%      UnregisterDJVUImage(void)
%
*/
ModuleExport void UnregisterDJVUImage(void)
{
  (void) UnregisterMagickInfo("DJVU");
}