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