blob: 2a664c80f3bef19ab87438cbf6ef498cf0d4b66a [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% DDDD J V V U U %
7% D D J V V U U %
8% D D J V V U U %
9% D D J J V V U U %
10% DDDD JJJ V UUU %
11% %
12% %
13% Read DjVu Images. %
14% %
15% Software Design %
16% John Cristy %
17% July 1992 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% 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*/
cristy4c08aed2011-07-01 19:47:50 +000042#include "MagickCore/studio.h"
43#include "MagickCore/blob.h"
44#include "MagickCore/blob-private.h"
45#include "MagickCore/cache.h"
46#include "MagickCore/colormap.h"
47#include "MagickCore/constitute.h"
48#include "MagickCore/exception.h"
49#include "MagickCore/exception-private.h"
50#include "MagickCore/list.h"
51#include "MagickCore/magick.h"
52#include "MagickCore/memory_.h"
53#include "MagickCore/monitor.h"
54#include "MagickCore/monitor-private.h"
55#include "MagickCore/pixel-accessor.h"
56#include "MagickCore/quantum-private.h"
57#include "MagickCore/static.h"
58#include "MagickCore/string_.h"
59#include "MagickCore/module.h"
cristy3ed852e2009-09-05 21:47:34 +000060#if defined(MAGICKCORE_DJVU_DELEGATE)
61#include <libdjvu/ddjvuapi.h>
62#endif
63
64/*
65%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66% %
67% %
68% %
69% I s D J V U %
70% %
71% %
72% %
73%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74%
75% IsDJVU() returns MagickTrue if the image format type, identified by the
76% magick string, is DJVU.
77%
78% The format of the IsDJVU method is:
79%
80% MagickBooleanType IsDJVU(const unsigned char *magick,const size_t length)
81%
82% A description of each parameter follows:
83%
84% o magick: compare image format pattern against these bytes.
85%
86% o length: Specifies the length of the magick string.
87%
88*/
89static MagickBooleanType IsDJVU(const unsigned char *magick,const size_t length)
90{
91 if (length < 8)
92 return(MagickFalse);
93 if (memcmp(magick,"AT&TFORM",8) == 0)
94 return(MagickTrue);
95 return(MagickFalse);
96}
97
98#if defined(MAGICKCORE_DJVU_DELEGATE)
99/*
100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101% %
102% %
103% %
104% R e a d D J V U I m a g e %
105% %
106% %
107% %
108%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109%
110% ReadDJVUImage() reads DJVU image and returns it. It allocates the memory
111% necessary for the new Image structure and returns a pointer to the new
112% image or set of images.
113%
114% The format of the ReadDJVUImage method is:
115%
116% Image *ReadDJVUImage(const ImageInfo *image_info,
117% ExceptionInfo *exception)
118%
119% A description of each parameter follows:
120%
121% o image_info: the image info.
122%
123% o exception: return any errors or warnings in this structure.
124%
125*/
126
127#if defined(__cplusplus) || defined(c_plusplus)
128extern "C" {
129#endif
130
131typedef struct _LoadContext
132 LoadContext;
133
134struct _LoadContext
135{
136 ddjvu_context_t* context;
137 ddjvu_document_t *document;
138 ddjvu_page_t *page;
139 int streamid;
140 int pages;
141 Image *image;
142};
143
144#define BLOCKSIZE 65536
145#if 0
146static void
147pump_data(Image *image, LoadContext* lc)
148{
149 int blocksize = BLOCKSIZE;
150 char data[BLOCKSIZE];
151 int size;
152
153 /* i might check for a condition! */
154 while ((size = (size_t) ReadBlob(image,(size_t) blocksize,data)) == blocksize) {
155 ddjvu_stream_write(lc->document, lc->streamid, data, size);
156 }
157 if (size)
158 ddjvu_stream_write(lc->document, lc->streamid, data, size);
159 ddjvu_stream_close(lc->document, lc->streamid, 0);
160}
161#endif
162
163/* returns NULL only after all is delivered! */
164static ddjvu_message_t*
165pump_data_until_message(LoadContext *lc,Image *image) /* ddjvu_context_t *context, type ddjvu_document_type_t */
166{
cristybb503372010-05-27 20:51:26 +0000167 size_t blocksize = BLOCKSIZE;
cristy3ed852e2009-09-05 21:47:34 +0000168 unsigned char data[BLOCKSIZE];
cristybb503372010-05-27 20:51:26 +0000169 size_t size;
cristy3ed852e2009-09-05 21:47:34 +0000170 ddjvu_message_t *message;
171
172 /* i might check for a condition! */
173 while (!(message = ddjvu_message_peek(lc->context))
cristybb503372010-05-27 20:51:26 +0000174 && (size = (size_t) ReadBlob(image,(size_t) blocksize,data)) == blocksize) {
cristy3ed852e2009-09-05 21:47:34 +0000175 ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
176 }
177 if (message)
178 return message;
179 if (size)
180 ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
181 ddjvu_stream_close(lc->document, lc->streamid, 0);
182 return NULL;
183}
184#define DEBUG 0
185
186#if DEBUG
187static const char*
188message_tag_name(ddjvu_message_tag_t tag)
189{
190 static char* names[] =
191 {
192 "ERROR",
193 "INFO",
194 "NEWSTREAM",
195 "DOCINFO",
196 "PAGEINFO",
197 "RELAYOUT",
198 "REDISPLAY",
199 "CHUNK",
200 "THUMBNAIL",
201 "PROGRESS",
202 };
203 if (tag <= DDJVU_PROGRESS)
204 return names[tag];
205 else {
206 /* bark! */
207 return 0;
208 }
209}
210#endif
211
212/* write out nice info on the message,
213 * and store in *user* data the info on progress.
214 * */
215int
216process_message(ddjvu_message_t *message)
217{
218
219#if 0
220 ddjvu_context_t* context= message->m_any.context;
221#endif
222
223 if (! message)
224 return(-1);
225#if DEBUG
226 printf("*** %s: %s.\n",__FUNCTION__, message_tag_name(message->m_any.tag));
227#endif
228
229
230 switch (message->m_any.tag){
231 case DDJVU_DOCINFO:
232 {
233 ddjvu_document_t* document= message->m_any.document;
234 /* ddjvu_document_decoding_status is set by libdjvu! */
235 /* we have some info on the document */
236 LoadContext *lc = (LoadContext *) ddjvu_document_get_user_data(document);
237 lc->pages = ddjvu_document_get_pagenum(document);
238#if DEBUG
239 printf("the doc has %d pages\n", ddjvu_document_get_pagenum(document));
240#endif
241 break;
242 }
243 case DDJVU_CHUNK:
244#if DEBUG
245 printf("the name of the chunk is: %s\n", message->m_chunk.chunkid);
246#endif
247 break;
248
249
250 case DDJVU_RELAYOUT:
251 case DDJVU_PAGEINFO:
252 {
253#if 0
254 ddjvu_page_t* page = message->m_any.page;
255 page_info* info = ddjvu_page_get_user_data(page);
256
257 printf("page decoding status: %d %s%s%s\n",
258 ddjvu_page_decoding_status(page),
259 status_color, status_name(ddjvu_page_decoding_status(page)), color_reset);
260
261 printf("the page LAYOUT changed: width x height: %d x %d @ %d dpi. Version %d, type %d\n",
262 // printf("page info:\n width x height: %d x %d @ %d dpi, version %d, type %d\n",
263 ddjvu_page_get_width(page),
264 ddjvu_page_get_height(page),
265 ddjvu_page_get_resolution(page),
266 ddjvu_page_get_version(page),
267 /* DDJVU_PAGETYPE_BITONAL */
268 ddjvu_page_get_type(page));
269
270 info->info = 1;
271#endif
272 break;
273 }
274
275 case DDJVU_REDISPLAY:
276 {
277
278#if 0
279 ddjvu_page_t* page = message->m_any.page;
280 page_info* info = ddjvu_page_get_user_data(page);
281
282 printf("the page can/should be REDISPLAYED\n");
283 info->display = 1;
284#endif
285 break;
286 }
287
288 case DDJVU_PROGRESS:
289#if DEBUG
290 printf("PROGRESS:\n");
291#endif
292 break;
293 case DDJVU_ERROR:
294 printf("simply ERROR!\n message:\t%s\nfunction:\t%s(file %s)\nlineno:\t%d\n",
295 message->m_error.message,
296 message->m_error.function,
297 message->m_error.filename,
298 message->m_error.lineno);
299 break;
300 case DDJVU_INFO:
301#if DEBUG
302 printf("INFO: %s!\n", message->m_info.message);
303#endif
304 break;
305 default:
306 printf("unexpected\n");
307 };
308 return(message->m_any.tag);
309}
310
311
312#if defined(__cplusplus) || defined(c_plusplus)
313}
314#endif
315
316
317#define RGB 1
318
319/*
320 * DjVu advertised readiness to provide bitmap: So get it!
321 * we use the RGB format!
322 */
323static void
cristyf19dd9c2011-05-23 23:04:35 +0000324get_page_image(LoadContext *lc, ddjvu_page_t *page, int x, int y, int w, int h, const ImageInfo *image_info ) {
cristy3ed852e2009-09-05 21:47:34 +0000325 ddjvu_format_t
326 *format;
327
328 ddjvu_page_type_t
329 type;
330
331 Image
332 *image;
333
334 int
335 ret,
336 stride;
337
338 unsigned char
339 *q;
340
341 ddjvu_rect_t rect;
342 rect.x = x;
343 rect.y = y;
344 rect.w = (unsigned int) w; /* /10 */
345 rect.h = (unsigned int) h; /* /10 */
346
347 image = lc->image;
348 type = ddjvu_page_get_type(lc->page);
349
350 /* stride of this temporary buffer: */
351 stride = (type == DDJVU_PAGETYPE_BITONAL)?
cristy98a85772011-05-23 21:46:44 +0000352 (image->columns + 7)/8 : image->columns *3;
cristy3ed852e2009-09-05 21:47:34 +0000353
cristy98a85772011-05-23 21:46:44 +0000354 q = (unsigned char *) AcquireQuantumMemory(image->rows,stride);
355 if (q == (unsigned char *) NULL)
356 return;
cristy3ed852e2009-09-05 21:47:34 +0000357
358 format = ddjvu_format_create(
359 (type == DDJVU_PAGETYPE_BITONAL)?DDJVU_FORMAT_LSBTOMSB : DDJVU_FORMAT_RGB24,
360 /* DDJVU_FORMAT_RGB24
361 * DDJVU_FORMAT_RGBMASK32*/
362 /* DDJVU_FORMAT_RGBMASK32 */
363 0, NULL);
364
365#if 0
366 /* fixme: ThrowReaderException is a macro, which uses `exception' variable */
367 if (format == NULL)
368 {
369 abort();
370 /* ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); */
371 }
372
373#endif
374 ddjvu_format_set_row_order(format, 1);
375 ddjvu_format_set_y_direction(format, 1);
376
377 ret = ddjvu_page_render(page,
378 DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
379 &rect,
380 &rect, /* mmc: ?? */
381 format,
382 stride, /* ?? */
383 (char*)q);
cristy9561fec2011-03-07 13:18:21 +0000384 (void) ret;
cristy3ed852e2009-09-05 21:47:34 +0000385 ddjvu_format_release(format);
386
387
388 if (type == DDJVU_PAGETYPE_BITONAL) {
389 /* */
390#if DEBUG
391 printf("%s: expanding BITONAL page/image\n", __FUNCTION__);
392#endif
cristybb503372010-05-27 20:51:26 +0000393 size_t bit, byte;
cristy3ed852e2009-09-05 21:47:34 +0000394
cristybb503372010-05-27 20:51:26 +0000395 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000396 {
cristy4c08aed2011-07-01 19:47:50 +0000397 Quantum * o = QueueAuthenticPixels(image,0,y,image->columns,1,&image->exception);
398 if (o == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000399 break;
cristy3ed852e2009-09-05 21:47:34 +0000400 bit=0;
401 byte=0;
402
403 /* fixme: the non-aligned, last =<7 bits ! that's ok!!!*/
cristybb503372010-05-27 20:51:26 +0000404 for (x= 0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000405 {
cristybb503372010-05-27 20:51:26 +0000406 if (bit == 0) byte= (size_t) q[(y * stride) + (x / 8)];
cristy3ed852e2009-09-05 21:47:34 +0000407
cristy4c08aed2011-07-01 19:47:50 +0000408 SetPixelIndex(image,(Quantum) (((byte & 0x01) != 0) ? 0x00 : 0x01),o);
cristy3ed852e2009-09-05 21:47:34 +0000409 bit++;
410 if (bit == 8)
411 bit=0;
412 byte>>=1;
cristyed231572011-07-14 02:18:59 +0000413 o+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000414 }
415 if (SyncAuthenticPixels(image,&image->exception) == MagickFalse)
416 break;
417 }
cristyf500a7b2010-07-01 18:23:49 +0000418 if (!image->ping)
419 SyncImage(image);
cristy3ed852e2009-09-05 21:47:34 +0000420 } else {
421#if DEBUG
422 printf("%s: expanding PHOTO page/image\n", __FUNCTION__);
423#endif
424 /* now transfer line-wise: */
cristybb503372010-05-27 20:51:26 +0000425 ssize_t i;
cristy3ed852e2009-09-05 21:47:34 +0000426#if 0
427 /* old: */
428 char* r;
429#else
cristy4c08aed2011-07-01 19:47:50 +0000430 register Quantum *r;
cristy98a85772011-05-23 21:46:44 +0000431 unsigned char *s;
cristy3ed852e2009-09-05 21:47:34 +0000432#endif
cristy98a85772011-05-23 21:46:44 +0000433 s=q;
434 for (i = 0;i< (ssize_t) image->rows; i++)
cristy3ed852e2009-09-05 21:47:34 +0000435 {
436#if DEBUG
437 if (i % 1000 == 0) printf("%d\n",i);
438#endif
cristy98a85772011-05-23 21:46:44 +0000439 r = QueueAuthenticPixels(image,0,i,image->columns,1,&image->exception);
cristy4c08aed2011-07-01 19:47:50 +0000440 if (r == (Quantum *) NULL)
cristy9561fec2011-03-07 13:18:21 +0000441 break;
cristy98a85772011-05-23 21:46:44 +0000442 for (x=0; x < (ssize_t) image->columns; x++)
443 {
cristy4c08aed2011-07-01 19:47:50 +0000444 SetPixelRed(image,ScaleCharToQuantum(*s++),r);
445 SetPixelGreen(image,ScaleCharToQuantum(*s++),r);
446 SetPixelBlue(image,ScaleCharToQuantum(*s++),r);
cristyed231572011-07-14 02:18:59 +0000447 r+=GetPixelChannels(image);
cristy98a85772011-05-23 21:46:44 +0000448 }
cristy3ed852e2009-09-05 21:47:34 +0000449
cristy98a85772011-05-23 21:46:44 +0000450 SyncAuthenticPixels(image,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +0000451 }
452 }
453 q=(unsigned char *) RelinquishMagickMemory(q);
454}
455
456
457#if defined(MAGICKCORE_DJVU_DELEGATE)
458
cristy95236b52009-12-30 21:56:45 +0000459#if 0
cristy3ed852e2009-09-05 21:47:34 +0000460static int
461get_page_line(LoadContext *lc, int row, QuantumInfo* quantum_info)
462{
463 ddjvu_format_t
464 *format;
465
466 int
467 ret;
468
469 size_t
470 stride;
471
472 unsigned char
473 *q;
474
475 ddjvu_rect_t rect, pagerect;
476 rect.x = 0;
477 rect.y = row;
478 rect.w = lc->image->columns; /* /10 */
479 rect.h = 1; /* /10 */
480
481 pagerect.x = 0;
482 pagerect.y = 0;
483 pagerect.w = lc->image->columns;
484 pagerect.h = lc->image->rows;
485
486
487 format = ddjvu_format_create(
488#if RGB
489 DDJVU_FORMAT_RGB24
490#else
491 DDJVU_FORMAT_GREY8
492#endif
493 ,
494 0, NULL);
495 ddjvu_format_set_row_order(format, 1);
496 ddjvu_format_set_y_direction(format, 1);
497
498 stride=1;
499#if RGB
500 stride=3;
501#endif
502 q = (unsigned char *) AcquireQuantumMemory(lc->image->columns,stride);
503
504 ret = ddjvu_page_render(lc->page,
505 DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
506 &pagerect,
507 &rect, /* mmc: ?? */
508 format,
509 pagerect.w * 3, /* ?? */
510 (char*)q);
511
512 ImportQuantumPixels(lc->image,
513 (CacheView *) NULL,
514 quantum_info,
515#if RGB
516 RGBQuantum
517#else
518 GrayQuantum
519#endif
520 ,q,&lc->image->exception);
521 q=(unsigned char *) RelinquishMagickMemory(q);
522 ddjvu_format_release(format);
523 return ret;
524}
525#endif
cristy95236b52009-12-30 21:56:45 +0000526#endif
cristy3ed852e2009-09-05 21:47:34 +0000527
528/*
529%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
530% %
531% %
532% %
533% R e a d O n e D J V U I m a g e %
534% %
535% %
536% %
537%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
538%
539% ReadOneDJVUImage() reads a Portable Network Graphics (DJVU) image file
540% (minus the 8-byte signature) and returns it. It allocates the memory
541% necessary for the new Image structure and returns a pointer to the new
542% image.
543%
544% The format of the ReadOneDJVUImage method is:
545%
546% Image *ReadOneDJVUImage(MngInfo *mng_info, const ImageInfo *image_info,
547% ExceptionInfo *exception)
548%
549% A description of each parameter follows:
550%
551% o mng_info: Specifies a pointer to a MngInfo structure.
552%
553% o image_info: the image info.
554%
555% o exception: return any errors or warnings in this structure.
556%
557*/
558
559static inline double MagickMax(const double x,const double y)
560{
561 if (x > y)
562 return(x);
563 return(y);
564}
565
566static Image *ReadOneDJVUImage(LoadContext* lc,const int pagenum,
567 const ImageInfo *image_info,ExceptionInfo *exception)
568{
569 ddjvu_page_type_t
570 type;
571
572 ddjvu_pageinfo_t info;
cristy3ed852e2009-09-05 21:47:34 +0000573 ddjvu_message_t *message;
574 Image *image;
575 int logging;
576 int tag;
577
578 /* so, we know that the page is there! Get its dimension, and */
579
580 /* Read one DJVU image */
581 image = lc->image;
582
cristy4c08aed2011-07-01 19:47:50 +0000583 /* register Quantum *q; */
cristy3ed852e2009-09-05 21:47:34 +0000584
585 logging=LogMagickEvent(CoderEvent,GetMagickModule(), " enter ReadOneDJVUImage()");
cristyc8d21992011-03-09 13:17:20 +0000586 (void) logging;
cristy3ed852e2009-09-05 21:47:34 +0000587
588#if DEBUG
589 printf("==== Loading the page %d\n", pagenum);
590#endif
591 lc->page = ddjvu_page_create_by_pageno(lc->document, pagenum); /* 0? */
592
593 /* pump data untill the page is ready for rendering. */
594 tag=(-1);
595 do {
596 while ((message = ddjvu_message_peek(lc->context)))
597 {
598 tag=process_message(message);
599 if (tag == 0) break;
600 ddjvu_message_pop(lc->context);
601 }
602 /* fixme: maybe exit? */
603 /* if (lc->error) break; */
604
605 message = pump_data_until_message(lc,image);
606 if (message)
607 do {
608 tag=process_message(message);
609 if (tag == 0) break;
610 ddjvu_message_pop(lc->context);
611 } while ((message = ddjvu_message_peek(lc->context)));
612 } while (!ddjvu_page_decoding_done(lc->page));
613
614 ddjvu_document_get_pageinfo(lc->document, pagenum, &info);
615
616 image->x_resolution = (float) info.dpi;
617 image->y_resolution =(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->x_resolution=geometry_info.rho;
631 image->y_resolution=geometry_info.sigma;
632 if ((flags & SigmaValue) == 0)
633 image->y_resolution=image->x_resolution;
634 info.width*=image->x_resolution/info.dpi;
635 info.height*=image->y_resolution/info.dpi;
cristybb503372010-05-27 20:51:26 +0000636 info.dpi=(ssize_t) MagickMax(image->x_resolution,image->y_resolution);
cristy3ed852e2009-09-05 21:47:34 +0000637 }
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
cristybb503372010-05-27 20:51:26 +0000646 image->columns=(size_t) info.width;
647 image->rows=(size_t) info.height;
cristy3ed852e2009-09-05 21:47:34 +0000648
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;
cristy018f07f2011-09-04 21:15:19 +0000655 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000656 ThrowReaderException(ResourceLimitError,
657 "MemoryAllocationFailed");
658 } else {
659 image->colorspace = RGBColorspace;
660 image->storage_class = DirectClass;
661 /* fixme: MAGICKCORE_QUANTUM_DEPTH ?*/
662 image->depth = 8UL; /* i only support that? */
663
664 image->matte = MagickTrue;
665 /* is this useful? */
666 }
667#if DEBUG
cristye8c25f92010-06-03 00:53:06 +0000668 printf("now filling %.20g x %.20g\n",(double) image->columns,(double)
669 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000670#endif
671
672
673#if 1 /* per_line */
cristy3ed852e2009-09-05 21:47:34 +0000674
675 /* q = QueueAuthenticPixels(image,0,0,image->columns,image->rows); */
cristy98a85772011-05-23 21:46:44 +0000676 get_page_image(lc, lc->page, 0, 0, info.width, info.height, image_info);
cristy3ed852e2009-09-05 21:47:34 +0000677#else
678 int i;
679 for (i = 0;i< image->rows; i++)
680 {
681 printf("%d\n",i);
682 q = QueueAuthenticPixels(image,0,i,image->columns,1);
683 get_page_line(lc, i, quantum_info);
684 SyncAuthenticPixels(image);
685 }
686
687#endif /* per_line */
688
689
690#if DEBUG
cristye8c25f92010-06-03 00:53:06 +0000691 printf("END: finished filling %.20g x %.20g\n",(double) image->columns,
692 (double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000693#endif
694
cristyf500a7b2010-07-01 18:23:49 +0000695 if (!image->ping)
696 SyncImage(image);
cristy3ed852e2009-09-05 21:47:34 +0000697 /* mmc: ??? Convert PNM pixels to runlength-encoded MIFF packets. */
698 /* image->colors = */
699
700 /* how is the line padding / stride? */
701
702 if (lc->page) {
703 ddjvu_page_release(lc->page);
704 lc->page = NULL;
705 }
706
707 /* image->page.y=mng_info->y_off[mng_info->object_id]; */
708 if (tag == 0)
709 image=DestroyImage(image);
710 return image;
711 /* end of reading one DJVU page/image */
712}
713
714#if 0
715/* palette */
cristy018f07f2011-09-04 21:15:19 +0000716 if (AcquireImageColormap(image,2,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000717 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
718 /*
719 Monochrome colormap. mmc: this the default!
720 */
721 image->colormap[0].red=QuantumRange;
722 image->colormap[0].green=QuantumRange;
723 image->colormap[0].blue=QuantumRange;
724 image->colormap[1].red=0;
725 image->colormap[1].green=0;
726 image->colormap[1].blue=0;
727#endif
728
729static void djvu_close_lc(LoadContext* lc)
730{
731 if (lc->document)
732 ddjvu_document_release(lc->document);
733 if (lc->context)
734 ddjvu_context_release(lc->context);
735 if (lc->page)
736 ddjvu_page_release(lc->page);
737 RelinquishMagickMemory(lc);
738}
739
740static Image *ReadDJVUImage(const ImageInfo *image_info,
741 ExceptionInfo *exception)
742{
743 const char
744 *url;
745
746 ddjvu_message_t
747 *message;
748
749 Image
750 *image,
751 *images;
752
753 int
754 logging,
755 use_cache;
756
757 LoadContext
758 *lc;
759
760 MagickBooleanType
761 status;
762
cristybb503372010-05-27 20:51:26 +0000763 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000764 i;
765
766 /*
767 * Open image file.
768 */
769 assert(image_info != (const ImageInfo *) NULL);
770 assert(image_info->signature == MagickSignature);
771
772
773 if (image_info->debug != MagickFalse)
774 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename);
775
776 assert(exception != (ExceptionInfo *) NULL);
777 assert(exception->signature == MagickSignature);
778
779
780 logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadDJVUImage()");
cristy9561fec2011-03-07 13:18:21 +0000781 (void) logging;
cristy3ed852e2009-09-05 21:47:34 +0000782
cristy9950d572011-10-01 18:22:35 +0000783 image = AcquireImage(image_info,exception); /* mmc: ?? */
cristy3ed852e2009-09-05 21:47:34 +0000784
785
786 lc = (LoadContext *) NULL;
787 status = OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
788 if (status == MagickFalse)
789 ThrowReaderException(FileOpenError,"UnableToOpenFile");
790 /*
791 Verify DJVU signature.
792 */
793#if 0
794 count = ReadBlob(image,8,(unsigned char *) magic_number);
795
796 /* IsDJVU(const unsigned char *magick,const size_t length) */
797 if (memcmp(magic_number,"AT&TFORM",8) != 0)
798 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
799#endif
800
801
802 /*
803 * Allocate a LoadContext structure.
804 */
cristy73bd4a52010-10-05 11:24:23 +0000805 lc = (LoadContext *) AcquireMagickMemory(sizeof(*lc));
cristy3ed852e2009-09-05 21:47:34 +0000806 if (lc == NULL)
807 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
808
809
810 /*
811 * Initialize members of the MngInfo structure.
812 */
813 (void) ResetMagickMemory(lc,0,sizeof(LoadContext));
814
815 lc->image = image;
816 lc->pages = 0;
817 lc->context = ddjvu_context_create("ImageMagick djvu loader"); /* g_program_name */
818
819 ddjvu_cache_set_size(lc->context, 1); /* right? */
820 use_cache = 0;
821 /* document: here we don't have a filename, but, for the sake of generality, a FILE* ! */
cristy79565a22010-06-25 01:38:52 +0000822 url="http://www.imagemagick.org/fake.djvu";
cristy3ed852e2009-09-05 21:47:34 +0000823 lc->document = ddjvu_document_create(lc->context, url, use_cache); /* don't cache */
824 ddjvu_document_set_user_data(lc->document, lc);
825
826
827 /* now we wait the message-request for data: */
828 message = ddjvu_message_wait(lc->context);
829
830 if (message->m_any.tag != DDJVU_NEWSTREAM) {
831 /* fixme: the djvu context, document! */
832
833 ddjvu_document_release(lc->document);
834 ddjvu_context_release(lc->context);
835
836 RelinquishMagickMemory(lc);
837
838 ThrowReaderException(ResourceLimitError,"Djvu initial message: unexpected type");
839 return NULL; /* error! */
840 };
841
842 lc->streamid = message->m_newstream.streamid;
843 ddjvu_message_pop(lc->context);
844
845 message = pump_data_until_message(lc,image);
846 /* now process the messages: */
847
848
849 if (message) do {
850 process_message(message);
851 ddjvu_message_pop(lc->context);
852 } while ((message = ddjvu_message_peek(lc->context)));
853
854 /* fixme: i hope we have not read any messages pertinent(?) related to the page itself! */
855
856 while (lc->pages == 0) {
857 message = ddjvu_message_wait(lc->context);
858 process_message(message);
859 ddjvu_message_pop(lc->context);
860 }
861
862 images=NewImageList();
863 i=0;
864 if (image_info->number_scenes != 0)
865 i=image_info->scene;
cristybb503372010-05-27 20:51:26 +0000866 for ( ; i < (ssize_t) lc->pages; i++)
cristy3ed852e2009-09-05 21:47:34 +0000867 {
868 image=ReadOneDJVUImage(lc,i,image_info,exception);
869 if (image == (Image *) NULL)
870 break;
cristyc3ebda22010-06-27 17:11:57 +0000871 image->scene=i;
cristy3ed852e2009-09-05 21:47:34 +0000872 AppendImageToList(&images,CloneImageList(image,exception));
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%
cristybb503372010-05-27 20:51:26 +0000925% size_t RegisterDJVUImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000926%
927*/
cristybb503372010-05-27 20:51:26 +0000928ModuleExport size_t RegisterDJVUImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000929{
930 char
931 version[MaxTextExtent];
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 ",MaxTextExtent);
947 (void) ConcatenateMagickString(version,DJVU_LIBDJVU_VER_STRING,MaxTextExtent);
948#endif
949 entry=SetMagickInfo("DJVU");
950#if defined(MAGICKCORE_DJVU_DELEGATE)
951 entry->decoder=(DecodeImageHandler *) ReadDJVUImage;
952#endif
953 entry->raw=MagickTrue;
954 entry->magick=(IsImageFormatHandler *) IsDJVU;
955 entry->adjoin=MagickFalse;
956 entry->thread_support=MagickTrue;
957 entry->description=AcquireString("Déjà vu");
958 entry->module=AcquireString("DJVU");
959 if (*version != '\0')
960 entry->version=AcquireString(version);
961 entry->note=AcquireString(DJVUNote);
962 (void) RegisterMagickInfo(entry);
963 return(MagickImageCoderSignature);
964}
965
966/*
967%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
968% %
969% %
970% %
971% U n r e g i s t e r D J V U I m a g e %
972% %
973% %
974% %
975%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
976%
977% UnregisterDJVUImage() removes format registrations made by the
978% DJVU module from the list of supported formats.
979%
980% The format of the UnregisterDJVUImage method is:
981%
982% UnregisterDJVUImage(void)
983%
984*/
985ModuleExport void UnregisterDJVUImage(void)
986{
987 (void) UnregisterMagickInfo("DJVU");
988}