blob: 00a43c8c4c3d4ea71a09c291771101cbf4dbeec7 [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% %
cristy1454be72011-12-19 01:52:48 +000020% Copyright 1999-2012 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! */
cristy697f5a92012-01-20 23:58:38 +0000173 size=0;
cristy3ed852e2009-09-05 21:47:34 +0000174 while (!(message = ddjvu_message_peek(lc->context))
cristybb503372010-05-27 20:51:26 +0000175 && (size = (size_t) ReadBlob(image,(size_t) blocksize,data)) == blocksize) {
cristy3ed852e2009-09-05 21:47:34 +0000176 ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
177 }
178 if (message)
179 return message;
180 if (size)
181 ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
182 ddjvu_stream_close(lc->document, lc->streamid, 0);
183 return NULL;
184}
185#define DEBUG 0
186
187#if DEBUG
188static const char*
189message_tag_name(ddjvu_message_tag_t tag)
190{
191 static char* names[] =
192 {
193 "ERROR",
194 "INFO",
195 "NEWSTREAM",
196 "DOCINFO",
197 "PAGEINFO",
198 "RELAYOUT",
199 "REDISPLAY",
200 "CHUNK",
201 "THUMBNAIL",
202 "PROGRESS",
203 };
204 if (tag <= DDJVU_PROGRESS)
205 return names[tag];
206 else {
207 /* bark! */
208 return 0;
209 }
210}
211#endif
212
213/* write out nice info on the message,
214 * and store in *user* data the info on progress.
215 * */
216int
217process_message(ddjvu_message_t *message)
218{
219
220#if 0
221 ddjvu_context_t* context= message->m_any.context;
222#endif
223
224 if (! message)
225 return(-1);
226#if DEBUG
227 printf("*** %s: %s.\n",__FUNCTION__, message_tag_name(message->m_any.tag));
228#endif
229
230
231 switch (message->m_any.tag){
232 case DDJVU_DOCINFO:
233 {
234 ddjvu_document_t* document= message->m_any.document;
235 /* ddjvu_document_decoding_status is set by libdjvu! */
236 /* we have some info on the document */
237 LoadContext *lc = (LoadContext *) ddjvu_document_get_user_data(document);
238 lc->pages = ddjvu_document_get_pagenum(document);
239#if DEBUG
240 printf("the doc has %d pages\n", ddjvu_document_get_pagenum(document));
241#endif
242 break;
243 }
244 case DDJVU_CHUNK:
245#if DEBUG
246 printf("the name of the chunk is: %s\n", message->m_chunk.chunkid);
247#endif
248 break;
249
250
251 case DDJVU_RELAYOUT:
252 case DDJVU_PAGEINFO:
253 {
254#if 0
255 ddjvu_page_t* page = message->m_any.page;
256 page_info* info = ddjvu_page_get_user_data(page);
257
258 printf("page decoding status: %d %s%s%s\n",
259 ddjvu_page_decoding_status(page),
260 status_color, status_name(ddjvu_page_decoding_status(page)), color_reset);
261
262 printf("the page LAYOUT changed: width x height: %d x %d @ %d dpi. Version %d, type %d\n",
263 // printf("page info:\n width x height: %d x %d @ %d dpi, version %d, type %d\n",
264 ddjvu_page_get_width(page),
265 ddjvu_page_get_height(page),
266 ddjvu_page_get_resolution(page),
267 ddjvu_page_get_version(page),
268 /* DDJVU_PAGETYPE_BITONAL */
269 ddjvu_page_get_type(page));
270
271 info->info = 1;
272#endif
273 break;
274 }
275
276 case DDJVU_REDISPLAY:
277 {
278
279#if 0
280 ddjvu_page_t* page = message->m_any.page;
281 page_info* info = ddjvu_page_get_user_data(page);
282
283 printf("the page can/should be REDISPLAYED\n");
284 info->display = 1;
285#endif
286 break;
287 }
288
289 case DDJVU_PROGRESS:
290#if DEBUG
291 printf("PROGRESS:\n");
292#endif
293 break;
294 case DDJVU_ERROR:
295 printf("simply ERROR!\n message:\t%s\nfunction:\t%s(file %s)\nlineno:\t%d\n",
296 message->m_error.message,
297 message->m_error.function,
298 message->m_error.filename,
299 message->m_error.lineno);
300 break;
301 case DDJVU_INFO:
302#if DEBUG
303 printf("INFO: %s!\n", message->m_info.message);
304#endif
305 break;
306 default:
307 printf("unexpected\n");
308 };
309 return(message->m_any.tag);
310}
311
312
313#if defined(__cplusplus) || defined(c_plusplus)
314}
315#endif
316
317
318#define RGB 1
319
320/*
321 * DjVu advertised readiness to provide bitmap: So get it!
322 * we use the RGB format!
323 */
324static void
cristyc82a27b2011-10-21 01:07:16 +0000325get_page_image(LoadContext *lc, ddjvu_page_t *page, int x, int y, int w, int h, const ImageInfo *image_info, ExceptionInfo *exception ) {
cristy3ed852e2009-09-05 21:47:34 +0000326 ddjvu_format_t
327 *format;
328
329 ddjvu_page_type_t
330 type;
331
332 Image
333 *image;
334
335 int
336 ret,
337 stride;
338
339 unsigned char
340 *q;
341
342 ddjvu_rect_t rect;
343 rect.x = x;
344 rect.y = y;
345 rect.w = (unsigned int) w; /* /10 */
346 rect.h = (unsigned int) h; /* /10 */
347
348 image = lc->image;
349 type = ddjvu_page_get_type(lc->page);
350
351 /* stride of this temporary buffer: */
352 stride = (type == DDJVU_PAGETYPE_BITONAL)?
cristy98a85772011-05-23 21:46:44 +0000353 (image->columns + 7)/8 : image->columns *3;
cristy3ed852e2009-09-05 21:47:34 +0000354
cristy98a85772011-05-23 21:46:44 +0000355 q = (unsigned char *) AcquireQuantumMemory(image->rows,stride);
356 if (q == (unsigned char *) NULL)
357 return;
cristy3ed852e2009-09-05 21:47:34 +0000358
359 format = ddjvu_format_create(
360 (type == DDJVU_PAGETYPE_BITONAL)?DDJVU_FORMAT_LSBTOMSB : DDJVU_FORMAT_RGB24,
361 /* DDJVU_FORMAT_RGB24
362 * DDJVU_FORMAT_RGBMASK32*/
363 /* DDJVU_FORMAT_RGBMASK32 */
364 0, NULL);
365
366#if 0
367 /* fixme: ThrowReaderException is a macro, which uses `exception' variable */
368 if (format == NULL)
369 {
370 abort();
371 /* ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); */
372 }
373
374#endif
375 ddjvu_format_set_row_order(format, 1);
376 ddjvu_format_set_y_direction(format, 1);
377
378 ret = ddjvu_page_render(page,
379 DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
380 &rect,
381 &rect, /* mmc: ?? */
382 format,
383 stride, /* ?? */
384 (char*)q);
cristy9561fec2011-03-07 13:18:21 +0000385 (void) ret;
cristy3ed852e2009-09-05 21:47:34 +0000386 ddjvu_format_release(format);
387
388
389 if (type == DDJVU_PAGETYPE_BITONAL) {
390 /* */
391#if DEBUG
392 printf("%s: expanding BITONAL page/image\n", __FUNCTION__);
393#endif
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 {
cristyc82a27b2011-10-21 01:07:16 +0000398 Quantum * o = QueueAuthenticPixels(image,0,y,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000399 if (o == (Quantum *) NULL)
cristy3ed852e2009-09-05 21:47:34 +0000400 break;
cristy3ed852e2009-09-05 21:47:34 +0000401 bit=0;
402 byte=0;
403
404 /* fixme: the non-aligned, last =<7 bits ! that's ok!!!*/
cristybb503372010-05-27 20:51:26 +0000405 for (x= 0; x < (ssize_t) image->columns; x++)
cristy3ed852e2009-09-05 21:47:34 +0000406 {
cristybb503372010-05-27 20:51:26 +0000407 if (bit == 0) byte= (size_t) q[(y * stride) + (x / 8)];
cristy3ed852e2009-09-05 21:47:34 +0000408
cristy4c08aed2011-07-01 19:47:50 +0000409 SetPixelIndex(image,(Quantum) (((byte & 0x01) != 0) ? 0x00 : 0x01),o);
cristy3ed852e2009-09-05 21:47:34 +0000410 bit++;
411 if (bit == 8)
412 bit=0;
413 byte>>=1;
cristyed231572011-07-14 02:18:59 +0000414 o+=GetPixelChannels(image);
cristy3ed852e2009-09-05 21:47:34 +0000415 }
cristyc82a27b2011-10-21 01:07:16 +0000416 if (SyncAuthenticPixels(image,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000417 break;
418 }
cristyf500a7b2010-07-01 18:23:49 +0000419 if (!image->ping)
cristyc82a27b2011-10-21 01:07:16 +0000420 SyncImage(image,exception);
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
cristy4c08aed2011-07-01 19:47:50 +0000431 register Quantum *r;
cristy98a85772011-05-23 21:46:44 +0000432 unsigned char *s;
cristy3ed852e2009-09-05 21:47:34 +0000433#endif
cristy98a85772011-05-23 21:46:44 +0000434 s=q;
435 for (i = 0;i< (ssize_t) image->rows; i++)
cristy3ed852e2009-09-05 21:47:34 +0000436 {
437#if DEBUG
438 if (i % 1000 == 0) printf("%d\n",i);
439#endif
cristyc82a27b2011-10-21 01:07:16 +0000440 r = QueueAuthenticPixels(image,0,i,image->columns,1,exception);
cristy4c08aed2011-07-01 19:47:50 +0000441 if (r == (Quantum *) NULL)
cristy9561fec2011-03-07 13:18:21 +0000442 break;
cristy98a85772011-05-23 21:46:44 +0000443 for (x=0; x < (ssize_t) image->columns; x++)
444 {
cristy4c08aed2011-07-01 19:47:50 +0000445 SetPixelRed(image,ScaleCharToQuantum(*s++),r);
446 SetPixelGreen(image,ScaleCharToQuantum(*s++),r);
447 SetPixelBlue(image,ScaleCharToQuantum(*s++),r);
cristyed231572011-07-14 02:18:59 +0000448 r+=GetPixelChannels(image);
cristy98a85772011-05-23 21:46:44 +0000449 }
cristy3ed852e2009-09-05 21:47:34 +0000450
cristyc82a27b2011-10-21 01:07:16 +0000451 SyncAuthenticPixels(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000452 }
453 }
454 q=(unsigned char *) RelinquishMagickMemory(q);
455}
456
457
458#if defined(MAGICKCORE_DJVU_DELEGATE)
459
cristy95236b52009-12-30 21:56:45 +0000460#if 0
cristy3ed852e2009-09-05 21:47:34 +0000461static int
462get_page_line(LoadContext *lc, int row, QuantumInfo* quantum_info)
463{
464 ddjvu_format_t
465 *format;
466
467 int
468 ret;
469
470 size_t
471 stride;
472
473 unsigned char
474 *q;
475
476 ddjvu_rect_t rect, pagerect;
477 rect.x = 0;
478 rect.y = row;
479 rect.w = lc->image->columns; /* /10 */
480 rect.h = 1; /* /10 */
481
482 pagerect.x = 0;
483 pagerect.y = 0;
484 pagerect.w = lc->image->columns;
485 pagerect.h = lc->image->rows;
486
487
488 format = ddjvu_format_create(
489#if RGB
490 DDJVU_FORMAT_RGB24
491#else
492 DDJVU_FORMAT_GREY8
493#endif
494 ,
495 0, NULL);
496 ddjvu_format_set_row_order(format, 1);
497 ddjvu_format_set_y_direction(format, 1);
498
499 stride=1;
500#if RGB
501 stride=3;
502#endif
503 q = (unsigned char *) AcquireQuantumMemory(lc->image->columns,stride);
504
505 ret = ddjvu_page_render(lc->page,
506 DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
507 &pagerect,
508 &rect, /* mmc: ?? */
509 format,
510 pagerect.w * 3, /* ?? */
511 (char*)q);
512
513 ImportQuantumPixels(lc->image,
514 (CacheView *) NULL,
515 quantum_info,
516#if RGB
517 RGBQuantum
518#else
519 GrayQuantum
520#endif
521 ,q,&lc->image->exception);
522 q=(unsigned char *) RelinquishMagickMemory(q);
523 ddjvu_format_release(format);
524 return ret;
525}
526#endif
cristy95236b52009-12-30 21:56:45 +0000527#endif
cristy3ed852e2009-09-05 21:47:34 +0000528
529/*
530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
531% %
532% %
533% %
534% R e a d O n e D J V U I m a g e %
535% %
536% %
537% %
538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539%
540% ReadOneDJVUImage() reads a Portable Network Graphics (DJVU) image file
541% (minus the 8-byte signature) and returns it. It allocates the memory
542% necessary for the new Image structure and returns a pointer to the new
543% image.
544%
545% The format of the ReadOneDJVUImage method is:
546%
547% Image *ReadOneDJVUImage(MngInfo *mng_info, const ImageInfo *image_info,
548% ExceptionInfo *exception)
549%
550% A description of each parameter follows:
551%
552% o mng_info: Specifies a pointer to a MngInfo structure.
553%
554% o image_info: the image info.
555%
556% o exception: return any errors or warnings in this structure.
557%
558*/
559
560static inline double MagickMax(const double x,const double y)
561{
562 if (x > y)
563 return(x);
564 return(y);
565}
566
567static Image *ReadOneDJVUImage(LoadContext* lc,const int pagenum,
568 const ImageInfo *image_info,ExceptionInfo *exception)
569{
570 ddjvu_page_type_t
571 type;
572
573 ddjvu_pageinfo_t info;
cristy3ed852e2009-09-05 21:47:34 +0000574 ddjvu_message_t *message;
575 Image *image;
576 int logging;
577 int tag;
578
579 /* so, we know that the page is there! Get its dimension, and */
580
581 /* Read one DJVU image */
582 image = lc->image;
583
cristy4c08aed2011-07-01 19:47:50 +0000584 /* register Quantum *q; */
cristy3ed852e2009-09-05 21:47:34 +0000585
586 logging=LogMagickEvent(CoderEvent,GetMagickModule(), " enter ReadOneDJVUImage()");
cristyc8d21992011-03-09 13:17:20 +0000587 (void) logging;
cristy3ed852e2009-09-05 21:47:34 +0000588
589#if DEBUG
590 printf("==== Loading the page %d\n", pagenum);
591#endif
592 lc->page = ddjvu_page_create_by_pageno(lc->document, pagenum); /* 0? */
593
594 /* pump data untill the page is ready for rendering. */
595 tag=(-1);
596 do {
597 while ((message = ddjvu_message_peek(lc->context)))
598 {
599 tag=process_message(message);
600 if (tag == 0) break;
601 ddjvu_message_pop(lc->context);
602 }
603 /* fixme: maybe exit? */
604 /* if (lc->error) break; */
605
606 message = pump_data_until_message(lc,image);
607 if (message)
608 do {
609 tag=process_message(message);
610 if (tag == 0) break;
611 ddjvu_message_pop(lc->context);
612 } while ((message = ddjvu_message_peek(lc->context)));
613 } while (!ddjvu_page_decoding_done(lc->page));
614
615 ddjvu_document_get_pageinfo(lc->document, pagenum, &info);
616
cristy2a11bef2011-10-28 18:33:11 +0000617 image->resolution.x = (float) info.dpi;
618 image->resolution.y =(float) info.dpi;
cristy3ed852e2009-09-05 21:47:34 +0000619 if (image_info->density != (char *) NULL)
620 {
621 int
622 flags;
623
624 GeometryInfo
625 geometry_info;
626
627 /*
628 Set rendering resolution.
629 */
630 flags=ParseGeometry(image_info->density,&geometry_info);
cristy2a11bef2011-10-28 18:33:11 +0000631 image->resolution.x=geometry_info.rho;
632 image->resolution.y=geometry_info.sigma;
cristy3ed852e2009-09-05 21:47:34 +0000633 if ((flags & SigmaValue) == 0)
cristy2a11bef2011-10-28 18:33:11 +0000634 image->resolution.y=image->resolution.x;
635 info.width*=image->resolution.x/info.dpi;
636 info.height*=image->resolution.y/info.dpi;
637 info.dpi=(ssize_t) MagickMax(image->resolution.x,image->resolution.y);
cristy3ed852e2009-09-05 21:47:34 +0000638 }
639 type = ddjvu_page_get_type(lc->page);
640
641 /* double -> float! */
642 /* image->gamma = (float)ddjvu_page_get_gamma(lc->page); */
643
644 /* mmc: set image->depth */
645 /* mmc: This from the type */
646
cristybb503372010-05-27 20:51:26 +0000647 image->columns=(size_t) info.width;
648 image->rows=(size_t) info.height;
cristy3ed852e2009-09-05 21:47:34 +0000649
650 /* mmc: bitonal should be palettized, and compressed! */
651 if (type == DDJVU_PAGETYPE_BITONAL){
652 image->colorspace = GRAYColorspace;
653 image->storage_class = PseudoClass;
654 image->depth = 8UL; /* i only support that? */
655 image->colors= 2;
cristy018f07f2011-09-04 21:15:19 +0000656 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000657 ThrowReaderException(ResourceLimitError,
658 "MemoryAllocationFailed");
659 } else {
660 image->colorspace = RGBColorspace;
661 image->storage_class = DirectClass;
662 /* fixme: MAGICKCORE_QUANTUM_DEPTH ?*/
663 image->depth = 8UL; /* i only support that? */
664
cristyb0a657e2012-08-29 00:45:37 +0000665 image->alpha_trait = BlendPixelTrait;
cristy3ed852e2009-09-05 21:47:34 +0000666 /* is this useful? */
667 }
668#if DEBUG
cristye8c25f92010-06-03 00:53:06 +0000669 printf("now filling %.20g x %.20g\n",(double) image->columns,(double)
670 image->rows);
cristy3ed852e2009-09-05 21:47:34 +0000671#endif
672
673
674#if 1 /* per_line */
cristy3ed852e2009-09-05 21:47:34 +0000675
676 /* q = QueueAuthenticPixels(image,0,0,image->columns,image->rows); */
cristyc82a27b2011-10-21 01:07:16 +0000677 get_page_image(lc, lc->page, 0, 0, info.width, info.height, image_info,
678 exception);
cristy3ed852e2009-09-05 21:47:34 +0000679#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)
cristyea1a8aa2011-10-20 13:24:06 +0000698 SyncImage(image,exception);
cristy3ed852e2009-09-05 21:47:34 +0000699 /* mmc: ??? Convert PNM pixels to runlength-encoded MIFF packets. */
700 /* image->colors = */
701
702 /* how is the line padding / stride? */
703
704 if (lc->page) {
705 ddjvu_page_release(lc->page);
706 lc->page = NULL;
707 }
708
709 /* image->page.y=mng_info->y_off[mng_info->object_id]; */
710 if (tag == 0)
711 image=DestroyImage(image);
712 return image;
713 /* end of reading one DJVU page/image */
714}
715
716#if 0
717/* palette */
cristy018f07f2011-09-04 21:15:19 +0000718 if (AcquireImageColormap(image,2,exception) == MagickFalse)
cristy3ed852e2009-09-05 21:47:34 +0000719 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
720 /*
721 Monochrome colormap. mmc: this the default!
722 */
723 image->colormap[0].red=QuantumRange;
724 image->colormap[0].green=QuantumRange;
725 image->colormap[0].blue=QuantumRange;
726 image->colormap[1].red=0;
727 image->colormap[1].green=0;
728 image->colormap[1].blue=0;
729#endif
730
731static void djvu_close_lc(LoadContext* lc)
732{
733 if (lc->document)
734 ddjvu_document_release(lc->document);
735 if (lc->context)
736 ddjvu_context_release(lc->context);
737 if (lc->page)
738 ddjvu_page_release(lc->page);
739 RelinquishMagickMemory(lc);
740}
741
742static Image *ReadDJVUImage(const ImageInfo *image_info,
743 ExceptionInfo *exception)
744{
745 const char
746 *url;
747
748 ddjvu_message_t
749 *message;
750
751 Image
752 *image,
753 *images;
754
755 int
756 logging,
757 use_cache;
758
759 LoadContext
760 *lc;
761
762 MagickBooleanType
763 status;
764
cristybb503372010-05-27 20:51:26 +0000765 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000766 i;
767
768 /*
769 * Open image file.
770 */
771 assert(image_info != (const ImageInfo *) NULL);
772 assert(image_info->signature == MagickSignature);
773
774
775 if (image_info->debug != MagickFalse)
776 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename);
777
778 assert(exception != (ExceptionInfo *) NULL);
779 assert(exception->signature == MagickSignature);
780
781
782 logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadDJVUImage()");
cristy9561fec2011-03-07 13:18:21 +0000783 (void) logging;
cristy3ed852e2009-09-05 21:47:34 +0000784
cristy9950d572011-10-01 18:22:35 +0000785 image = AcquireImage(image_info,exception); /* mmc: ?? */
cristy3ed852e2009-09-05 21:47:34 +0000786
787
788 lc = (LoadContext *) NULL;
789 status = OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
790 if (status == MagickFalse)
791 ThrowReaderException(FileOpenError,"UnableToOpenFile");
792 /*
793 Verify DJVU signature.
794 */
795#if 0
796 count = ReadBlob(image,8,(unsigned char *) magic_number);
797
798 /* IsDJVU(const unsigned char *magick,const size_t length) */
799 if (memcmp(magic_number,"AT&TFORM",8) != 0)
800 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
801#endif
802
803
804 /*
805 * Allocate a LoadContext structure.
806 */
cristy73bd4a52010-10-05 11:24:23 +0000807 lc = (LoadContext *) AcquireMagickMemory(sizeof(*lc));
cristy3ed852e2009-09-05 21:47:34 +0000808 if (lc == NULL)
809 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
810
811
812 /*
813 * Initialize members of the MngInfo structure.
814 */
815 (void) ResetMagickMemory(lc,0,sizeof(LoadContext));
816
817 lc->image = image;
818 lc->pages = 0;
819 lc->context = ddjvu_context_create("ImageMagick djvu loader"); /* g_program_name */
820
821 ddjvu_cache_set_size(lc->context, 1); /* right? */
822 use_cache = 0;
823 /* document: here we don't have a filename, but, for the sake of generality, a FILE* ! */
cristy79565a22010-06-25 01:38:52 +0000824 url="http://www.imagemagick.org/fake.djvu";
cristy3ed852e2009-09-05 21:47:34 +0000825 lc->document = ddjvu_document_create(lc->context, url, use_cache); /* don't cache */
826 ddjvu_document_set_user_data(lc->document, lc);
827
828
829 /* now we wait the message-request for data: */
830 message = ddjvu_message_wait(lc->context);
831
832 if (message->m_any.tag != DDJVU_NEWSTREAM) {
833 /* fixme: the djvu context, document! */
834
835 ddjvu_document_release(lc->document);
836 ddjvu_context_release(lc->context);
837
838 RelinquishMagickMemory(lc);
839
840 ThrowReaderException(ResourceLimitError,"Djvu initial message: unexpected type");
841 return NULL; /* error! */
842 };
843
844 lc->streamid = message->m_newstream.streamid;
845 ddjvu_message_pop(lc->context);
846
847 message = pump_data_until_message(lc,image);
848 /* now process the messages: */
849
850
851 if (message) do {
852 process_message(message);
853 ddjvu_message_pop(lc->context);
854 } while ((message = ddjvu_message_peek(lc->context)));
855
856 /* fixme: i hope we have not read any messages pertinent(?) related to the page itself! */
857
858 while (lc->pages == 0) {
859 message = ddjvu_message_wait(lc->context);
860 process_message(message);
861 ddjvu_message_pop(lc->context);
862 }
863
864 images=NewImageList();
865 i=0;
866 if (image_info->number_scenes != 0)
867 i=image_info->scene;
cristybb503372010-05-27 20:51:26 +0000868 for ( ; i < (ssize_t) lc->pages; i++)
cristy3ed852e2009-09-05 21:47:34 +0000869 {
870 image=ReadOneDJVUImage(lc,i,image_info,exception);
871 if (image == (Image *) NULL)
872 break;
cristyc3ebda22010-06-27 17:11:57 +0000873 image->scene=i;
cristy3ed852e2009-09-05 21:47:34 +0000874 AppendImageToList(&images,CloneImageList(image,exception));
cristy3f1c1202011-12-28 16:16:24 +0000875 images->extent=GetBlobSize(image);
cristy3ed852e2009-09-05 21:47:34 +0000876 if (image_info->number_scenes != 0)
877 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
878 break;
879 }
880 djvu_close_lc(lc);
881 (void) CloseBlob(images);
882 if (image != (Image *) NULL)
883 image=DestroyImageList(image);
884
885#if 0
886 if ((image->page.width == 0) && (image->page.height == 0))
887 {
888 image->page.width = image->columns+image->page.x;
889 image->page.height = image->rows+image->page.y;
890 }
891 if (image->columns == 0 || image->rows == 0)
892 {
893 if (logging != MagickFalse)
894 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
895 "exit ReadDJVUImage() with error.");
896 ThrowReaderException(CorruptImageError,"CorruptImage");
897 }
898
899 if (logging != MagickFalse)
900 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadDJVUImage()");
901#endif
902
903
904 return(GetFirstImageInList(images));
905}
906#endif
907
908/*
909%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
910% %
911% %
912% %
913% R e g i s t e r D J V U I m a g e %
914% %
915% %
916% %
917%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
918%
919% RegisterDJVUImage() adds attributes for the DJVU image format to
920% the list of supported formats. The attributes include the image format
921% tag, a method to read and/or write the format, whether the format
922% supports the saving of more than one frame to the same file or blob,
923% whether the format supports native in-memory I/O, and a brief
924% description of the format.
925%
926% The format of the RegisterDJVUImage method is:
927%
cristybb503372010-05-27 20:51:26 +0000928% size_t RegisterDJVUImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000929%
930*/
cristybb503372010-05-27 20:51:26 +0000931ModuleExport size_t RegisterDJVUImage(void)
cristy3ed852e2009-09-05 21:47:34 +0000932{
933 char
934 version[MaxTextExtent];
935
936 MagickInfo
937 *entry;
938
939 static const char
940 *DJVUNote =
941 {
942 "See http://www.djvuzone.org/ for details about the DJVU format. The\n"
943 "DJVU 1.2 specification is available there and at\n"
944 "ftp://swrinde.nde.swri.edu/pub/djvu/documents/."
945 };
946
947 *version='\0';
948#if defined(DJVU_LIBDJVU_VER_STRING)
949 (void) ConcatenateMagickString(version,"libdjvu ",MaxTextExtent);
950 (void) ConcatenateMagickString(version,DJVU_LIBDJVU_VER_STRING,MaxTextExtent);
951#endif
952 entry=SetMagickInfo("DJVU");
953#if defined(MAGICKCORE_DJVU_DELEGATE)
954 entry->decoder=(DecodeImageHandler *) ReadDJVUImage;
955#endif
956 entry->raw=MagickTrue;
957 entry->magick=(IsImageFormatHandler *) IsDJVU;
958 entry->adjoin=MagickFalse;
959 entry->thread_support=MagickTrue;
960 entry->description=AcquireString("Déjà vu");
961 entry->module=AcquireString("DJVU");
962 if (*version != '\0')
963 entry->version=AcquireString(version);
964 entry->note=AcquireString(DJVUNote);
965 (void) RegisterMagickInfo(entry);
966 return(MagickImageCoderSignature);
967}
968
969/*
970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
971% %
972% %
973% %
974% U n r e g i s t e r D J V U I m a g e %
975% %
976% %
977% %
978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
979%
980% UnregisterDJVUImage() removes format registrations made by the
981% DJVU module from the list of supported formats.
982%
983% The format of the UnregisterDJVUImage method is:
984%
985% UnregisterDJVUImage(void)
986%
987*/
988ModuleExport void UnregisterDJVUImage(void)
989{
990 (void) UnregisterMagickInfo("DJVU");
991}