1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % DDDD J V V U U %
7 % D D J V V U U %
8 % D D J V V U U %
9 % D D J J V V U U %
10 % DDDD JJJ V UUU %
11 % %
12 % %
13 % Read DjVu Images. %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #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/image-private.h"
51 #include "MagickCore/list.h"
52 #include "MagickCore/magick.h"
53 #include "MagickCore/memory_.h"
54 #include "MagickCore/monitor.h"
55 #include "MagickCore/monitor-private.h"
56 #include "MagickCore/pixel-accessor.h"
57 #include "MagickCore/quantum-private.h"
58 #include "MagickCore/static.h"
59 #include "MagickCore/string_.h"
60 #include "MagickCore/module.h"
61 #if defined(MAGICKCORE_DJVU_DELEGATE)
62 #include <libdjvu/ddjvuapi.h>
63 #endif
64
65 /*
66 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67 % %
68 % %
69 % %
70 % I s D J V U %
71 % %
72 % %
73 % %
74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75 %
76 % IsDJVU() returns MagickTrue if the image format type, identified by the
77 % magick string, is DJVU.
78 %
79 % The format of the IsDJVU method is:
80 %
81 % MagickBooleanType IsDJVU(const unsigned char *magick,const size_t length)
82 %
83 % A description of each parameter follows:
84 %
85 % o magick: compare image format pattern against these bytes.
86 %
87 % o length: Specifies the length of the magick string.
88 %
89 */
IsDJVU(const unsigned char * magick,const size_t length)90 static MagickBooleanType IsDJVU(const unsigned char *magick,const size_t length)
91 {
92 if (length < 8)
93 return(MagickFalse);
94 if (memcmp(magick,"AT&TFORM",8) == 0)
95 return(MagickTrue);
96 return(MagickFalse);
97 }
98
99 #if defined(MAGICKCORE_DJVU_DELEGATE)
100 /*
101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
102 % %
103 % %
104 % %
105 % R e a d D J V U I m a g e %
106 % %
107 % %
108 % %
109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110 %
111 % ReadDJVUImage() reads DJVU image and returns it. It allocates the memory
112 % necessary for the new Image structure and returns a pointer to the new
113 % image or set of images.
114 %
115 % The format of the ReadDJVUImage method is:
116 %
117 % Image *ReadDJVUImage(const ImageInfo *image_info,
118 % ExceptionInfo *exception)
119 %
120 % A description of each parameter follows:
121 %
122 % o image_info: the image info.
123 %
124 % o exception: return any errors or warnings in this structure.
125 %
126 */
127
128 #if defined(__cplusplus) || defined(c_plusplus)
129 extern "C" {
130 #endif
131
132 typedef struct _LoadContext
133 LoadContext;
134
135 struct _LoadContext
136 {
137 ddjvu_context_t* context;
138 ddjvu_document_t *document;
139 ddjvu_page_t *page;
140 int streamid;
141 int pages;
142 Image *image;
143 };
144
145 #define BLOCKSIZE 65536
146 #if 0
147 static void
148 pump_data(Image *image, LoadContext* lc)
149 {
150 int blocksize = BLOCKSIZE;
151 char data[BLOCKSIZE];
152 int size;
153
154 /* i might check for a condition! */
155 while ((size = (size_t) ReadBlob(image,(size_t) blocksize,data)) == blocksize) {
156 ddjvu_stream_write(lc->document, lc->streamid, data, size);
157 }
158 if (size)
159 ddjvu_stream_write(lc->document, lc->streamid, data, size);
160 ddjvu_stream_close(lc->document, lc->streamid, 0);
161 }
162 #endif
163
164 /* returns NULL only after all is delivered! */
165 static ddjvu_message_t*
pump_data_until_message(LoadContext * lc,Image * image)166 pump_data_until_message(LoadContext *lc,Image *image) /* ddjvu_context_t *context, type ddjvu_document_type_t */
167 {
168 size_t blocksize = BLOCKSIZE;
169 unsigned char data[BLOCKSIZE];
170 size_t size;
171 ddjvu_message_t *message;
172
173 /* i might check for a condition! */
174 size=0;
175 while (!(message = ddjvu_message_peek(lc->context))
176 && (size = (size_t) ReadBlob(image,(size_t) blocksize,data)) == blocksize) {
177 ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
178 }
179 if (message)
180 return message;
181 if (size)
182 ddjvu_stream_write(lc->document, lc->streamid, (char *) data, size);
183 ddjvu_stream_close(lc->document, lc->streamid, 0);
184 return NULL;
185 }
186 #define DEBUG 0
187
188 #if DEBUG
message_tag_name(ddjvu_message_tag_t tag)189 static const char *message_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 * */
216 int
process_message(ddjvu_message_t * message)217 process_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 */
324 static void
get_page_image(LoadContext * lc,ddjvu_page_t * page,int x,int y,int w,int h,ExceptionInfo * exception)325 get_page_image(LoadContext *lc, ddjvu_page_t *page, int x, int y, int w, int h, ExceptionInfo *exception ) {
326 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)?
353 (image->columns + 7)/8 : image->columns *3;
354
355 q = (unsigned char *) AcquireQuantumMemory(image->rows,stride);
356 if (q == (unsigned char *) NULL)
357 return;
358
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);
385 (void) ret;
386 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
394 size_t bit, byte;
395
396 for (y=0; y < (ssize_t) image->rows; y++)
397 {
398 Quantum * o = QueueAuthenticPixels(image,0,y,image->columns,1,exception);
399 if (o == (Quantum *) NULL)
400 break;
401 bit=0;
402 byte=0;
403
404 /* fixme: the non-aligned, last =<7 bits ! that's ok!!!*/
405 for (x= 0; x < (ssize_t) image->columns; x++)
406 {
407 if (bit == 0) byte= (size_t) q[(y * stride) + (x / 8)];
408
409 SetPixelIndex(image,(Quantum) (((byte & 0x01) != 0) ? 0x00 : 0x01),o);
410 bit++;
411 if (bit == 8)
412 bit=0;
413 byte>>=1;
414 o+=GetPixelChannels(image);
415 }
416 if (SyncAuthenticPixels(image,exception) == MagickFalse)
417 break;
418 }
419 if (!image->ping)
420 SyncImage(image,exception);
421 } else {
422 #if DEBUG
423 printf("%s: expanding PHOTO page/image\n", __FUNCTION__);
424 #endif
425 /* now transfer line-wise: */
426 ssize_t i;
427 #if 0
428 /* old: */
429 char* r;
430 #else
431 Quantum *r;
432 unsigned char *s;
433 #endif
434 s=q;
435 for (i = 0;i< (ssize_t) image->rows; i++)
436 {
437 #if DEBUG
438 if (i % 1000 == 0) printf("%d\n",i);
439 #endif
440 r = QueueAuthenticPixels(image,0,i,image->columns,1,exception);
441 if (r == (Quantum *) NULL)
442 break;
443 for (x=0; x < (ssize_t) image->columns; x++)
444 {
445 SetPixelRed(image,ScaleCharToQuantum(*s++),r);
446 SetPixelGreen(image,ScaleCharToQuantum(*s++),r);
447 SetPixelBlue(image,ScaleCharToQuantum(*s++),r);
448 r+=GetPixelChannels(image);
449 }
450
451 (void) SyncAuthenticPixels(image,exception);
452 }
453 }
454 q=(unsigned char *) RelinquishMagickMemory(q);
455 }
456
457
458 #if defined(MAGICKCORE_DJVU_DELEGATE)
459
460 #if 0
461 static int
462 get_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
527 #endif
528
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
ReadOneDJVUImage(LoadContext * lc,const int pagenum,const ImageInfo * image_info,ExceptionInfo * exception)560 static Image *ReadOneDJVUImage(LoadContext* lc,const int pagenum,
561 const ImageInfo *image_info,ExceptionInfo *exception)
562 {
563 ddjvu_page_type_t
564 type;
565
566 ddjvu_pageinfo_t info;
567 ddjvu_message_t *message;
568 Image *image;
569 int logging;
570 int tag;
571 MagickBooleanType status;
572
573 /* so, we know that the page is there! Get its dimension, and */
574
575 /* Read one DJVU image */
576 image = lc->image;
577
578 /* Quantum *q; */
579
580 logging=LogMagickEvent(CoderEvent,GetMagickModule(), " enter ReadOneDJVUImage()");
581 (void) logging;
582
583 #if DEBUG
584 printf("==== Loading the page %d\n", pagenum);
585 #endif
586 lc->page = ddjvu_page_create_by_pageno(lc->document, pagenum); /* 0? */
587
588 /* pump data untill the page is ready for rendering. */
589 tag=(-1);
590 do {
591 while ((message = ddjvu_message_peek(lc->context)))
592 {
593 tag=process_message(message);
594 if (tag == 0) break;
595 ddjvu_message_pop(lc->context);
596 }
597 /* fixme: maybe exit? */
598 /* if (lc->error) break; */
599
600 message = pump_data_until_message(lc,image);
601 if (message)
602 do {
603 tag=process_message(message);
604 if (tag == 0) break;
605 ddjvu_message_pop(lc->context);
606 } while ((message = ddjvu_message_peek(lc->context)));
607 if (tag == 0) break;
608 } while (!ddjvu_page_decoding_done(lc->page));
609
610 ddjvu_document_get_pageinfo(lc->document, pagenum, &info);
611
612 image->resolution.x = (float) info.dpi;
613 image->resolution.y =(float) info.dpi;
614 if (image_info->density != (char *) NULL)
615 {
616 int
617 flags;
618
619 GeometryInfo
620 geometry_info;
621
622 /*
623 Set rendering resolution.
624 */
625 flags=ParseGeometry(image_info->density,&geometry_info);
626 image->resolution.x=geometry_info.rho;
627 image->resolution.y=geometry_info.sigma;
628 if ((flags & SigmaValue) == 0)
629 image->resolution.y=image->resolution.x;
630 info.width*=image->resolution.x/info.dpi;
631 info.height*=image->resolution.y/info.dpi;
632 info.dpi=(ssize_t) MagickMax(image->resolution.x,image->resolution.y);
633 }
634 type = ddjvu_page_get_type(lc->page);
635
636 /* double -> float! */
637 /* image->gamma = (float)ddjvu_page_get_gamma(lc->page); */
638
639 /* mmc: set image->depth */
640 /* mmc: This from the type */
641
642 image->columns=(size_t) info.width;
643 image->rows=(size_t) info.height;
644
645 /* mmc: bitonal should be palettized, and compressed! */
646 if (type == DDJVU_PAGETYPE_BITONAL){
647 image->colorspace = GRAYColorspace;
648 image->storage_class = PseudoClass;
649 image->depth = 8UL; /* i only support that? */
650 image->colors= 2;
651 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
652 ThrowReaderException(ResourceLimitError,
653 "MemoryAllocationFailed");
654 } else {
655 image->colorspace = RGBColorspace;
656 image->storage_class = DirectClass;
657 /* fixme: MAGICKCORE_QUANTUM_DEPTH ?*/
658 image->depth = 8UL; /* i only support that? */
659
660 image->alpha_trait = BlendPixelTrait;
661 /* is this useful? */
662 }
663 status=SetImageExtent(image,image->columns,image->rows,exception);
664 if (status == MagickFalse)
665 return(DestroyImageList(image));
666 #if DEBUG
667 printf("now filling %.20g x %.20g\n",(double) image->columns,(double)
668 image->rows);
669 #endif
670
671
672 #if 1 /* per_line */
673
674 /* q = QueueAuthenticPixels(image,0,0,image->columns,image->rows); */
675 get_page_image(lc, lc->page, 0, 0, info.width, info.height, exception);
676 #else
677 int i;
678 for (i = 0;i< image->rows; i++)
679 {
680 printf("%d\n",i);
681 q = QueueAuthenticPixels(image,0,i,image->columns,1);
682 get_page_line(lc, i, quantum_info);
683 SyncAuthenticPixels(image);
684 }
685
686 #endif /* per_line */
687
688
689 #if DEBUG
690 printf("END: finished filling %.20g x %.20g\n",(double) image->columns,
691 (double) image->rows);
692 #endif
693
694 if (!image->ping)
695 SyncImage(image,exception);
696 /* mmc: ??? Convert PNM pixels to runlength-encoded MIFF packets. */
697 /* image->colors = */
698
699 /* how is the line padding / stride? */
700
701 if (lc->page) {
702 ddjvu_page_release(lc->page);
703 lc->page = NULL;
704 }
705
706 /* image->page.y=mng_info->y_off[mng_info->object_id]; */
707 if (tag == 0)
708 image=DestroyImage(image);
709 return image;
710 /* end of reading one DJVU page/image */
711 }
712
713 #if 0
714 /* palette */
715 if (AcquireImageColormap(image,2,exception) == MagickFalse)
716 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
717 /*
718 Monochrome colormap. mmc: this the default!
719 */
720 image->colormap[0].red=QuantumRange;
721 image->colormap[0].green=QuantumRange;
722 image->colormap[0].blue=QuantumRange;
723 image->colormap[1].red=0;
724 image->colormap[1].green=0;
725 image->colormap[1].blue=0;
726 #endif
727
djvu_close_lc(LoadContext * lc)728 static void djvu_close_lc(LoadContext* lc)
729 {
730 if (lc->document)
731 ddjvu_document_release(lc->document);
732 if (lc->context)
733 ddjvu_context_release(lc->context);
734 if (lc->page)
735 ddjvu_page_release(lc->page);
736 RelinquishMagickMemory(lc);
737 }
738
ReadDJVUImage(const ImageInfo * image_info,ExceptionInfo * exception)739 static Image *ReadDJVUImage(const ImageInfo *image_info,
740 ExceptionInfo *exception)
741 {
742 const char
743 *url;
744
745 ddjvu_message_t
746 *message;
747
748 Image
749 *image,
750 *images;
751
752 int
753 logging,
754 use_cache;
755
756 LoadContext
757 *lc;
758
759 MagickBooleanType
760 status;
761
762 ssize_t
763 i;
764
765 /*
766 * Open image file.
767 */
768 assert(image_info != (const ImageInfo *) NULL);
769 assert(image_info->signature == MagickCoreSignature);
770
771
772 if (image_info->debug != MagickFalse)
773 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", image_info->filename);
774
775 assert(exception != (ExceptionInfo *) NULL);
776 assert(exception->signature == MagickCoreSignature);
777
778
779 logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadDJVUImage()");
780 (void) logging;
781
782 image = AcquireImage(image_info,exception); /* mmc: ?? */
783
784
785 lc = (LoadContext *) NULL;
786 status = OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
787 if (status == MagickFalse)
788 ThrowReaderException(FileOpenError,"UnableToOpenFile");
789 /*
790 Verify DJVU signature.
791 */
792 #if 0
793 count = ReadBlob(image,8,(unsigned char *) magic_number);
794
795 /* IsDJVU(const unsigned char *magick,const size_t length) */
796 if (memcmp(magic_number,"AT&TFORM",8) != 0)
797 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
798 #endif
799
800
801 /*
802 * Allocate a LoadContext structure.
803 */
804 lc = (LoadContext *) AcquireMagickMemory(sizeof(*lc));
805 if (lc == NULL)
806 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
807
808
809 /*
810 * Initialize members of the MngInfo structure.
811 */
812 (void) memset(lc,0,sizeof(LoadContext));
813
814 lc->image = image;
815 lc->pages = 0;
816 lc->context = ddjvu_context_create("ImageMagick djvu loader"); /* g_program_name */
817
818 ddjvu_cache_set_size(lc->context, 1); /* right? */
819 use_cache = 0;
820 /* document: here we don't have a filename, but, for the sake of generality, a FILE* ! */
821 url="https://imagemagick.org/fake.djvu";
822 lc->document = ddjvu_document_create(lc->context, url, use_cache); /* don't cache */
823 ddjvu_document_set_user_data(lc->document, lc);
824
825
826 /* now we wait the message-request for data: */
827 message = ddjvu_message_wait(lc->context);
828
829 if (message->m_any.tag != DDJVU_NEWSTREAM) {
830 /* fixme: the djvu context, document! */
831
832 ddjvu_document_release(lc->document);
833 ddjvu_context_release(lc->context);
834
835 RelinquishMagickMemory(lc);
836
837 ThrowReaderException(ResourceLimitError,"Djvu initial message: unexpected type");
838 return NULL; /* error! */
839 };
840
841 lc->streamid = message->m_newstream.streamid;
842 ddjvu_message_pop(lc->context);
843
844 message = pump_data_until_message(lc,image);
845 /* now process the messages: */
846
847
848 if (message) do {
849 process_message(message);
850 ddjvu_message_pop(lc->context);
851 } while ((message = ddjvu_message_peek(lc->context)));
852
853 /* fixme: i hope we have not read any messages pertinent(?) related to the page itself! */
854
855 while (lc->pages == 0) {
856 message = ddjvu_message_wait(lc->context);
857 process_message(message);
858 ddjvu_message_pop(lc->context);
859 }
860
861 images=NewImageList();
862 i=0;
863 if (image_info->number_scenes != 0)
864 i=image_info->scene;
865 for ( ; i < (ssize_t) lc->pages; i++)
866 {
867 image=ReadOneDJVUImage(lc,i,image_info,exception);
868 if (image == (Image *) NULL)
869 break;
870 image->scene=i;
871 AppendImageToList(&images,CloneImageList(image,exception));
872 images->extent=GetBlobSize(image);
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 if (images != (Image *) NULL)
879 (void) CloseBlob(images);
880 if (image != (Image *) NULL)
881 image=DestroyImageList(image);
882
883 #if 0
884 if ((image->page.width == 0) && (image->page.height == 0))
885 {
886 image->page.width = image->columns+image->page.x;
887 image->page.height = image->rows+image->page.y;
888 }
889 if (image->columns == 0 || image->rows == 0)
890 {
891 if (logging != MagickFalse)
892 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
893 "exit ReadDJVUImage() with error.");
894 ThrowReaderException(CorruptImageError,"CorruptImage");
895 }
896
897 if (logging != MagickFalse)
898 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadDJVUImage()");
899 #endif
900
901
902 return(GetFirstImageInList(images));
903 }
904 #endif
905
906 /*
907 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
908 % %
909 % %
910 % %
911 % R e g i s t e r D J V U I m a g e %
912 % %
913 % %
914 % %
915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
916 %
917 % RegisterDJVUImage() adds attributes for the DJVU image format to
918 % the list of supported formats. The attributes include the image format
919 % tag, a method to read and/or write the format, whether the format
920 % supports the saving of more than one frame to the same file or blob,
921 % whether the format supports native in-memory I/O, and a brief
922 % description of the format.
923 %
924 % The format of the RegisterDJVUImage method is:
925 %
926 % size_t RegisterDJVUImage(void)
927 %
928 */
RegisterDJVUImage(void)929 ModuleExport size_t RegisterDJVUImage(void)
930 {
931 char
932 version[MagickPathExtent];
933
934 MagickInfo
935 *entry;
936
937 static const char
938 *DJVUNote =
939 {
940 "See http://www.djvuzone.org/ for details about the DJVU format. The\n"
941 "DJVU 1.2 specification is available there and at\n"
942 "ftp://swrinde.nde.swri.edu/pub/djvu/documents/."
943 };
944
945 *version='\0';
946 #if defined(DJVU_LIBDJVU_VER_STRING)
947 (void) ConcatenateMagickString(version,"libdjvu ",MagickPathExtent);
948 (void) ConcatenateMagickString(version,DJVU_LIBDJVU_VER_STRING,MagickPathExtent);
949 #endif
950 entry=AcquireMagickInfo("DJVU","DJVU","Deja vu");
951 #if defined(MAGICKCORE_DJVU_DELEGATE)
952 entry->decoder=(DecodeImageHandler *) ReadDJVUImage;
953 #endif
954 entry->magick=(IsImageFormatHandler *) IsDJVU;
955 entry->flags|=CoderRawSupportFlag;
956 entry->flags^=CoderAdjoinFlag;
957 if (*version != '\0')
958 entry->version=AcquireString(version);
959 entry->note=AcquireString(DJVUNote);
960 (void) RegisterMagickInfo(entry);
961 return(MagickImageCoderSignature);
962 }
963
964 /*
965 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
966 % %
967 % %
968 % %
969 % U n r e g i s t e r D J V U I m a g e %
970 % %
971 % %
972 % %
973 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
974 %
975 % UnregisterDJVUImage() removes format registrations made by the
976 % DJVU module from the list of supported formats.
977 %
978 % The format of the UnregisterDJVUImage method is:
979 %
980 % UnregisterDJVUImage(void)
981 %
982 */
UnregisterDJVUImage(void)983 ModuleExport void UnregisterDJVUImage(void)
984 {
985 (void) UnregisterMagickInfo("DJVU");
986 }
987