1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % PPPP CCCC DDDD % 7 % P P C D D % 8 % PPPP C D D % 9 % P C D D % 10 % P CCCC DDDD % 11 % % 12 % % 13 % Read/Write Photo CD Image Format % 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/property.h" 45 #include "MagickCore/blob.h" 46 #include "MagickCore/blob-private.h" 47 #include "MagickCore/cache.h" 48 #include "MagickCore/client.h" 49 #include "MagickCore/colorspace.h" 50 #include "MagickCore/colorspace-private.h" 51 #include "MagickCore/constitute.h" 52 #include "MagickCore/decorate.h" 53 #include "MagickCore/distort.h" 54 #include "MagickCore/exception.h" 55 #include "MagickCore/exception-private.h" 56 #include "MagickCore/gem.h" 57 #include "MagickCore/geometry.h" 58 #include "MagickCore/image.h" 59 #include "MagickCore/image-private.h" 60 #include "MagickCore/list.h" 61 #include "MagickCore/magick.h" 62 #include "MagickCore/memory_.h" 63 #include "MagickCore/monitor.h" 64 #include "MagickCore/monitor-private.h" 65 #include "MagickCore/montage.h" 66 #include "MagickCore/pixel-accessor.h" 67 #include "MagickCore/resize.h" 68 #include "MagickCore/quantum-private.h" 69 #include "MagickCore/static.h" 70 #include "MagickCore/string_.h" 71 #include "MagickCore/module.h" 72 #include "MagickCore/utility.h" 73 74 /* 76 Forward declarations. 77 */ 78 static MagickBooleanType 79 WritePCDImage(const ImageInfo *,Image *,ExceptionInfo *); 80 81 /* 83 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 84 % % 85 % % 86 % % 87 % D e c o d e I m a g e % 88 % % 89 % % 90 % % 91 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 92 % 93 % DecodeImage recovers the Huffman encoded luminance and chrominance 94 % deltas. 95 % 96 % The format of the DecodeImage method is: 97 % 98 % MagickBooleanType DecodeImage(Image *image,unsigned char *luma, 99 % unsigned char *chroma1,unsigned char *chroma2) 100 % 101 % A description of each parameter follows: 102 % 103 % o image: the address of a structure of type Image. 104 % 105 % o luma: the address of a character buffer that contains the 106 % luminance information. 107 % 108 % o chroma1: the address of a character buffer that contains the 109 % chrominance information. 110 % 111 % o chroma2: the address of a character buffer that contains the 112 % chrominance information. 113 % 114 */ 115 static MagickBooleanType DecodeImage(Image *image,unsigned char *luma, 116 unsigned char *chroma1,unsigned char *chroma2,ExceptionInfo *exception) 117 { 118 #define IsSync(sum) ((sum & 0xffffff00UL) == 0xfffffe00UL) 119 #define PCDGetBits(n) \ 120 { \ 121 sum=(sum << n) & 0xffffffff; \ 122 bits-=n; \ 123 while (bits <= 24) \ 124 { \ 125 if (p >= (buffer+0x800)) \ 126 { \ 127 count=ReadBlob(image,0x800,buffer); \ 128 p=buffer; \ 129 } \ 130 sum|=((unsigned int) (*p) << (24-bits)); \ 131 bits+=8; \ 132 p++; \ 133 } \ 134 } 135 136 typedef struct PCDTable 137 { 138 unsigned int 139 length, 140 sequence; 141 142 MagickStatusType 143 mask; 144 145 unsigned char 146 key; 147 } PCDTable; 148 149 PCDTable 150 *pcd_table[3]; 151 152 register ssize_t 153 i, 154 j; 155 156 register PCDTable 157 *r; 158 159 register unsigned char 160 *p, 161 *q; 162 163 size_t 164 bits, 165 length, 166 plane, 167 pcd_length[3], 168 row, 169 sum; 170 171 ssize_t 172 count, 173 quantum; 174 175 unsigned char 176 *buffer; 177 178 /* 179 Initialize Huffman tables. 180 */ 181 assert(image != (const Image *) NULL); 182 assert(image->signature == MagickCoreSignature); 183 if (image->debug != MagickFalse) 184 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 185 assert(luma != (unsigned char *) NULL); 186 assert(chroma1 != (unsigned char *) NULL); 187 assert(chroma2 != (unsigned char *) NULL); 188 buffer=(unsigned char *) AcquireQuantumMemory(0x800,sizeof(*buffer)); 189 if (buffer == (unsigned char *) NULL) 190 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 191 image->filename); 192 sum=0; 193 bits=32; 194 p=buffer+0x800; 195 for (i=0; i < 3; i++) 196 { 197 pcd_table[i]=(PCDTable *) NULL; 198 pcd_length[i]=0; 199 } 200 for (i=0; i < (image->columns > 1536 ? 3 : 1); i++) 201 { 202 PCDGetBits(8); 203 length=(sum & 0xff)+1; 204 pcd_table[i]=(PCDTable *) AcquireQuantumMemory(length, 205 sizeof(*pcd_table[i])); 206 if (pcd_table[i] == (PCDTable *) NULL) 207 { 208 buffer=(unsigned char *) RelinquishMagickMemory(buffer); 209 ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed", 210 image->filename); 211 } 212 r=pcd_table[i]; 213 for (j=0; j < (ssize_t) length; j++) 214 { 215 PCDGetBits(8); 216 r->length=(unsigned int) (sum & 0xff)+1; 217 if (r->length > 16) 218 { 219 buffer=(unsigned char *) RelinquishMagickMemory(buffer); 220 return(MagickFalse); 221 } 222 PCDGetBits(16); 223 r->sequence=(unsigned int) (sum & 0xffff) << 16; 224 PCDGetBits(8); 225 r->key=(unsigned char) (sum & 0xff); 226 r->mask=(~((1U << (32-r->length))-1)); 227 r++; 228 } 229 pcd_length[i]=(size_t) length; 230 } 231 /* 232 Search for Sync byte. 233 */ 234 for (i=0; i < 1; i++) 235 PCDGetBits(16); 236 for (i=0; i < 1; i++) 237 PCDGetBits(16); 238 while ((sum & 0x00fff000UL) != 0x00fff000UL) 239 PCDGetBits(8); 240 while (IsSync(sum) == 0) 241 PCDGetBits(1); 242 /* 243 Recover the Huffman encoded luminance and chrominance deltas. 244 */ 245 count=0; 246 length=0; 247 plane=0; 248 row=0; 249 q=luma; 250 for ( ; ; ) 251 { 252 if (IsSync(sum) != 0) 253 { 254 /* 255 Determine plane and row number. 256 */ 257 PCDGetBits(16); 258 row=((sum >> 9) & 0x1fff); 259 if (row == image->rows) 260 break; 261 PCDGetBits(8); 262 plane=sum >> 30; 263 PCDGetBits(16); 264 switch (plane) 265 { 266 case 0: 267 { 268 q=luma+row*image->columns; 269 count=(ssize_t) image->columns; 270 break; 271 } 272 case 2: 273 { 274 q=chroma1+(row >> 1)*image->columns; 275 count=(ssize_t) (image->columns >> 1); 276 plane--; 277 break; 278 } 279 case 3: 280 { 281 q=chroma2+(row >> 1)*image->columns; 282 count=(ssize_t) (image->columns >> 1); 283 plane--; 284 break; 285 } 286 default: 287 { 288 ThrowBinaryException(CorruptImageError,"CorruptImage", 289 image->filename); 290 } 291 } 292 length=pcd_length[plane]; 293 continue; 294 } 295 /* 296 Decode luminance or chrominance deltas. 297 */ 298 r=pcd_table[plane]; 299 for (i=0; ((i < (ssize_t) length) && ((sum & r->mask) != r->sequence)); i++) 300 r++; 301 if ((row > image->rows) || (r == (PCDTable *) NULL)) 302 { 303 (void) ThrowMagickException(exception,GetMagickModule(), 304 CorruptImageWarning,"SkipToSyncByte","`%s'",image->filename); 305 while ((sum & 0x00fff000) != 0x00fff000) 306 PCDGetBits(8); 307 while (IsSync(sum) == 0) 308 PCDGetBits(1); 309 continue; 310 } 311 if (r->key < 128) 312 quantum=(ssize_t) (*q)+r->key; 313 else 314 quantum=(ssize_t) (*q)+r->key-256; 315 *q=(unsigned char) ((quantum < 0) ? 0 : (quantum > 255) ? 255 : quantum); 316 q++; 317 PCDGetBits(r->length); 318 count--; 319 } 320 /* 321 Relinquish resources. 322 */ 323 for (i=0; i < (image->columns > 1536 ? 3 : 1); i++) 324 pcd_table[i]=(PCDTable *) RelinquishMagickMemory(pcd_table[i]); 325 buffer=(unsigned char *) RelinquishMagickMemory(buffer); 326 return(MagickTrue); 327 } 328 329 /* 331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 332 % % 333 % % 334 % % 335 % I s P C D % 336 % % 337 % % 338 % % 339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 340 % 341 % IsPCD() returns MagickTrue if the image format type, identified by the 342 % magick string, is PCD. 343 % 344 % The format of the IsPCD method is: 345 % 346 % MagickBooleanType IsPCD(const unsigned char *magick,const size_t length) 347 % 348 % A description of each parameter follows: 349 % 350 % o magick: compare image format pattern against these bytes. 351 % 352 % o length: Specifies the length of the magick string. 353 % 354 */ 355 static MagickBooleanType IsPCD(const unsigned char *magick,const size_t length) 356 { 357 if (length < 2052) 358 return(MagickFalse); 359 if (LocaleNCompare((const char *) magick+2048,"PCD_",4) == 0) 360 return(MagickTrue); 361 return(MagickFalse); 362 } 363 364 /* 366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 367 % % 368 % % 369 % % 370 % R e a d P C D I m a g e % 371 % % 372 % % 373 % % 374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 375 % 376 % ReadPCDImage() reads a Photo CD image file and returns it. It 377 % allocates the memory necessary for the new Image structure and returns a 378 % pointer to the new image. Much of the PCD decoder was derived from 379 % the program hpcdtoppm(1) by Hadmut Danisch. 380 % 381 % The format of the ReadPCDImage method is: 382 % 383 % image=ReadPCDImage(image_info) 384 % 385 % A description of each parameter follows: 386 % 387 % o image_info: the image info. 388 % 389 % o exception: return any errors or warnings in this structure. 390 % 391 */ 392 static Image *OverviewImage(const ImageInfo *image_info,Image *image, 393 ExceptionInfo *exception) 394 { 395 Image 396 *montage_image; 397 398 MontageInfo 399 *montage_info; 400 401 register Image 402 *p; 403 404 /* 405 Create the PCD Overview image. 406 */ 407 for (p=image; p != (Image *) NULL; p=p->next) 408 { 409 (void) DeleteImageProperty(p,"label"); 410 (void) SetImageProperty(p,"label",DefaultTileLabel,exception); 411 } 412 montage_info=CloneMontageInfo(image_info,(MontageInfo *) NULL); 413 (void) CopyMagickString(montage_info->filename,image_info->filename, 414 MagickPathExtent); 415 montage_image=MontageImageList(image_info,montage_info,image,exception); 416 montage_info=DestroyMontageInfo(montage_info); 417 if (montage_image == (Image *) NULL) 418 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 419 image=DestroyImage(image); 420 return(montage_image); 421 } 422 423 static void Upsample(const size_t width,const size_t height, 424 const size_t scaled_width,unsigned char *pixels) 425 { 426 register ssize_t 427 x, 428 y; 429 430 register unsigned char 431 *p, 432 *q, 433 *r; 434 435 /* 436 Create a new image that is a integral size greater than an existing one. 437 */ 438 assert(pixels != (unsigned char *) NULL); 439 for (y=0; y < (ssize_t) height; y++) 440 { 441 p=pixels+(height-1-y)*scaled_width+(width-1); 442 q=pixels+((height-1-y) << 1)*scaled_width+((width-1) << 1); 443 *q=(*p); 444 *(q+1)=(*(p)); 445 for (x=1; x < (ssize_t) width; x++) 446 { 447 p--; 448 q-=2; 449 *q=(*p); 450 *(q+1)=(unsigned char) ((((size_t) *p)+((size_t) *(p+1))+1) >> 1); 451 } 452 } 453 for (y=0; y < (ssize_t) (height-1); y++) 454 { 455 p=pixels+((size_t) y << 1)*scaled_width; 456 q=p+scaled_width; 457 r=q+scaled_width; 458 for (x=0; x < (ssize_t) (width-1); x++) 459 { 460 *q=(unsigned char) ((((size_t) *p)+((size_t) *r)+1) >> 1); 461 *(q+1)=(unsigned char) ((((size_t) *p)+((size_t) *(p+2))+ 462 ((size_t) *r)+((size_t) *(r+2))+2) >> 2); 463 q+=2; 464 p+=2; 465 r+=2; 466 } 467 *q++=(unsigned char) ((((size_t) *p++)+((size_t) *r++)+1) >> 1); 468 *q++=(unsigned char) ((((size_t) *p++)+((size_t) *r++)+1) >> 1); 469 } 470 p=pixels+(2*height-2)*scaled_width; 471 q=pixels+(2*height-1)*scaled_width; 472 (void) CopyMagickMemory(q,p,(size_t) (2*width)); 473 } 474 475 static Image *ReadPCDImage(const ImageInfo *image_info,ExceptionInfo *exception) 476 { 477 Image 478 *image; 479 480 MagickBooleanType 481 status; 482 483 MagickOffsetType 484 offset; 485 486 MagickSizeType 487 number_pixels; 488 489 register ssize_t 490 i, 491 y; 492 493 register Quantum 494 *q; 495 496 register unsigned char 497 *c1, 498 *c2, 499 *yy; 500 501 size_t 502 height, 503 number_images, 504 rotate, 505 scene, 506 width; 507 508 ssize_t 509 count, 510 x; 511 512 unsigned char 513 *chroma1, 514 *chroma2, 515 *header, 516 *luma; 517 518 unsigned int 519 overview; 520 521 /* 522 Open image file. 523 */ 524 assert(image_info != (const ImageInfo *) NULL); 525 assert(image_info->signature == MagickCoreSignature); 526 if (image_info->debug != MagickFalse) 527 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 528 image_info->filename); 529 assert(exception != (ExceptionInfo *) NULL); 530 assert(exception->signature == MagickCoreSignature); 531 image=AcquireImage(image_info,exception); 532 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 533 if (status == MagickFalse) 534 { 535 image=DestroyImageList(image); 536 return((Image *) NULL); 537 } 538 /* 539 Determine if this a PCD file. 540 */ 541 header=(unsigned char *) AcquireQuantumMemory(0x800,3UL*sizeof(*header)); 542 if (header == (unsigned char *) NULL) 543 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 544 count=ReadBlob(image,3*0x800,header); 545 overview=LocaleNCompare((char *) header,"PCD_OPA",7) == 0; 546 if ((count != (3*0x800)) || 547 ((LocaleNCompare((char *) header+0x800,"PCD",3) != 0) && (overview ==0))) 548 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 549 rotate=header[0x0e02] & 0x03; 550 number_images=(header[10] << 8) | header[11]; 551 if (number_images > 65535) 552 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 553 header=(unsigned char *) RelinquishMagickMemory(header); 554 /* 555 Determine resolution by scene specification. 556 */ 557 if ((image->columns == 0) || (image->rows == 0)) 558 scene=3; 559 else 560 { 561 width=192; 562 height=128; 563 for (scene=1; scene < 6; scene++) 564 { 565 if ((width >= image->columns) && (height >= image->rows)) 566 break; 567 width<<=1; 568 height<<=1; 569 } 570 } 571 if (image_info->number_scenes != 0) 572 scene=(size_t) MagickMin(image_info->scene,6); 573 if (overview != 0) 574 scene=1; 575 /* 576 Initialize image structure. 577 */ 578 width=192; 579 height=128; 580 for (i=1; i < (ssize_t) MagickMin(scene,3); i++) 581 { 582 width<<=1; 583 height<<=1; 584 } 585 image->columns=width; 586 image->rows=height; 587 image->depth=8; 588 for ( ; i < (ssize_t) scene; i++) 589 { 590 image->columns<<=1; 591 image->rows<<=1; 592 } 593 status=SetImageExtent(image,image->columns,image->rows,exception); 594 if (status == MagickFalse) 595 return(DestroyImageList(image)); 596 /* 597 Allocate luma and chroma memory. 598 */ 599 number_pixels=(MagickSizeType) image->columns*image->rows; 600 if (number_pixels != (size_t) number_pixels) 601 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 602 chroma1=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows* 603 10*sizeof(*chroma1)); 604 chroma2=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows* 605 10*sizeof(*chroma2)); 606 luma=(unsigned char *) AcquireQuantumMemory(image->columns+1UL,image->rows* 607 10*sizeof(*luma)); 608 if ((chroma1 == (unsigned char *) NULL) || 609 (chroma2 == (unsigned char *) NULL) || (luma == (unsigned char *) NULL)) 610 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 611 /* 612 Advance to image data. 613 */ 614 offset=93; 615 if (overview != 0) 616 offset=2; 617 else 618 if (scene == 2) 619 offset=20; 620 else 621 if (scene <= 1) 622 offset=1; 623 for (i=0; i < (ssize_t) (offset*0x800); i++) 624 (void) ReadBlobByte(image); 625 if (overview != 0) 626 { 627 Image 628 *overview_image; 629 630 MagickProgressMonitor 631 progress_monitor; 632 633 register ssize_t 634 j; 635 636 /* 637 Read thumbnails from overview image. 638 */ 639 for (j=1; j <= (ssize_t) number_images; j++) 640 { 641 progress_monitor=SetImageProgressMonitor(image, 642 (MagickProgressMonitor) NULL,image->client_data); 643 (void) FormatLocaleString(image->filename,MagickPathExtent, 644 "images/img%04ld.pcd",(long) j); 645 (void) FormatLocaleString(image->magick_filename,MagickPathExtent, 646 "images/img%04ld.pcd",(long) j); 647 image->scene=(size_t) j; 648 image->columns=width; 649 image->rows=height; 650 image->depth=8; 651 yy=luma; 652 c1=chroma1; 653 c2=chroma2; 654 for (y=0; y < (ssize_t) height; y+=2) 655 { 656 count=ReadBlob(image,width,yy); 657 yy+=image->columns; 658 count=ReadBlob(image,width,yy); 659 yy+=image->columns; 660 count=ReadBlob(image,width >> 1,c1); 661 c1+=image->columns; 662 count=ReadBlob(image,width >> 1,c2); 663 c2+=image->columns; 664 } 665 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1); 666 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2); 667 /* 668 Transfer luminance and chrominance channels. 669 */ 670 yy=luma; 671 c1=chroma1; 672 c2=chroma2; 673 for (y=0; y < (ssize_t) image->rows; y++) 674 { 675 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 676 if (q == (Quantum *) NULL) 677 break; 678 for (x=0; x < (ssize_t) image->columns; x++) 679 { 680 SetPixelRed(image,ScaleCharToQuantum(*yy++),q); 681 SetPixelGreen(image,ScaleCharToQuantum(*c1++),q); 682 SetPixelBlue(image,ScaleCharToQuantum(*c2++),q); 683 q+=GetPixelChannels(image); 684 } 685 if (SyncAuthenticPixels(image,exception) == MagickFalse) 686 break; 687 } 688 image->colorspace=YCCColorspace; 689 if (LocaleCompare(image_info->magick,"PCDS") == 0) 690 SetImageColorspace(image,sRGBColorspace,exception); 691 if (j < (ssize_t) number_images) 692 { 693 /* 694 Allocate next image structure. 695 */ 696 AcquireNextImage(image_info,image,exception); 697 if (GetNextImageInList(image) == (Image *) NULL) 698 { 699 image=DestroyImageList(image); 700 return((Image *) NULL); 701 } 702 image=SyncNextImageInList(image); 703 } 704 (void) SetImageProgressMonitor(image,progress_monitor, 705 image->client_data); 706 if (image->previous == (Image *) NULL) 707 { 708 status=SetImageProgress(image,LoadImageTag,j-1,number_images); 709 if (status == MagickFalse) 710 break; 711 } 712 } 713 chroma2=(unsigned char *) RelinquishMagickMemory(chroma2); 714 chroma1=(unsigned char *) RelinquishMagickMemory(chroma1); 715 luma=(unsigned char *) RelinquishMagickMemory(luma); 716 image=GetFirstImageInList(image); 717 overview_image=OverviewImage(image_info,image,exception); 718 return(overview_image); 719 } 720 /* 721 Read interleaved image. 722 */ 723 yy=luma; 724 c1=chroma1; 725 c2=chroma2; 726 for (y=0; y < (ssize_t) height; y+=2) 727 { 728 count=ReadBlob(image,width,yy); 729 yy+=image->columns; 730 count=ReadBlob(image,width,yy); 731 yy+=image->columns; 732 count=ReadBlob(image,width >> 1,c1); 733 c1+=image->columns; 734 count=ReadBlob(image,width >> 1,c2); 735 c2+=image->columns; 736 } 737 if (scene >= 4) 738 { 739 /* 740 Recover luminance deltas for 1536x1024 image. 741 */ 742 Upsample(768,512,image->columns,luma); 743 Upsample(384,256,image->columns,chroma1); 744 Upsample(384,256,image->columns,chroma2); 745 image->rows=1024; 746 for (i=0; i < (4*0x800); i++) 747 (void) ReadBlobByte(image); 748 status=DecodeImage(image,luma,chroma1,chroma2,exception); 749 if ((scene >= 5) && status) 750 { 751 /* 752 Recover luminance deltas for 3072x2048 image. 753 */ 754 Upsample(1536,1024,image->columns,luma); 755 Upsample(768,512,image->columns,chroma1); 756 Upsample(768,512,image->columns,chroma2); 757 image->rows=2048; 758 offset=TellBlob(image)/0x800+12; 759 offset=SeekBlob(image,offset*0x800,SEEK_SET); 760 status=DecodeImage(image,luma,chroma1,chroma2,exception); 761 if ((scene >= 6) && (status != MagickFalse)) 762 { 763 /* 764 Recover luminance deltas for 6144x4096 image (vaporware). 765 */ 766 Upsample(3072,2048,image->columns,luma); 767 Upsample(1536,1024,image->columns,chroma1); 768 Upsample(1536,1024,image->columns,chroma2); 769 image->rows=4096; 770 } 771 } 772 } 773 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma1); 774 Upsample(image->columns >> 1,image->rows >> 1,image->columns,chroma2); 775 /* 776 Transfer luminance and chrominance channels. 777 */ 778 yy=luma; 779 c1=chroma1; 780 c2=chroma2; 781 for (y=0; y < (ssize_t) image->rows; y++) 782 { 783 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 784 if (q == (Quantum *) NULL) 785 break; 786 for (x=0; x < (ssize_t) image->columns; x++) 787 { 788 SetPixelRed(image,ScaleCharToQuantum(*yy++),q); 789 SetPixelGreen(image,ScaleCharToQuantum(*c1++),q); 790 SetPixelBlue(image,ScaleCharToQuantum(*c2++),q); 791 q+=GetPixelChannels(image); 792 } 793 if (SyncAuthenticPixels(image,exception) == MagickFalse) 794 break; 795 if (image->previous == (Image *) NULL) 796 { 797 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 798 image->rows); 799 if (status == MagickFalse) 800 break; 801 } 802 } 803 chroma2=(unsigned char *) RelinquishMagickMemory(chroma2); 804 chroma1=(unsigned char *) RelinquishMagickMemory(chroma1); 805 luma=(unsigned char *) RelinquishMagickMemory(luma); 806 if (EOFBlob(image) != MagickFalse) 807 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 808 image->filename); 809 (void) CloseBlob(image); 810 if (image_info->ping == MagickFalse) 811 if ((rotate == 1) || (rotate == 3)) 812 { 813 double 814 degrees; 815 816 Image 817 *rotate_image; 818 819 /* 820 Rotate image. 821 */ 822 degrees=rotate == 1 ? -90.0 : 90.0; 823 rotate_image=RotateImage(image,degrees,exception); 824 if (rotate_image != (Image *) NULL) 825 { 826 image=DestroyImage(image); 827 image=rotate_image; 828 } 829 } 830 /* 831 Set CCIR 709 primaries with a D65 white point. 832 */ 833 image->chromaticity.red_primary.x=0.6400f; 834 image->chromaticity.red_primary.y=0.3300f; 835 image->chromaticity.green_primary.x=0.3000f; 836 image->chromaticity.green_primary.y=0.6000f; 837 image->chromaticity.blue_primary.x=0.1500f; 838 image->chromaticity.blue_primary.y=0.0600f; 839 image->chromaticity.white_point.x=0.3127f; 840 image->chromaticity.white_point.y=0.3290f; 841 image->gamma=1.000f/2.200f; 842 image->colorspace=YCCColorspace; 843 if (LocaleCompare(image_info->magick,"PCDS") == 0) 844 SetImageColorspace(image,sRGBColorspace,exception); 845 return(GetFirstImageInList(image)); 846 } 847 848 /* 850 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 851 % % 852 % % 853 % % 854 % R e g i s t e r P C D I m a g e % 855 % % 856 % % 857 % % 858 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 859 % 860 % RegisterPCDImage() adds attributes for the PCD image format to 861 % the list of supported formats. The attributes include the image format 862 % tag, a method to read and/or write the format, whether the format 863 % supports the saving of more than one frame to the same file or blob, 864 % whether the format supports native in-memory I/O, and a brief 865 % description of the format. 866 % 867 % The format of the RegisterPCDImage method is: 868 % 869 % size_t RegisterPCDImage(void) 870 % 871 */ 872 ModuleExport size_t RegisterPCDImage(void) 873 { 874 MagickInfo 875 *entry; 876 877 entry=AcquireMagickInfo("PCD","PCD","Photo CD"); 878 entry->decoder=(DecodeImageHandler *) ReadPCDImage; 879 entry->encoder=(EncodeImageHandler *) WritePCDImage; 880 entry->magick=(IsImageFormatHandler *) IsPCD; 881 entry->flags^=CoderAdjoinFlag; 882 entry->flags|=CoderSeekableStreamFlag; 883 (void) RegisterMagickInfo(entry); 884 entry=AcquireMagickInfo("PCD","PCDS","Photo CD"); 885 entry->decoder=(DecodeImageHandler *) ReadPCDImage; 886 entry->encoder=(EncodeImageHandler *) WritePCDImage; 887 entry->flags^=CoderAdjoinFlag; 888 entry->flags|=CoderSeekableStreamFlag; 889 (void) RegisterMagickInfo(entry); 890 return(MagickImageCoderSignature); 891 } 892 893 /* 895 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 896 % % 897 % % 898 % % 899 % U n r e g i s t e r P C D I m a g e % 900 % % 901 % % 902 % % 903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 904 % 905 % UnregisterPCDImage() removes format registrations made by the 906 % PCD module from the list of supported formats. 907 % 908 % The format of the UnregisterPCDImage method is: 909 % 910 % UnregisterPCDImage(void) 911 % 912 */ 913 ModuleExport void UnregisterPCDImage(void) 914 { 915 (void) UnregisterMagickInfo("PCD"); 916 (void) UnregisterMagickInfo("PCDS"); 917 } 918 919 /* 921 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 922 % % 923 % % 924 % % 925 % W r i t e P C D I m a g e % 926 % % 927 % % 928 % % 929 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 930 % 931 % WritePCDImage() writes an image in the Photo CD encoded image format. 932 % 933 % The format of the WritePCDImage method is: 934 % 935 % MagickBooleanType WritePCDImage(const ImageInfo *image_info, 936 % Image *image,ExceptionInfo *exception) 937 % 938 % A description of each parameter follows. 939 % 940 % o image_info: the image info. 941 % 942 % o image: The image. 943 % 944 % o exception: return any errors or warnings in this structure. 945 % 946 */ 947 948 static MagickBooleanType WritePCDTile(Image *image,const char *page_geometry, 949 const size_t tile_columns,const size_t tile_rows,ExceptionInfo *exception) 950 { 951 GeometryInfo 952 geometry_info; 953 954 Image 955 *downsample_image, 956 *tile_image; 957 958 MagickBooleanType 959 status; 960 961 MagickStatusType 962 flags; 963 964 RectangleInfo 965 geometry; 966 967 register const Quantum 968 *p, 969 *q; 970 971 register ssize_t 972 i, 973 x; 974 975 ssize_t 976 y; 977 978 /* 979 Scale image to tile size. 980 */ 981 SetGeometry(image,&geometry); 982 (void) ParseMetaGeometry(page_geometry,&geometry.x,&geometry.y, 983 &geometry.width,&geometry.height); 984 if ((geometry.width % 2) != 0) 985 geometry.width--; 986 if ((geometry.height % 2) != 0) 987 geometry.height--; 988 tile_image=ResizeImage(image,geometry.width,geometry.height,TriangleFilter, 989 exception); 990 if (tile_image == (Image *) NULL) 991 return(MagickFalse); 992 flags=ParseGeometry(page_geometry,&geometry_info); 993 geometry.width=(size_t) geometry_info.rho; 994 geometry.height=(size_t) geometry_info.sigma; 995 if ((flags & SigmaValue) == 0) 996 geometry.height=geometry.width; 997 if ((tile_image->columns != geometry.width) || 998 (tile_image->rows != geometry.height)) 999 { 1000 Image 1001 *bordered_image; 1002 1003 RectangleInfo 1004 border_info; 1005 1006 /* 1007 Put a border around the image. 1008 */ 1009 border_info.width=(geometry.width-tile_image->columns+1) >> 1; 1010 border_info.height=(geometry.height-tile_image->rows+1) >> 1; 1011 bordered_image=BorderImage(tile_image,&border_info,image->compose, 1012 exception); 1013 if (bordered_image == (Image *) NULL) 1014 return(MagickFalse); 1015 tile_image=DestroyImage(tile_image); 1016 tile_image=bordered_image; 1017 } 1018 if ((tile_image->columns != tile_columns) || (tile_image->rows != tile_rows)) 1019 { 1020 Image 1021 *resize_image; 1022 1023 resize_image=ResizeImage(tile_image,tile_columns,tile_rows, 1024 tile_image->filter,exception); 1025 if (resize_image != (Image *) NULL) 1026 { 1027 tile_image=DestroyImage(tile_image); 1028 tile_image=resize_image; 1029 } 1030 } 1031 (void) TransformImageColorspace(tile_image,YCCColorspace,exception); 1032 downsample_image=ResizeImage(tile_image,tile_image->columns/2, 1033 tile_image->rows/2,TriangleFilter,exception); 1034 if (downsample_image == (Image *) NULL) 1035 return(MagickFalse); 1036 /* 1037 Write tile to PCD file. 1038 */ 1039 for (y=0; y < (ssize_t) tile_image->rows; y+=2) 1040 { 1041 p=GetVirtualPixels(tile_image,0,y,tile_image->columns,2,exception); 1042 if (p == (const Quantum *) NULL) 1043 break; 1044 for (x=0; x < (ssize_t) (tile_image->columns << 1); x++) 1045 { 1046 (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelRed(tile_image,p))); 1047 p+=GetPixelChannels(tile_image); 1048 } 1049 q=GetVirtualPixels(downsample_image,0,y >> 1,downsample_image->columns,1, 1050 exception); 1051 if (q == (Quantum *) NULL) 1052 break; 1053 for (x=0; x < (ssize_t) downsample_image->columns; x++) 1054 { 1055 (void) WriteBlobByte(image,ScaleQuantumToChar( 1056 GetPixelGreen(tile_image,q))); 1057 q++; 1058 } 1059 q=GetVirtualPixels(downsample_image,0,y >> 1,downsample_image->columns,1, 1060 exception); 1061 if (q == (Quantum *) NULL) 1062 break; 1063 for (x=0; x < (ssize_t) downsample_image->columns; x++) 1064 { 1065 (void) WriteBlobByte(image,ScaleQuantumToChar( 1066 GetPixelBlue(tile_image,q))); 1067 q++; 1068 } 1069 status=SetImageProgress(image,SaveImageTag,y,tile_image->rows); 1070 if (status == MagickFalse) 1071 break; 1072 } 1073 for (i=0; i < 0x800; i++) 1074 (void) WriteBlobByte(image,'\0'); 1075 downsample_image=DestroyImage(downsample_image); 1076 tile_image=DestroyImage(tile_image); 1077 return(MagickTrue); 1078 } 1079 1080 static MagickBooleanType WritePCDImage(const ImageInfo *image_info,Image *image, 1081 ExceptionInfo *exception) 1082 { 1083 Image 1084 *pcd_image; 1085 1086 MagickBooleanType 1087 status; 1088 1089 register ssize_t 1090 i; 1091 1092 assert(image_info != (const ImageInfo *) NULL); 1093 assert(image_info->signature == MagickCoreSignature); 1094 assert(image != (Image *) NULL); 1095 assert(image->signature == MagickCoreSignature); 1096 if (image->debug != MagickFalse) 1097 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1098 pcd_image=image; 1099 if (image->columns < image->rows) 1100 { 1101 Image 1102 *rotate_image; 1103 1104 /* 1105 Rotate portrait to landscape. 1106 */ 1107 rotate_image=RotateImage(image,90.0,exception); 1108 if (rotate_image == (Image *) NULL) 1109 return(MagickFalse); 1110 pcd_image=rotate_image; 1111 } 1112 /* 1113 Open output image file. 1114 */ 1115 status=OpenBlob(image_info,pcd_image,WriteBinaryBlobMode,exception); 1116 if (status == MagickFalse) 1117 return(status); 1118 if (IssRGBCompatibleColorspace(pcd_image->colorspace) == MagickFalse) 1119 (void) TransformImageColorspace(pcd_image,sRGBColorspace,exception); 1120 /* 1121 Write PCD image header. 1122 */ 1123 for (i=0; i < 32; i++) 1124 (void) WriteBlobByte(pcd_image,0xff); 1125 for (i=0; i < 4; i++) 1126 (void) WriteBlobByte(pcd_image,0x0e); 1127 for (i=0; i < 8; i++) 1128 (void) WriteBlobByte(pcd_image,'\0'); 1129 for (i=0; i < 4; i++) 1130 (void) WriteBlobByte(pcd_image,0x01); 1131 for (i=0; i < 4; i++) 1132 (void) WriteBlobByte(pcd_image,0x05); 1133 for (i=0; i < 8; i++) 1134 (void) WriteBlobByte(pcd_image,'\0'); 1135 for (i=0; i < 4; i++) 1136 (void) WriteBlobByte(pcd_image,0x0A); 1137 for (i=0; i < 36; i++) 1138 (void) WriteBlobByte(pcd_image,'\0'); 1139 for (i=0; i < 4; i++) 1140 (void) WriteBlobByte(pcd_image,0x01); 1141 for (i=0; i < 1944; i++) 1142 (void) WriteBlobByte(pcd_image,'\0'); 1143 (void) WriteBlob(pcd_image,7,(const unsigned char *) "PCD_IPI"); 1144 (void) WriteBlobByte(pcd_image,0x06); 1145 for (i=0; i < 1530; i++) 1146 (void) WriteBlobByte(pcd_image,'\0'); 1147 if (image->columns < image->rows) 1148 (void) WriteBlobByte(pcd_image,'\1'); 1149 else 1150 (void) WriteBlobByte(pcd_image,'\0'); 1151 for (i=0; i < (3*0x800-1539); i++) 1152 (void) WriteBlobByte(pcd_image,'\0'); 1153 /* 1154 Write PCD tiles. 1155 */ 1156 status=WritePCDTile(pcd_image,"768x512>",192,128,exception); 1157 status=WritePCDTile(pcd_image,"768x512>",384,256,exception); 1158 status=WritePCDTile(pcd_image,"768x512>",768,512,exception); 1159 (void) CloseBlob(pcd_image); 1160 if (pcd_image != image) 1161 pcd_image=DestroyImage(pcd_image); 1162 return(status); 1163 } 1164