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