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-2019 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
189 static const char*
message_tag_name(ddjvu_message_tag_t tag)190 message_tag_name(ddjvu_message_tag_t tag)
191 {
192 static char* names[] =
193 {
194 "ERROR",
195 "INFO",
196 "NEWSTREAM",
197 "DOCINFO",
198 "PAGEINFO",
199 "RELAYOUT",
200 "REDISPLAY",
201 "CHUNK",
202 "THUMBNAIL",
203 "PROGRESS",
204 };
205 if (tag <= DDJVU_PROGRESS)
206 return names[tag];
207 else {
208 /* bark! */
209 return 0;
210 }
211 }
212 #endif
213
214 /* write out nice info on the message,
215 * and store in *user* data the info on progress.
216 * */
217 int
process_message(ddjvu_message_t * message)218 process_message(ddjvu_message_t *message)
219 {
220
221 #if 0
222 ddjvu_context_t* context= message->m_any.context;
223 #endif
224
225 if (! message)
226 return(-1);
227 #if DEBUG
228 printf("*** %s: %s.\n",__FUNCTION__, message_tag_name(message->m_any.tag));
229 #endif
230
231
232 switch (message->m_any.tag){
233 case DDJVU_DOCINFO:
234 {
235 ddjvu_document_t* document= message->m_any.document;
236 /* ddjvu_document_decoding_status is set by libdjvu! */
237 /* we have some info on the document */
238 LoadContext *lc = (LoadContext *) ddjvu_document_get_user_data(document);
239 lc->pages = ddjvu_document_get_pagenum(document);
240 #if DEBUG
241 printf("the doc has %d pages\n", ddjvu_document_get_pagenum(document));
242 #endif
243 break;
244 }
245 case DDJVU_CHUNK:
246 #if DEBUG
247 printf("the name of the chunk is: %s\n", message->m_chunk.chunkid);
248 #endif
249 break;
250
251
252 case DDJVU_RELAYOUT:
253 case DDJVU_PAGEINFO:
254 {
255 #if 0
256 ddjvu_page_t* page = message->m_any.page;
257 page_info* info = ddjvu_page_get_user_data(page);
258
259 printf("page decoding status: %d %s%s%s\n",
260 ddjvu_page_decoding_status(page),
261 status_color, status_name(ddjvu_page_decoding_status(page)), color_reset);
262
263 printf("the page LAYOUT changed: width x height: %d x %d @ %d dpi. Version %d, type %d\n",
264 // printf("page info:\n width x height: %d x %d @ %d dpi, version %d, type %d\n",
265 ddjvu_page_get_width(page),
266 ddjvu_page_get_height(page),
267 ddjvu_page_get_resolution(page),
268 ddjvu_page_get_version(page),
269 /* DDJVU_PAGETYPE_BITONAL */
270 ddjvu_page_get_type(page));
271
272 info->info = 1;
273 #endif
274 break;
275 }
276
277 case DDJVU_REDISPLAY:
278 {
279
280 #if 0
281 ddjvu_page_t* page = message->m_any.page;
282 page_info* info = ddjvu_page_get_user_data(page);
283
284 printf("the page can/should be REDISPLAYED\n");
285 info->display = 1;
286 #endif
287 break;
288 }
289
290 case DDJVU_PROGRESS:
291 #if DEBUG
292 printf("PROGRESS:\n");
293 #endif
294 break;
295 case DDJVU_ERROR:
296 printf("simply ERROR!\n message:\t%s\nfunction:\t%s(file %s)\nlineno:\t%d\n",
297 message->m_error.message,
298 message->m_error.function,
299 message->m_error.filename,
300 message->m_error.lineno);
301 break;
302 case DDJVU_INFO:
303 #if DEBUG
304 printf("INFO: %s!\n", message->m_info.message);
305 #endif
306 break;
307 default:
308 printf("unexpected\n");
309 };
310 return(message->m_any.tag);
311 }
312
313
314 #if defined(__cplusplus) || defined(c_plusplus)
315 }
316 #endif
317
318
319 #define RGB 1
320
321 /*
322 * DjVu advertised readiness to provide bitmap: So get it!
323 * we use the RGB format!
324 */
325 static void
get_page_image(LoadContext * lc,ddjvu_page_t * page,int x,int y,int w,int h,ExceptionInfo * exception)326 get_page_image(LoadContext *lc, ddjvu_page_t *page, int x, int y, int w, int h, ExceptionInfo *exception ) {
327 ddjvu_format_t
328 *format;
329
330 ddjvu_page_type_t
331 type;
332
333 Image
334 *image;
335
336 int
337 ret,
338 stride;
339
340 unsigned char
341 *q;
342
343 ddjvu_rect_t rect;
344 rect.x = x;
345 rect.y = y;
346 rect.w = (unsigned int) w; /* /10 */
347 rect.h = (unsigned int) h; /* /10 */
348
349 image = lc->image;
350 type = ddjvu_page_get_type(lc->page);
351
352 /* stride of this temporary buffer: */
353 stride = (type == DDJVU_PAGETYPE_BITONAL)?
354 (image->columns + 7)/8 : image->columns *3;
355
356 q = (unsigned char *) AcquireQuantumMemory(image->rows,stride);
357 if (q == (unsigned char *) NULL)
358 return;
359
360 format = ddjvu_format_create(
361 (type == DDJVU_PAGETYPE_BITONAL)?DDJVU_FORMAT_LSBTOMSB : DDJVU_FORMAT_RGB24,
362 /* DDJVU_FORMAT_RGB24
363 * DDJVU_FORMAT_RGBMASK32*/
364 /* DDJVU_FORMAT_RGBMASK32 */
365 0, NULL);
366
367 #if 0
368 /* fixme: ThrowReaderException is a macro, which uses `exception' variable */
369 if (format == NULL)
370 {
371 abort();
372 /* ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); */
373 }
374
375 #endif
376 ddjvu_format_set_row_order(format, 1);
377 ddjvu_format_set_y_direction(format, 1);
378
379 ret = ddjvu_page_render(page,
380 DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
381 &rect,
382 &rect, /* mmc: ?? */
383 format,
384 stride, /* ?? */
385 (char*)q);
386 (void) ret;
387 ddjvu_format_release(format);
388
389
390 if (type == DDJVU_PAGETYPE_BITONAL) {
391 /* */
392 #if DEBUG
393 printf("%s: expanding BITONAL page/image\n", __FUNCTION__);
394 #endif
395 size_t bit, byte;
396
397 for (y=0; y < (ssize_t) image->rows; y++)
398 {
399 Quantum * o = QueueAuthenticPixels(image,0,y,image->columns,1,exception);
400 if (o == (Quantum *) NULL)
401 break;
402 bit=0;
403 byte=0;
404
405 /* fixme: the non-aligned, last =<7 bits ! that's ok!!!*/
406 for (x= 0; x < (ssize_t) image->columns; x++)
407 {
408 if (bit == 0) byte= (size_t) q[(y * stride) + (x / 8)];
409
410 SetPixelIndex(image,(Quantum) (((byte & 0x01) != 0) ? 0x00 : 0x01),o);
411 bit++;
412 if (bit == 8)
413 bit=0;
414 byte>>=1;
415 o+=GetPixelChannels(image);
416 }
417 if (SyncAuthenticPixels(image,exception) == MagickFalse)
418 break;
419 }
420 if (!image->ping)
421 SyncImage(image,exception);
422 } else {
423 #if DEBUG
424 printf("%s: expanding PHOTO page/image\n", __FUNCTION__);
425 #endif
426 /* now transfer line-wise: */
427 ssize_t i;
428 #if 0
429 /* old: */
430 char* r;
431 #else
432 register Quantum *r;
433 unsigned char *s;
434 #endif
435 s=q;
436 for (i = 0;i< (ssize_t) image->rows; i++)
437 {
438 #if DEBUG
439 if (i % 1000 == 0) printf("%d\n",i);
440 #endif
441 r = QueueAuthenticPixels(image,0,i,image->columns,1,exception);
442 if (r == (Quantum *) NULL)
443 break;
444 for (x=0; x < (ssize_t) image->columns; x++)
445 {
446 SetPixelRed(image,ScaleCharToQuantum(*s++),r);
447 SetPixelGreen(image,ScaleCharToQuantum(*s++),r);
448 SetPixelBlue(image,ScaleCharToQuantum(*s++),r);
449 r+=GetPixelChannels(image);
450 }
451
452 (void) SyncAuthenticPixels(image,exception);
453 }
454 }
455 q=(unsigned char *) RelinquishMagickMemory(q);
456 }
457
458
459 #if defined(MAGICKCORE_DJVU_DELEGATE)
460
461 #if 0
462 static int
463 get_page_line(LoadContext *lc, int row, QuantumInfo* quantum_info)
464 {
465 ddjvu_format_t
466 *format;
467
468 int
469 ret;
470
471 size_t
472 stride;
473
474 unsigned char
475 *q;
476
477 ddjvu_rect_t rect, pagerect;
478 rect.x = 0;
479 rect.y = row;
480 rect.w = lc->image->columns; /* /10 */
481 rect.h = 1; /* /10 */
482
483 pagerect.x = 0;
484 pagerect.y = 0;
485 pagerect.w = lc->image->columns;
486 pagerect.h = lc->image->rows;
487
488
489 format = ddjvu_format_create(
490 #if RGB
491 DDJVU_FORMAT_RGB24
492 #else
493 DDJVU_FORMAT_GREY8
494 #endif
495 ,
496 0, NULL);
497 ddjvu_format_set_row_order(format, 1);
498 ddjvu_format_set_y_direction(format, 1);
499
500 stride=1;
501 #if RGB
502 stride=3;
503 #endif
504 q = (unsigned char *) AcquireQuantumMemory(lc->image->columns,stride);
505
506 ret = ddjvu_page_render(lc->page,
507 DDJVU_RENDER_COLOR, /* ddjvu_render_mode_t */
508 &pagerect,
509 &rect, /* mmc: ?? */
510 format,
511 pagerect.w * 3, /* ?? */
512 (char*)q);
513
514 ImportQuantumPixels(lc->image,
515 (CacheView *) NULL,
516 quantum_info,
517 #if RGB
518 RGBQuantum
519 #else
520 GrayQuantum
521 #endif
522 ,q,&lc->image->exception);
523 q=(unsigned char *) RelinquishMagickMemory(q);
524 ddjvu_format_release(format);
525 return ret;
526 }
527 #endif
528 #endif
529
530 /*
531 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
532 % %
533 % %
534 % %
535 % R e a d O n e D J V U I m a g e %
536 % %
537 % %
538 % %
539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
540 %
541 % ReadOneDJVUImage() reads a Portable Network Graphics (DJVU) image file
542 % (minus the 8-byte signature) and returns it. It allocates the memory
543 % necessary for the new Image structure and returns a pointer to the new
544 % image.
545 %
546 % The format of the ReadOneDJVUImage method is:
547 %
548 % Image *ReadOneDJVUImage(MngInfo *mng_info, const ImageInfo *image_info,
549 % ExceptionInfo *exception)
550 %
551 % A description of each parameter follows:
552 %
553 % o mng_info: Specifies a pointer to a MngInfo structure.
554 %
555 % o image_info: the image info.
556 %
557 % o exception: return any errors or warnings in this structure.
558 %
559 */
560
ReadOneDJVUImage(LoadContext * lc,const int pagenum,const ImageInfo * image_info,ExceptionInfo * exception)561 static Image *ReadOneDJVUImage(LoadContext* lc,const int pagenum,
562 const ImageInfo *image_info,ExceptionInfo *exception)
563 {
564 ddjvu_page_type_t
565 type;
566
567 ddjvu_pageinfo_t info;
568 ddjvu_message_t *message;
569 Image *image;
570 int logging;
571 int tag;
572 MagickBooleanType status;
573
574 /* so, we know that the page is there! Get its dimension, and */
575
576 /* Read one DJVU image */
577 image = lc->image;
578
579 /* register Quantum *q; */
580
581 logging=LogMagickEvent(CoderEvent,GetMagickModule(), " enter ReadOneDJVUImage()");
582 (void) logging;
583
584 #if DEBUG
585 printf("==== Loading the page %d\n", pagenum);
586 #endif
587 lc->page = ddjvu_page_create_by_pageno(lc->document, pagenum); /* 0? */
588
589 /* pump data untill the page is ready for rendering. */
590 tag=(-1);
591 do {
592 while ((message = ddjvu_message_peek(lc->context)))
593 {
594 tag=process_message(message);
595 if (tag == 0) break;
596 ddjvu_message_pop(lc->context);
597 }
598 /* fixme: maybe exit? */
599 /* if (lc->error) break; */
600
601 message = pump_data_until_message(lc,image);
602 if (message)
603 do {
604 tag=process_message(message);
605 if (tag == 0) break;
606 ddjvu_message_pop(lc->context);
607 } while ((message = ddjvu_message_peek(lc->context)));
608 if (tag == 0) break;
609 } while (!ddjvu_page_decoding_done(lc->page));
610
611 ddjvu_document_get_pageinfo(lc->document, pagenum, &info);
612
613 image->resolution.x = (float) info.dpi;
614 image->resolution.y =(float) info.dpi;
615 if (image_info->density != (char *) NULL)
616 {
617 int
618 flags;
619
620 GeometryInfo
621 geometry_info;
622
623 /*
624 Set rendering resolution.
625 */
626 flags=ParseGeometry(image_info->density,&geometry_info);
627 image->resolution.x=geometry_info.rho;
628 image->resolution.y=geometry_info.sigma;
629 if ((flags & SigmaValue) == 0)
630 image->resolution.y=image->resolution.x;
631 info.width*=image->resolution.x/info.dpi;
632 info.height*=image->resolution.y/info.dpi;
633 info.dpi=(ssize_t) MagickMax(image->resolution.x,image->resolution.y);
634 }
635 type = ddjvu_page_get_type(lc->page);
636
637 /* double -> float! */
638 /* image->gamma = (float)ddjvu_page_get_gamma(lc->page); */
639
640 /* mmc: set image->depth */
641 /* mmc: This from the type */
642
643 image->columns=(size_t) info.width;
644 image->rows=(size_t) info.height;
645
646 /* mmc: bitonal should be palettized, and compressed! */
647 if (type == DDJVU_PAGETYPE_BITONAL){
648 image->colorspace = GRAYColorspace;
649 image->storage_class = PseudoClass;
650 image->depth = 8UL; /* i only support that? */
651 image->colors= 2;
652 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
653 ThrowReaderException(ResourceLimitError,
654 "MemoryAllocationFailed");
655 } else {
656 image->colorspace = RGBColorspace;
657 image->storage_class = DirectClass;
658 /* fixme: MAGICKCORE_QUANTUM_DEPTH ?*/
659 image->depth = 8UL; /* i only support that? */
660
661 image->alpha_trait = BlendPixelTrait;
662 /* is this useful? */
663 }
664 status=SetImageExtent(image,image->columns,image->rows,exception);
665 if (status == MagickFalse)
666 return(DestroyImageList(image));
667 #if DEBUG
668 printf("now filling %.20g x %.20g\n",(double) image->columns,(double)
669 image->rows);
670 #endif
671
672
673 #if 1 /* per_line */
674
675 /* q = QueueAuthenticPixels(image,0,0,image->columns,image->rows); */
676 get_page_image(lc, lc->page, 0, 0, info.width, info.height, exception);
677 #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
691 printf("END: finished filling %.20g x %.20g\n",(double) image->columns,
692 (double) image->rows);
693 #endif
694
695 if (!image->ping)
696 SyncImage(image,exception);
697 /* 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 */
716 if (AcquireImageColormap(image,2,exception) == MagickFalse)
717 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
djvu_close_lc(LoadContext * lc)729 static 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
ReadDJVUImage(const ImageInfo * image_info,ExceptionInfo * exception)740 static 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
763 register ssize_t
764 i;
765
766 /*
767 * Open image file.
768 */
769 assert(image_info != (const ImageInfo *) NULL);
770 assert(image_info->signature == MagickCoreSignature);
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 == MagickCoreSignature);
778
779
780 logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadDJVUImage()");
781 (void) logging;
782
783 image = AcquireImage(image_info,exception); /* mmc: ?? */
784
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 */
805 lc = (LoadContext *) AcquireMagickMemory(sizeof(*lc));
806 if (lc == NULL)
807 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
808
809
810 /*
811 * Initialize members of the MngInfo structure.
812 */
813 (void) memset(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* ! */
822 url="https://imagemagick.org/fake.djvu";
823 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;
866 for ( ; i < (ssize_t) lc->pages; i++)
867 {
868 image=ReadOneDJVUImage(lc,i,image_info,exception);
869 if (image == (Image *) NULL)
870 break;
871 image->scene=i;
872 AppendImageToList(&images,CloneImageList(image,exception));
873 images->extent=GetBlobSize(image);
874 if (image_info->number_scenes != 0)
875 if (image->scene >= (image_info->scene+image_info->number_scenes-1))
876 break;
877 }
878 djvu_close_lc(lc);
879 if (images != (Image *) NULL)
880 (void) CloseBlob(images);
881 if (image != (Image *) NULL)
882 image=DestroyImageList(image);
883
884 #if 0
885 if ((image->page.width == 0) && (image->page.height == 0))
886 {
887 image->page.width = image->columns+image->page.x;
888 image->page.height = image->rows+image->page.y;
889 }
890 if (image->columns == 0 || image->rows == 0)
891 {
892 if (logging != MagickFalse)
893 (void) LogMagickEvent(CoderEvent,GetMagickModule(),
894 "exit ReadDJVUImage() with error.");
895 ThrowReaderException(CorruptImageError,"CorruptImage");
896 }
897
898 if (logging != MagickFalse)
899 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadDJVUImage()");
900 #endif
901
902
903 return(GetFirstImageInList(images));
904 }
905 #endif
906
907 /*
908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
909 % %
910 % %
911 % %
912 % R e g i s t e r D J V U I m a g e %
913 % %
914 % %
915 % %
916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
917 %
918 % RegisterDJVUImage() adds attributes for the DJVU image format to
919 % the list of supported formats. The attributes include the image format
920 % tag, a method to read and/or write the format, whether the format
921 % supports the saving of more than one frame to the same file or blob,
922 % whether the format supports native in-memory I/O, and a brief
923 % description of the format.
924 %
925 % The format of the RegisterDJVUImage method is:
926 %
927 % size_t RegisterDJVUImage(void)
928 %
929 */
RegisterDJVUImage(void)930 ModuleExport size_t RegisterDJVUImage(void)
931 {
932 char
933 version[MagickPathExtent];
934
935 MagickInfo
936 *entry;
937
938 static const char
939 *DJVUNote =
940 {
941 "See http://www.djvuzone.org/ for details about the DJVU format. The\n"
942 "DJVU 1.2 specification is available there and at\n"
943 "ftp://swrinde.nde.swri.edu/pub/djvu/documents/."
944 };
945
946 *version='\0';
947 #if defined(DJVU_LIBDJVU_VER_STRING)
948 (void) ConcatenateMagickString(version,"libdjvu ",MagickPathExtent);
949 (void) ConcatenateMagickString(version,DJVU_LIBDJVU_VER_STRING,MagickPathExtent);
950 #endif
951 entry=AcquireMagickInfo("DJVU","DJVU","Deja vu");
952 #if defined(MAGICKCORE_DJVU_DELEGATE)
953 entry->decoder=(DecodeImageHandler *) ReadDJVUImage;
954 #endif
955 entry->magick=(IsImageFormatHandler *) IsDJVU;
956 entry->flags|=CoderRawSupportFlag;
957 entry->flags^=CoderAdjoinFlag;
958 if (*version != '\0')
959 entry->version=AcquireString(version);
960 entry->note=AcquireString(DJVUNote);
961 (void) RegisterMagickInfo(entry);
962 return(MagickImageCoderSignature);
963 }
964
965 /*
966 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
967 % %
968 % %
969 % %
970 % U n r e g i s t e r D J V U I m a g e %
971 % %
972 % %
973 % %
974 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
975 %
976 % UnregisterDJVUImage() removes format registrations made by the
977 % DJVU module from the list of supported formats.
978 %
979 % The format of the UnregisterDJVUImage method is:
980 %
981 % UnregisterDJVUImage(void)
982 %
983 */
UnregisterDJVUImage(void)984 ModuleExport void UnregisterDJVUImage(void)
985 {
986 (void) UnregisterMagickInfo("DJVU");
987 }
988