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-2016 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 % 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 /* 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 } while (!ddjvu_page_decoding_done(lc->page)); 612 613 ddjvu_document_get_pageinfo(lc->document, pagenum, &info); 614 615 image->resolution.x = (float) info.dpi; 616 image->resolution.y =(float) info.dpi; 617 if (image_info->density != (char *) NULL) 618 { 619 int 620 flags; 621 622 GeometryInfo 623 geometry_info; 624 625 /* 626 Set rendering resolution. 627 */ 628 flags=ParseGeometry(image_info->density,&geometry_info); 629 image->resolution.x=geometry_info.rho; 630 image->resolution.y=geometry_info.sigma; 631 if ((flags & SigmaValue) == 0) 632 image->resolution.y=image->resolution.x; 633 info.width*=image->resolution.x/info.dpi; 634 info.height*=image->resolution.y/info.dpi; 635 info.dpi=(ssize_t) MagickMax(image->resolution.x,image->resolution.y); 636 } 637 type = ddjvu_page_get_type(lc->page); 638 639 /* double -> float! */ 640 /* image->gamma = (float)ddjvu_page_get_gamma(lc->page); */ 641 642 /* mmc: set image->depth */ 643 /* mmc: This from the type */ 644 645 image->columns=(size_t) info.width; 646 image->rows=(size_t) info.height; 647 648 /* mmc: bitonal should be palettized, and compressed! */ 649 if (type == DDJVU_PAGETYPE_BITONAL){ 650 image->colorspace = GRAYColorspace; 651 image->storage_class = PseudoClass; 652 image->depth = 8UL; /* i only support that? */ 653 image->colors= 2; 654 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) 655 ThrowReaderException(ResourceLimitError, 656 "MemoryAllocationFailed"); 657 } else { 658 image->colorspace = RGBColorspace; 659 image->storage_class = DirectClass; 660 /* fixme: MAGICKCORE_QUANTUM_DEPTH ?*/ 661 image->depth = 8UL; /* i only support that? */ 662 663 image->alpha_trait = BlendPixelTrait; 664 /* is this useful? */ 665 } 666 status=SetImageExtent(image,image->columns,image->rows,exception); 667 if (status == MagickFalse) 668 return(DestroyImageList(image)); 669 #if DEBUG 670 printf("now filling %.20g x %.20g\n",(double) image->columns,(double) 671 image->rows); 672 #endif 673 674 675 #if 1 /* per_line */ 676 677 /* q = QueueAuthenticPixels(image,0,0,image->columns,image->rows); */ 678 get_page_image(lc, lc->page, 0, 0, info.width, info.height, exception); 679 #else 680 int i; 681 for (i = 0;i< image->rows; i++) 682 { 683 printf("%d\n",i); 684 q = QueueAuthenticPixels(image,0,i,image->columns,1); 685 get_page_line(lc, i, quantum_info); 686 SyncAuthenticPixels(image); 687 } 688 689 #endif /* per_line */ 690 691 692 #if DEBUG 693 printf("END: finished filling %.20g x %.20g\n",(double) image->columns, 694 (double) image->rows); 695 #endif 696 697 if (!image->ping) 698 SyncImage(image,exception); 699 /* 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 */ 718 if (AcquireImageColormap(image,2,exception) == MagickFalse) 719 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 731 static 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 742 static 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 765 register ssize_t 766 i; 767 768 /* 769 * Open image file. 770 */ 771 assert(image_info != (const ImageInfo *) NULL); 772 assert(image_info->signature == MagickCoreSignature); 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 == MagickCoreSignature); 780 781 782 logging = LogMagickEvent(CoderEvent,GetMagickModule(),"enter ReadDJVUImage()"); 783 (void) logging; 784 785 image = AcquireImage(image_info,exception); /* mmc: ?? */ 786 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 */ 807 lc = (LoadContext *) AcquireMagickMemory(sizeof(*lc)); 808 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* ! */ 824 url="http://www.imagemagick.org/fake.djvu"; 825 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; 868 for ( ; i < (ssize_t) lc->pages; i++) 869 { 870 image=ReadOneDJVUImage(lc,i,image_info,exception); 871 if (image == (Image *) NULL) 872 break; 873 image->scene=i; 874 AppendImageToList(&images,CloneImageList(image,exception)); 875 images->extent=GetBlobSize(image); 876 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 /* 910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 911 % % 912 % % 913 % % 914 % R e g i s t e r D J V U I m a g e % 915 % % 916 % % 917 % % 918 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 919 % 920 % RegisterDJVUImage() adds attributes for the DJVU image format to 921 % the list of supported formats. The attributes include the image format 922 % tag, a method to read and/or write the format, whether the format 923 % supports the saving of more than one frame to the same file or blob, 924 % whether the format supports native in-memory I/O, and a brief 925 % description of the format. 926 % 927 % The format of the RegisterDJVUImage method is: 928 % 929 % size_t RegisterDJVUImage(void) 930 % 931 */ 932 ModuleExport size_t RegisterDJVUImage(void) 933 { 934 char 935 version[MagickPathExtent]; 936 937 MagickInfo 938 *entry; 939 940 static const char 941 *DJVUNote = 942 { 943 "See http://www.djvuzone.org/ for details about the DJVU format. The\n" 944 "DJVU 1.2 specification is available there and at\n" 945 "ftp://swrinde.nde.swri.edu/pub/djvu/documents/." 946 }; 947 948 *version='\0'; 949 #if defined(DJVU_LIBDJVU_VER_STRING) 950 (void) ConcatenateMagickString(version,"libdjvu ",MagickPathExtent); 951 (void) ConcatenateMagickString(version,DJVU_LIBDJVU_VER_STRING,MagickPathExtent); 952 #endif 953 entry=AcquireMagickInfo("DJVU","DJVU","Deja vu"); 954 #if defined(MAGICKCORE_DJVU_DELEGATE) 955 entry->decoder=(DecodeImageHandler *) ReadDJVUImage; 956 #endif 957 entry->magick=(IsImageFormatHandler *) IsDJVU; 958 entry->flags|=CoderRawSupportFlag; 959 entry->flags^=CoderAdjoinFlag; 960 if (*version != '\0') 961 entry->version=AcquireString(version); 962 entry->note=AcquireString(DJVUNote); 963 (void) RegisterMagickInfo(entry); 964 return(MagickImageCoderSignature); 965 } 966 967 /* 969 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 970 % % 971 % % 972 % % 973 % U n r e g i s t e r D J V U I m a g e % 974 % % 975 % % 976 % % 977 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 978 % 979 % UnregisterDJVUImage() removes format registrations made by the 980 % DJVU module from the list of supported formats. 981 % 982 % The format of the UnregisterDJVUImage method is: 983 % 984 % UnregisterDJVUImage(void) 985 % 986 */ 987 ModuleExport void UnregisterDJVUImage(void) 988 { 989 (void) UnregisterMagickInfo("DJVU"); 990 } 991