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/* 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*/ 90static 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) 129extern "C" { 130#endif 131 132typedef struct _LoadContext 133 LoadContext; 134 135struct _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 147static void 148pump_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! */ 165static ddjvu_message_t* 166pump_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 189static const char* 190message_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 * */ 217int 218process_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 */ 325static void 326get_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 462static int 463get_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 561static 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 } 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 728static 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 739static 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 register 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) ResetMagickMemory(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="http://www.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 (void) CloseBlob(images); 879 if (image != (Image *) NULL) 880 image=DestroyImageList(image); 881 882#if 0 883 if ((image->page.width == 0) && (image->page.height == 0)) 884 { 885 image->page.width = image->columns+image->page.x; 886 image->page.height = image->rows+image->page.y; 887 } 888 if (image->columns == 0 || image->rows == 0) 889 { 890 if (logging != MagickFalse) 891 (void) LogMagickEvent(CoderEvent,GetMagickModule(), 892 "exit ReadDJVUImage() with error."); 893 ThrowReaderException(CorruptImageError,"CorruptImage"); 894 } 895 896 if (logging != MagickFalse) 897 (void) LogMagickEvent(CoderEvent,GetMagickModule(),"exit ReadDJVUImage()"); 898#endif 899 900 901 return(GetFirstImageInList(images)); 902} 903#endif 904 905/* 906%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 907% % 908% % 909% % 910% R e g i s t e r D J V U I m a g e % 911% % 912% % 913% % 914%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 915% 916% RegisterDJVUImage() adds attributes for the DJVU image format to 917% the list of supported formats. The attributes include the image format 918% tag, a method to read and/or write the format, whether the format 919% supports the saving of more than one frame to the same file or blob, 920% whether the format supports native in-memory I/O, and a brief 921% description of the format. 922% 923% The format of the RegisterDJVUImage method is: 924% 925% size_t RegisterDJVUImage(void) 926% 927*/ 928ModuleExport size_t RegisterDJVUImage(void) 929{ 930 char 931 version[MagickPathExtent]; 932 933 MagickInfo 934 *entry; 935 936 static const char 937 *DJVUNote = 938 { 939 "See http://www.djvuzone.org/ for details about the DJVU format. The\n" 940 "DJVU 1.2 specification is available there and at\n" 941 "ftp://swrinde.nde.swri.edu/pub/djvu/documents/." 942 }; 943 944 *version='\0'; 945#if defined(DJVU_LIBDJVU_VER_STRING) 946 (void) ConcatenateMagickString(version,"libdjvu ",MagickPathExtent); 947 (void) ConcatenateMagickString(version,DJVU_LIBDJVU_VER_STRING,MagickPathExtent); 948#endif 949 entry=AcquireMagickInfo("DJVU","DJVU","Deja vu"); 950#if defined(MAGICKCORE_DJVU_DELEGATE) 951 entry->decoder=(DecodeImageHandler *) ReadDJVUImage; 952#endif 953 entry->magick=(IsImageFormatHandler *) IsDJVU; 954 entry->flags|=CoderRawSupportFlag; 955 entry->flags^=CoderAdjoinFlag; 956 if (*version != '\0') 957 entry->version=AcquireString(version); 958 entry->note=AcquireString(DJVUNote); 959 (void) RegisterMagickInfo(entry); 960 return(MagickImageCoderSignature); 961} 962 963/* 964%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 965% % 966% % 967% % 968% U n r e g i s t e r D J V U I m a g e % 969% % 970% % 971% % 972%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 973% 974% UnregisterDJVUImage() removes format registrations made by the 975% DJVU module from the list of supported formats. 976% 977% The format of the UnregisterDJVUImage method is: 978% 979% UnregisterDJVUImage(void) 980% 981*/ 982ModuleExport void UnregisterDJVUImage(void) 983{ 984 (void) UnregisterMagickInfo("DJVU"); 985} 986