blob: 5d8cb66dcbe5f4f9616ae7cb3a2bf7886fb009f8 [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*/
42#include "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/cache.h"
cristyaeb2cbc2010-05-07 13:28:58 +000046#include "magick/colormap.h"
cristy3ed852e2009-09-05 21:47:34 +000047#include "magick/constitute.h"
48#include "magick/exception.h"
49#include "magick/exception-private.h"
50#include "magick/list.h"
51#include "magick/magick.h"
52#include "magick/memory_.h"
53#include "magick/monitor.h"
54#include "magick/monitor-private.h"
55#include "magick/quantum-private.h"
56#include "magick/static.h"
57#include "magick/string_.h"
58#include "magick/module.h"
59#if defined(MAGICKCORE_DJVU_DELEGATE)
60#include <libdjvu/ddjvuapi.h>
61#endif
62
63/*
64%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65% %
66% %
67% %
68% I s D J V U %
69% %
70% %
71% %
72%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73%
74% IsDJVU() returns MagickTrue if the image format type, identified by the
75% magick string, is DJVU.
76%
77% The format of the IsDJVU method is:
78%
79% MagickBooleanType IsDJVU(const unsigned char *magick,const size_t length)
80%
81% A description of each parameter follows:
82%
83% o magick: compare image format pattern against these bytes.
84%
85% o length: Specifies the length of the magick string.
86%
87*/
88static MagickBooleanType IsDJVU(const unsigned char *magick,const size_t length)
89{
90 if (length < 8)
91 return(MagickFalse);
92 if (memcmp(magick,"AT&TFORM",8) == 0)
93 return(MagickTrue);
94 return(MagickFalse);
95}
96
97#if defined(MAGICKCORE_DJVU_DELEGATE)
98/*
99%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100% %
101% %
102% %
103% R e a d D J V U I m a g e %
104% %
105% %
106% %
107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108%
109% ReadDJVUImage() reads DJVU image and returns it. It allocates the memory
110% necessary for the new Image structure and returns a pointer to the new
111% image or set of images.
112%
113% The format of the ReadDJVUImage method is:
114%
115% Image *ReadDJVUImage(const ImageInfo *image_info,
116% ExceptionInfo *exception)
117%
118% A description of each parameter follows:
119%
120% o image_info: the image info.
121%
122% o exception: return any errors or warnings in this structure.
123%
124*/
125
126#if defined(__cplusplus) || defined(c_plusplus)
127extern "C" {
128#endif
129
130typedef struct _LoadContext
131 LoadContext;
132
133struct _LoadContext
134{
135 ddjvu_context_t* context;
136 ddjvu_document_t *document;
137 ddjvu_page_t *page;
138 int streamid;
139 int pages;
140 Image *image;
141};
142
143#define BLOCKSIZE 65536
144#if 0
145static void
146pump_data(Image *image, LoadContext* lc)
147{
148 int blocksize = BLOCKSIZE;
149 char data[BLOCKSIZE];
150 int size;
151
152 /* i might check for a condition! */
153 while ((size = (size_t) ReadBlob(image,(size_t) blocksize,data)) == blocksize) {
154 ddjvu_stream_write(lc->document, lc->streamid, data, size);
155 }
156 if (size)
157 ddjvu_stream_write(lc->document, lc->streamid, data, size);
158 ddjvu_stream_close(lc->document, lc->streamid, 0);
159}
160#endif
161
162/* returns NULL only after all is delivered! */
163static ddjvu_message_t*
164pump_data_until_message(LoadContext *lc,Image *image) /* ddjvu_context_t *context, type ddjvu_document_type_t */
165{
cristybb503372010-05-27 20:51:26 +0000166 size_t blocksize = BLOCKSIZE;
cristy3ed852e2009-09-05 21:47:34 +0000167 unsigned char data[BLOCKSIZE];
cristybb503372010-05-27 20:51:26 +0000168 size_t size;
cristy3ed852e2009-09-05 21:47:34 +0000169 ddjvu_message_t *message;
170
171 /* i might check for a condition! */
172 while (!(message = ddjvu_message_peek(lc->context))
cristybb503372010-05-27 20:51:26 +0000173 && (size = (size_t) ReadBlob(image,(size_t) blocksize,data)) == blocksize) {
cristy3ed852e2009-09-05 21:47:34 +0000174 ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
175 }
176 if (message)
177 return message;
178 if (size)
179 ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
180 ddjvu_stream_close(lc->document, lc->streamid, 0);
181 return NULL;
182}
183#define DEBUG 0
184
185#if DEBUG
186static const char*
187message_tag_name(ddjvu_message_tag_t tag)
188{
189 static char* names[] =
190 {
191 "ERROR",
192 "INFO",
193 "NEWSTREAM",
194 "DOCINFO",
195 "PAGEINFO",
196 "RELAYOUT",
197 "REDISPLAY",
198 "CHUNK",
199 "THUMBNAIL",
200 "PROGRESS",
201 };
202 if (tag <= DDJVU_PROGRESS)
203 return names[tag];
204 else {
205 /* bark! */
206 return 0;
207 }
208}
209#endif
210
211/* write out nice info on the message,
212 * and store in *user* data the info on progress.
213 * */
214int
215process_message(ddjvu_message_t *message)
216{
217
218#if 0
219 ddjvu_context_t* context= message->m_any.context;
220#endif
221
222 if (! message)
223 return(-1);
224#if DEBUG
225 printf("*** %s: %s.\n",__FUNCTION__, message_tag_name(message->m_any.tag));
226#endif
227
228
229 switch (message->m_any.tag){
230 case DDJVU_DOCINFO:
231 {
232 ddjvu_document_t* document= message->m_any.document;
233 /* ddjvu_document_decoding_status is set by libdjvu! */
234 /* we have some info on the document */
235 LoadContext *lc = (LoadContext *) ddjvu_document_get_user_data(document);
236 lc->pages = ddjvu_document_get_pagenum(document);
237#if DEBUG
238 printf("the doc has %d pages\n", ddjvu_document_get_pagenum(document));
239#endif
240 break;
241 }
242 case DDJVU_CHUNK:
243#if DEBUG
244 printf("the name of the chunk is: %s\n", message->m_chunk.chunkid);
245#endif
246 break;
247
248
249 case DDJVU_RELAYOUT:
250 case DDJVU_PAGEINFO:
251 {
252#if 0
253 ddjvu_page_t* page = message->m_any.page;
254 page_info* info = ddjvu_page_get_user_data(page);
255
256 printf("page decoding status: %d %s%s%s\n",
257 ddjvu_page_decoding_status(page),
258 status_color, status_name(ddjvu_page_decoding_status(page)), color_reset);
259
260 printf("the page LAYOUT changed: width x height: %d x %d @ %d dpi. Version %d, type %d\n",
261 // printf("page info:\n width x height: %d x %d @ %d dpi, version %d, type %d\n",
262 ddjvu_page_get_width(page),
263 ddjvu_page_get_height(page),
264 ddjvu_page_get_resolution(page),
265 ddjvu_page_get_version(page),
266 /* DDJVU_PAGETYPE_BITONAL */
267 ddjvu_page_get_type(page));
268
269 info->info = 1;
270#endif
271 break;
272 }
273
274 case DDJVU_REDISPLAY:
275 {
276
277#if 0
278 ddjvu_page_t* page = message->m_any.page;
279 page_info* info = ddjvu_page_get_user_data(page);
280
281 printf("the page can/should be REDISPLAYED\n");
282 info->display = 1;
283#endif
284 break;
285 }
286
287 case DDJVU_PROGRESS:
288#if DEBUG
289 printf("PROGRESS:\n");
290#endif
291 break;
292 case DDJVU_ERROR:
293 printf("simply ERROR!\n message:\t%s\nfunction:\t%s(file %s)\nlineno:\t%d\n",
294 message->m_error.message,
295 message->m_error.function,
296 message->m_error.filename,
297 message->m_error.lineno);
298 break;
299 case DDJVU_INFO:
300#if DEBUG
301 printf("INFO: %s!\n", message->m_info.message);
302#endif
303 break;
304 default:
305 printf("unexpected\n");
306 };
307 return(message->m_any.tag);
308}
309
310
311#if defined(__cplusplus) || defined(c_plusplus)
312}
313#endif
314
315
316#define RGB 1
317
318/*
319 * DjVu advertised readiness to provide bitmap: So get it!
320 * we use the RGB format!
321 */
322static void
323get_page_image(LoadContext *lc, ddjvu_page_t *page, int x, int y, int w, int h, QuantumInfo* quantum_info)
324{
325 ddjvu_format_t
326 *format;
327
328 ddjvu_page_type_t
329 type;
330
331 Image
332 *image;
333
334 int
335 ret,
336 stride;
337
338 unsigned char
339 *q;
340
341 ddjvu_rect_t rect;
342 rect.x = x;
343 rect.y = y;
344 rect.w = (unsigned int) w; /* /10 */
345 rect.h = (unsigned int) h; /* /10 */
346
347 image = lc->image;
348 type = ddjvu_page_get_type(lc->page);
349
350 /* stride of this temporary buffer: */
351 stride = (type == DDJVU_PAGETYPE_BITONAL)?
352 (lc->image->columns + 7)/8:
353 lc->image->columns *3;
354
355 q = (unsigned char *) AcquireQuantumMemory(lc->image->rows,stride);
356
357
358 format = ddjvu_format_create(
359 (type == DDJVU_PAGETYPE_BITONAL)?DDJVU_FORMAT_LSBTOMSB : DDJVU_FORMAT_RGB24,
360 /* DDJVU_FORMAT_RGB24
361 * DDJVU_FORMAT_RGBMASK32*/
362 /* DDJVU_FORMAT_RGBMASK32 */
363 0, NULL);
364
365#if 0
366 /* fixme: ThrowReaderException is a macro, which uses `exception' variable */
367 if (format == NULL)
368 {
369 abort();
370 /* ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); */
371 }
372
373#endif
374 ddjvu_format_set_row_order(format, 1);
375 ddjvu_format_set_y_direction(format, 1);
376
377 ret = ddjvu_page_render(page,
378 DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
379 &rect,
380 &rect, /* mmc: ?? */
381 format,
382 stride, /* ?? */
383 (char*)q);
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
393 register IndexPacket *indexes;
cristybb503372010-05-27 20:51:26 +0000394 size_t bit, byte;
cristy3ed852e2009-09-05 21:47:34 +0000395
cristybb503372010-05-27 20:51:26 +0000396 for (y=0; y < (ssize_t) image->rows; y++)
cristy3ed852e2009-09-05 21:47:34 +0000397 {
398 PixelPacket * o = QueueAuthenticPixels(image,0,y,image->columns,1,&image->exception);
399 if (o == (PixelPacket *) NULL)
400 break;
401 indexes=GetAuthenticIndexQueue(image);
402 bit=0;
403 byte=0;
404
405 /* fixme: the non-aligned, last =<7 bits ! that's ok!!!*/
cristybb503372010-05-27 20:51:26 +0000406 for (x= 0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000407 {
cristybb503372010-05-27 20:51:26 +0000408 if (bit == 0) byte= (size_t) q[(y * stride) + (x / 8)];
cristy3ed852e2009-09-05 21:47:34 +0000409
cristyddbc41b2011-04-24 14:27:48 +0000410 SetIndexPixelComponent(indexes+x,(IndexPacket) (((byte & 0x01) != 0) ? 0x00 : 0x01));
cristy3ed852e2009-09-05 21:47:34 +0000411 bit++;
412 if (bit == 8)
413 bit=0;
414 byte>>=1;
415 }
416 if (SyncAuthenticPixels(image,&image->exception) == MagickFalse)
417 break;
418 }
cristyf500a7b2010-07-01 18:23:49 +0000419 if (!image->ping)
420 SyncImage(image);
cristy3ed852e2009-09-05 21:47:34 +0000421 } else {
422#if DEBUG
423 printf("%s: expanding PHOTO page/image\n", __FUNCTION__);
424#endif
425 /* now transfer line-wise: */
cristybb503372010-05-27 20:51:26 +0000426 ssize_t i;
cristy3ed852e2009-09-05 21:47:34 +0000427#if 0
428 /* old: */
429 char* r;
430#else
431 register PixelPacket *r;
432#endif
433
cristybb503372010-05-27 20:51:26 +0000434 for (i = 0;i< (ssize_t) lc->image->rows; i++)
cristy3ed852e2009-09-05 21:47:34 +0000435 {
436#if DEBUG
437 if (i % 1000 == 0) printf("%d\n",i);
438#endif
439 r = QueueAuthenticPixels(lc->image,0,i,lc->image->columns,1,&image->exception);
cristy9561fec2011-03-07 13:18:21 +0000440 if (r == (PixelPacket *) NULL)
441 break;
cristy3ed852e2009-09-05 21:47:34 +0000442
cristy9561fec2011-03-07 13:18:21 +0000443 ImportQuantumPixels(lc->image,
cristy3ed852e2009-09-05 21:47:34 +0000444 (CacheView *) NULL,
445 quantum_info,
446 RGBQuantum, /*GrayQuantum*/
447 q+i*stride,&image->exception);
cristy9561fec2011-03-07 13:18:21 +0000448 SyncAuthenticPixels(lc->image,&image->exception);
cristy3ed852e2009-09-05 21:47:34 +0000449 }
450 }
451 q=(unsigned char *) RelinquishMagickMemory(q);
452}
453
454
455#if defined(MAGICKCORE_DJVU_DELEGATE)
456
cristy95236b52009-12-30 21:56:45 +0000457#if 0
cristy3ed852e2009-09-05 21:47:34 +0000458static int
459get_page_line(LoadContext *lc, int row, QuantumInfo* quantum_info)
460{
461 ddjvu_format_t
462 *format;
463
464 int
465 ret;
466
467 size_t
468 stride;
469
470 unsigned char
471 *q;
472
473 ddjvu_rect_t rect, pagerect;
474 rect.x = 0;
475 rect.y = row;
476 rect.w = lc->image->columns; /* /10 */
477 rect.h = 1; /* /10 */
478
479 pagerect.x = 0;
480 pagerect.y = 0;
481 pagerect.w = lc->image->columns;
482 pagerect.h = lc->image->rows;
483
484
485 format = ddjvu_format_create(
486#if RGB
487 DDJVU_FORMAT_RGB24
488#else
489 DDJVU_FORMAT_GREY8
490#endif
491 ,
492 0, NULL);
493 ddjvu_format_set_row_order(format, 1);
494 ddjvu_format_set_y_direction(format, 1);
495
496 stride=1;
497#if RGB
498 stride=3;
499#endif
500 q = (unsigned char *) AcquireQuantumMemory(lc->image->columns,stride);
501
502 ret = ddjvu_page_render(lc->page,
503 DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
504 &pagerect,
505 &rect, /* mmc: ?? */
506 format,
507 pagerect.w * 3, /* ?? */
508 (char*)q);
509
510 ImportQuantumPixels(lc->image,
511 (CacheView *) NULL,
512 quantum_info,
513#if RGB
514 RGBQuantum
515#else
516 GrayQuantum
517#endif
518 ,q,&lc->image->exception);
519 q=(unsigned char *) RelinquishMagickMemory(q);
520 ddjvu_format_release(format);
521 return ret;
522}
523#endif
cristy95236b52009-12-30 21:56:45 +0000524#endif
cristy3ed852e2009-09-05 21:47:34 +0000525
526/*
527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
528% %
529% %
530% %
531% R e a d O n e D J V U I m a g e %
532% %
533% %
534% %
535%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
536%
537% ReadOneDJVUImage() reads a Portable Network Graphics (DJVU) image file
538% (minus the 8-byte signature) and returns it. It allocates the memory
539% necessary for the new Image structure and returns a pointer to the new
540% image.
541%
542% The format of the ReadOneDJVUImage method is:
543%
544% Image *ReadOneDJVUImage(MngInfo *mng_info, const ImageInfo *image_info,
545% ExceptionInfo *exception)
546%
547% A description of each parameter follows:
548%
549% o mng_info: Specifies a pointer to a MngInfo structure.
550%
551% o image_info: the image info.
552%
553% o exception: return any errors or warnings in this structure.
554%
555*/
556
557static inline double MagickMax(const double x,const double y)
558{
559 if (x > y)
560 return(x);
561 return(y);
562}
563
564static 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 QuantumInfo *quantum_info;
572 ddjvu_message_t *message;
573 Image *image;
574 int logging;
575 int tag;
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 PixelPacket *q; */
583
584 logging=LogMagickEvent(CoderEvent,GetMagickModule(), " enter ReadOneDJVUImage()");
cristyc8d21992011-03-09 13:17:20 +0000585 (void) logging;
cristy3ed852e2009-09-05 21:47:34 +0000586
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 } while (!ddjvu_page_decoding_done(lc->page));
612
613 ddjvu_document_get_pageinfo(lc->document, pagenum, &info);
614
615 image->x_resolution = (float) info.dpi;
616 image->y_resolution =(float) info.dpi;
617 if (image_info->density != (char *) NULL)
618 {
619 int
620 flags;
621
622 GeometryInfo
623 geometry_info;
624
625 /*
626 Set rendering resolution.
627 */
628 flags=ParseGeometry(image_info->density,&geometry_info);
629 image->x_resolution=geometry_info.rho;
630 image->y_resolution=geometry_info.sigma;
631 if ((flags & SigmaValue) == 0)
632 image->y_resolution=image->x_resolution;
633 info.width*=image->x_resolution/info.dpi;
634 info.height*=image->y_resolution/info.dpi;
cristybb503372010-05-27 20:51:26 +0000635 info.dpi=(ssize_t) MagickMax(image->x_resolution,image->y_resolution);
cristy3ed852e2009-09-05 21:47:34 +0000636 }
637 type = ddjvu_page_get_type(lc->page);
638
639 /* double -> float! */
640 /* image->gamma = (float)ddjvu_page_get_gamma(lc->page); */
641
642 /* mmc: set image->depth */
643 /* mmc: This from the type */
644
cristybb503372010-05-27 20:51:26 +0000645 image->columns=(size_t) info.width;
646 image->rows=(size_t) info.height;
cristy3ed852e2009-09-05 21:47:34 +0000647
648 /* mmc: bitonal should be palettized, and compressed! */
649 if (type == DDJVU_PAGETYPE_BITONAL){
650 image->colorspace = GRAYColorspace;
651 image->storage_class = PseudoClass;
652 image->depth = 8UL; /* i only support that? */
653 image->colors= 2;
654 if (AcquireImageColormap(image,image->colors) == MagickFalse)
655 ThrowReaderException(ResourceLimitError,
656 "MemoryAllocationFailed");
657 } else {
658 image->colorspace = RGBColorspace;
659 image->storage_class = DirectClass;
660 /* fixme: MAGICKCORE_QUANTUM_DEPTH ?*/
661 image->depth = 8UL; /* i only support that? */
662
663 image->matte = MagickTrue;
664 /* is this useful? */
665 }
666#if DEBUG
cristye8c25f92010-06-03 00:53:06 +0000667 printf("now filling %.20g x %.20g\n",(double) image->columns,(double)
668 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000669#endif
670
671
672#if 1 /* per_line */
673 quantum_info=AcquireQuantumInfo(image_info,image);
674 if (quantum_info == (QuantumInfo *) NULL)
675 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
676
677 /* q = QueueAuthenticPixels(image,0,0,image->columns,image->rows); */
678 get_page_image(lc, lc->page, 0, 0, info.width, info.height, quantum_info);
679#else
680 int i;
681 for (i = 0;i< image->rows; i++)
682 {
683 printf("%d\n",i);
684 q = QueueAuthenticPixels(image,0,i,image->columns,1);
685 get_page_line(lc, i, quantum_info);
686 SyncAuthenticPixels(image);
687 }
688
689#endif /* per_line */
690
691
692#if DEBUG
cristye8c25f92010-06-03 00:53:06 +0000693 printf("END: finished filling %.20g x %.20g\n",(double) image->columns,
694 (double) image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000695#endif
696
cristyf500a7b2010-07-01 18:23:49 +0000697 if (!image->ping)
698 SyncImage(image);
cristy3ed852e2009-09-05 21:47:34 +0000699 quantum_info=DestroyQuantumInfo(quantum_info);
700 /* indexes=GetAuthenticIndexQueue(image); */
701 /* mmc: ??? Convert PNM pixels to runlength-encoded MIFF packets. */
702 /* image->colors = */
703
704 /* how is the line padding / stride? */
705
706 if (lc->page) {
707 ddjvu_page_release(lc->page);
708 lc->page = NULL;
709 }
710
711 /* image->page.y=mng_info->y_off[mng_info->object_id]; */
712 if (tag == 0)
713 image=DestroyImage(image);
714 return image;
715 /* end of reading one DJVU page/image */
716}
717
718#if 0
719/* palette */
720 if (AcquireImageColormap(image,2) == MagickFalse)
721 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
722 /*
723 Monochrome colormap. mmc: this the default!
724 */
725 image->colormap[0].red=QuantumRange;
726 image->colormap[0].green=QuantumRange;
727 image->colormap[0].blue=QuantumRange;
728 image->colormap[1].red=0;
729 image->colormap[1].green=0;
730 image->colormap[1].blue=0;
731#endif
732
733static void djvu_close_lc(LoadContext* lc)
734{
735 if (lc->document)
736 ddjvu_document_release(lc->document);
737 if (lc->context)
738 ddjvu_context_release(lc->context);
739 if (lc->page)
740 ddjvu_page_release(lc->page);
741 RelinquishMagickMemory(lc);
742}
743
744static Image *ReadDJVUImage(const ImageInfo *image_info,
745 ExceptionInfo *exception)
746{
747 const char
748 *url;
749
750 ddjvu_message_t
751 *message;
752
753 Image
754 *image,
755 *images;
756
757 int
758 logging,
759 use_cache;
760
761 LoadContext
762 *lc;
763
764 MagickBooleanType
765 status;
766
cristybb503372010-05-27 20:51:26 +0000767 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000768 i;
769
770 /*
771 * Open image file.
772 */
773 assert(image_info != (const ImageInfo *) NULL);
774 assert(image_info->signature == MagickSignature);
775
776
777 if (image_info->debug != MagickFalse)
778 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename);
779
780 assert(exception != (ExceptionInfo *) NULL);
781 assert(exception->signature == MagickSignature);
782
783
784 logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadDJVUImage()");
cristy9561fec2011-03-07 13:18:21 +0000785 (void) logging;
cristy3ed852e2009-09-05 21:47:34 +0000786
787 image = AcquireImage(image_info); /* mmc: ?? */
788
789
790 lc = (LoadContext *) NULL;
791 status = OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
792 if (status == MagickFalse)
793 ThrowReaderException(FileOpenError,"UnableToOpenFile");
794 /*
795 Verify DJVU signature.
796 */
797#if 0
798 count = ReadBlob(image,8,(unsigned char *) magic_number);
799
800 /* IsDJVU(const unsigned char *magick,const size_t length) */
801 if (memcmp(magic_number,"AT&TFORM",8) != 0)
802 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
803#endif
804
805
806 /*
807 * Allocate a LoadContext structure.
808 */
cristy73bd4a52010-10-05 11:24:23 +0000809 lc = (LoadContext *) AcquireMagickMemory(sizeof(*lc));
cristy3ed852e2009-09-05 21:47:34 +0000810 if (lc == NULL)
811 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
812
813
814 /*
815 * Initialize members of the MngInfo structure.
816 */
817 (void) ResetMagickMemory(lc,0,sizeof(LoadContext));
818
819 lc->image = image;
820 lc->pages = 0;
821 lc->context = ddjvu_context_create("ImageMagick djvu loader"); /* g_program_name */
822
823 ddjvu_cache_set_size(lc->context, 1); /* right? */
824 use_cache = 0;
825 /* document: here we don't have a filename, but, for the sake of generality, a FILE* ! */
cristy79565a22010-06-25 01:38:52 +0000826 url="http://www.imagemagick.org/fake.djvu";
cristy3ed852e2009-09-05 21:47:34 +0000827 lc->document = ddjvu_document_create(lc->context, url, use_cache); /* don't cache */
828 ddjvu_document_set_user_data(lc->document, lc);
829
830
831 /* now we wait the message-request for data: */
832 message = ddjvu_message_wait(lc->context);
833
834 if (message->m_any.tag != DDJVU_NEWSTREAM) {
835 /* fixme: the djvu context, document! */
836
837 ddjvu_document_release(lc->document);
838 ddjvu_context_release(lc->context);
839
840 RelinquishMagickMemory(lc);
841
842 ThrowReaderException(ResourceLimitError,"Djvu initial message: unexpected type");
843 return NULL; /* error! */
844 };
845
846 lc->streamid = message->m_newstream.streamid;
847 ddjvu_message_pop(lc->context);
848
849 message = pump_data_until_message(lc,image);
850 /* now process the messages: */
851
852
853 if (message) do {
854 process_message(message);
855 ddjvu_message_pop(lc->context);
856 } while ((message = ddjvu_message_peek(lc->context)));
857
858 /* fixme: i hope we have not read any messages pertinent(?) related to the page itself! */
859
860 while (lc->pages == 0) {
861 message = ddjvu_message_wait(lc->context);
862 process_message(message);
863 ddjvu_message_pop(lc->context);
864 }
865
866 images=NewImageList();
867 i=0;
868 if (image_info->number_scenes != 0)
869 i=image_info->scene;
cristybb503372010-05-27 20:51:26 +0000870 for ( ; i < (ssize_t) lc->pages; i++)
cristy3ed852e2009-09-05 21:47:34 +0000871 {
872 image=ReadOneDJVUImage(lc,i,image_info,exception);
873 if (image == (Image *) NULL)
874 break;
cristyc3ebda22010-06-27 17:11:57 +0000875 image->scene=i;
cristy3ed852e2009-09-05 21:47:34 +0000876 AppendImageToList(&images,CloneImageList(image,exception));
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 (void) CloseBlob(images);
883 if (image != (Image *) NULL)
884 image=DestroyImageList(image);
885
886#if 0
887 if ((image->page.width == 0) && (image->page.height == 0))
888 {
889 image->page.width = image->columns+image->page.x;
890 image->page.height = image->rows+image->page.y;
891 }
892 if (image->columns == 0 || image->rows == 0)
893 {
894 if (logging != MagickFalse)
895 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
896 "exit ReadDJVUImage() with error.");
897 ThrowReaderException(CorruptImageError,"CorruptImage");
898 }
899
900 if (logging != MagickFalse)
901 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadDJVUImage()");
902#endif
903
904
905 return(GetFirstImageInList(images));
906}
907#endif
908
909/*
910%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
911% %
912% %
913% %
914% R e g i s t e r D J V U I m a g e %
915% %
916% %
917% %
918%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
919%
920% RegisterDJVUImage() adds attributes for the DJVU image format to
921% the list of supported formats. The attributes include the image format
922% tag, a method to read and/or write the format, whether the format
923% supports the saving of more than one frame to the same file or blob,
924% whether the format supports native in-memory I/O, and a brief
925% description of the format.
926%
927% The format of the RegisterDJVUImage method is:
928%
cristybb503372010-05-27 20:51:26 +0000929% size_t RegisterDJVUImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000930%
931*/
cristybb503372010-05-27 20:51:26 +0000932ModuleExport size_t RegisterDJVUImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000933{
934 char
935 version[MaxTextExtent];
936
937 MagickInfo
938 *entry;
939
940 static const char
941 *DJVUNote =
942 {
943 "See http://www.djvuzone.org/ for details about the DJVU format. The\n"
944 "DJVU 1.2 specification is available there and at\n"
945 "ftp://swrinde.nde.swri.edu/pub/djvu/documents/."
946 };
947
948 *version='\0';
949#if defined(DJVU_LIBDJVU_VER_STRING)
950 (void) ConcatenateMagickString(version,"libdjvu ",MaxTextExtent);
951 (void) ConcatenateMagickString(version,DJVU_LIBDJVU_VER_STRING,MaxTextExtent);
952#endif
953 entry=SetMagickInfo("DJVU");
954#if defined(MAGICKCORE_DJVU_DELEGATE)
955 entry->decoder=(DecodeImageHandler *) ReadDJVUImage;
956#endif
957 entry->raw=MagickTrue;
958 entry->magick=(IsImageFormatHandler *) IsDJVU;
959 entry->adjoin=MagickFalse;
960 entry->thread_support=MagickTrue;
961 entry->description=AcquireString("Déjà vu");
962 entry->module=AcquireString("DJVU");
963 if (*version != '\0')
964 entry->version=AcquireString(version);
965 entry->note=AcquireString(DJVUNote);
966 (void) RegisterMagickInfo(entry);
967 return(MagickImageCoderSignature);
968}
969
970/*
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*/
989ModuleExport void UnregisterDJVUImage(void)
990{
991 (void) UnregisterMagickInfo("DJVU");
992}