1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % % 6 % PPPP AAA L M M % 7 % P P A A L MM MM % 8 % PPPP AAAAA L M M M % 9 % P A A L M M % 10 % P A A LLLLL M M % 11 % % 12 % % 13 % Read/Write Palm Pixmap. % 14 % % 15 % % 16 % Software Design % 17 % Christopher R. Hawks % 18 % December 2001 % 19 % % 20 % Copyright 1999-2004 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 % Based on pnmtopalm by Bill Janssen and ppmtobmp by Ian Goldberg. 38 % 39 */ 40 41 /* 43 Include declarations. 44 */ 45 #include "MagickCore/studio.h" 46 #include "MagickCore/attribute.h" 47 #include "MagickCore/blob.h" 48 #include "MagickCore/blob-private.h" 49 #include "MagickCore/cache.h" 50 #include "MagickCore/color.h" 51 #include "MagickCore/colormap.h" 52 #include "MagickCore/colormap-private.h" 53 #include "MagickCore/color-private.h" 54 #include "MagickCore/colorspace.h" 55 #include "MagickCore/colorspace-private.h" 56 #include "MagickCore/constitute.h" 57 #include "MagickCore/exception.h" 58 #include "MagickCore/histogram.h" 59 #include "MagickCore/image.h" 60 #include "MagickCore/image-private.h" 61 #include "MagickCore/list.h" 62 #include "MagickCore/magick.h" 63 #include "MagickCore/memory_.h" 64 #include "MagickCore/monitor.h" 65 #include "MagickCore/monitor-private.h" 66 #include "MagickCore/paint.h" 67 #include "MagickCore/pixel-accessor.h" 68 #include "MagickCore/property.h" 69 #include "MagickCore/quantize.h" 70 #include "MagickCore/quantum-private.h" 71 #include "MagickCore/static.h" 72 #include "MagickCore/string_.h" 73 #include "MagickCore/module.h" 74 #include "MagickCore/utility.h" 75 76 /* 78 Define declarations. 79 */ 80 #define PALM_IS_COMPRESSED_FLAG 0x8000 81 #define PALM_HAS_COLORMAP_FLAG 0x4000 82 #define PALM_HAS_FOUR_BYTE_FIELD 0x0200 83 #define PALM_HAS_TRANSPARENCY_FLAG 0x2000 84 #define PALM_IS_INDIRECT 0x1000 85 #define PALM_IS_FOR_SCREEN 0x0800 86 #define PALM_IS_DIRECT_COLOR 0x0400 87 #define PALM_COMPRESSION_SCANLINE 0x00 88 #define PALM_COMPRESSION_RLE 0x01 89 #define PALM_COMPRESSION_NONE 0xFF 90 91 /* 93 The 256 color system palette for Palm Computing Devices. 94 */ 95 static const unsigned char 96 PalmPalette[256][3] = 97 { 98 {255, 255,255}, {255, 204,255}, {255, 153,255}, {255, 102,255}, 99 {255, 51,255}, {255, 0,255}, {255, 255,204}, {255, 204,204}, 100 {255, 153,204}, {255, 102,204}, {255, 51,204}, {255, 0,204}, 101 {255, 255,153}, {255, 204,153}, {255, 153,153}, {255, 102,153}, 102 {255, 51,153}, {255, 0,153}, {204, 255,255}, {204, 204,255}, 103 {204, 153,255}, {204, 102,255}, {204, 51,255}, {204, 0,255}, 104 {204, 255,204}, {204, 204,204}, {204, 153,204}, {204, 102,204}, 105 {204, 51,204}, {204, 0,204}, {204, 255,153}, {204, 204,153}, 106 {204, 153,153}, {204, 102,153}, {204, 51,153}, {204, 0,153}, 107 {153, 255,255}, {153, 204,255}, {153, 153,255}, {153, 102,255}, 108 {153, 51,255}, {153, 0,255}, {153, 255,204}, {153, 204,204}, 109 {153, 153,204}, {153, 102,204}, {153, 51,204}, {153, 0,204}, 110 {153, 255,153}, {153, 204,153}, {153, 153,153}, {153, 102,153}, 111 {153, 51,153}, {153, 0,153}, {102, 255,255}, {102, 204,255}, 112 {102, 153,255}, {102, 102,255}, {102, 51,255}, {102, 0,255}, 113 {102, 255,204}, {102, 204,204}, {102, 153,204}, {102, 102,204}, 114 {102, 51,204}, {102, 0,204}, {102, 255,153}, {102, 204,153}, 115 {102, 153,153}, {102, 102,153}, {102, 51,153}, {102, 0,153}, 116 { 51, 255,255}, { 51, 204,255}, { 51, 153,255}, { 51, 102,255}, 117 { 51, 51,255}, { 51, 0,255}, { 51, 255,204}, { 51, 204,204}, 118 { 51, 153,204}, { 51, 102,204}, { 51, 51,204}, { 51, 0,204}, 119 { 51, 255,153}, { 51, 204,153}, { 51, 153,153}, { 51, 102,153}, 120 { 51, 51,153}, { 51, 0,153}, { 0, 255,255}, { 0, 204,255}, 121 { 0, 153,255}, { 0, 102,255}, { 0, 51,255}, { 0, 0,255}, 122 { 0, 255,204}, { 0, 204,204}, { 0, 153,204}, { 0, 102,204}, 123 { 0, 51,204}, { 0, 0,204}, { 0, 255,153}, { 0, 204,153}, 124 { 0, 153,153}, { 0, 102,153}, { 0, 51,153}, { 0, 0,153}, 125 {255, 255,102}, {255, 204,102}, {255, 153,102}, {255, 102,102}, 126 {255, 51,102}, {255, 0,102}, {255, 255, 51}, {255, 204, 51}, 127 {255, 153, 51}, {255, 102, 51}, {255, 51, 51}, {255, 0, 51}, 128 {255, 255, 0}, {255, 204, 0}, {255, 153, 0}, {255, 102, 0}, 129 {255, 51, 0}, {255, 0, 0}, {204, 255,102}, {204, 204,102}, 130 {204, 153,102}, {204, 102,102}, {204, 51,102}, {204, 0,102}, 131 {204, 255, 51}, {204, 204, 51}, {204, 153, 51}, {204, 102, 51}, 132 {204, 51, 51}, {204, 0, 51}, {204, 255, 0}, {204, 204, 0}, 133 {204, 153, 0}, {204, 102, 0}, {204, 51, 0}, {204, 0, 0}, 134 {153, 255,102}, {153, 204,102}, {153, 153,102}, {153, 102,102}, 135 {153, 51,102}, {153, 0,102}, {153, 255, 51}, {153, 204, 51}, 136 {153, 153, 51}, {153, 102, 51}, {153, 51, 51}, {153, 0, 51}, 137 {153, 255, 0}, {153, 204, 0}, {153, 153, 0}, {153, 102, 0}, 138 {153, 51, 0}, {153, 0, 0}, {102, 255,102}, {102, 204,102}, 139 {102, 153,102}, {102, 102,102}, {102, 51,102}, {102, 0,102}, 140 {102, 255, 51}, {102, 204, 51}, {102, 153, 51}, {102, 102, 51}, 141 {102, 51, 51}, {102, 0, 51}, {102, 255, 0}, {102, 204, 0}, 142 {102, 153, 0}, {102, 102, 0}, {102, 51, 0}, {102, 0, 0}, 143 { 51, 255,102}, { 51, 204,102}, { 51, 153,102}, { 51, 102,102}, 144 { 51, 51,102}, { 51, 0,102}, { 51, 255, 51}, { 51, 204, 51}, 145 { 51, 153, 51}, { 51, 102, 51}, { 51, 51, 51}, { 51, 0, 51}, 146 { 51, 255, 0}, { 51, 204, 0}, { 51, 153, 0}, { 51, 102, 0}, 147 { 51, 51, 0}, { 51, 0, 0}, { 0, 255,102}, { 0, 204,102}, 148 { 0, 153,102}, { 0, 102,102}, { 0, 51,102}, { 0, 0,102}, 149 { 0, 255, 51}, { 0, 204, 51}, { 0, 153, 51}, { 0, 102, 51}, 150 { 0, 51, 51}, { 0, 0, 51}, { 0, 255, 0}, { 0, 204, 0}, 151 { 0, 153, 0}, { 0, 102, 0}, { 0, 51, 0}, { 17, 17, 17}, 152 { 34, 34, 34}, { 68, 68, 68}, { 85, 85, 85}, {119, 119,119}, 153 {136, 136,136}, {170, 170,170}, {187, 187,187}, {221, 221,221}, 154 {238, 238,238}, {192, 192,192}, {128, 0, 0}, {128, 0,128}, 155 { 0, 128, 0}, { 0, 128,128}, { 0, 0, 0}, { 0, 0, 0}, 156 { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, 157 { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, 158 { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, 159 { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, 160 { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, 161 { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0} 162 }; 163 164 /* 166 Forward declarations. 167 */ 168 static MagickBooleanType 169 WritePALMImage(const ImageInfo *,Image *,ExceptionInfo *); 170 171 /* 173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 174 % % 175 % % 176 % % 177 % F i n d C o l o r % 178 % % 179 % % 180 % % 181 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 182 % 183 % FindColor() returns the index of the matching entry from PalmPalette for a 184 % given PixelInfo. 185 % 186 % The format of the FindColor method is: 187 % 188 % int FindColor(PixelInfo *pixel) 189 % 190 % A description of each parameter follows: 191 % 192 % o int: the index of the matching color or -1 if not found/ 193 % 194 % o pixel: a pointer to the PixelInfo to be matched. 195 % 196 */ 197 static ssize_t FindColor(PixelInfo *packet) 198 { 199 register ssize_t 200 i; 201 202 for (i=0; i < 256; i++) 203 if (ScaleQuantumToChar(ClampToQuantum(packet->red)) == PalmPalette[i][0] && 204 ScaleQuantumToChar(ClampToQuantum(packet->green)) == PalmPalette[i][1] && 205 ScaleQuantumToChar(ClampToQuantum(packet->blue)) == PalmPalette[i][2]) 206 return(i); 207 return(-1); 208 } 209 210 /* 212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 213 % % 214 % % 215 % % 216 % R e a d P A L M I m a g e % 217 % % 218 % % 219 % % 220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 221 % 222 % ReadPALMImage() reads an image of raw bites in LSB order and returns it. It 223 % allocates the memory necessary for the new Image structure and returns a 224 % pointer to the new image. 225 % 226 % The format of the ReadPALMImage method is: 227 % 228 % Image *ReadPALMImage(const ImageInfo *image_info, 229 % ExceptionInfo *exception) 230 % 231 % A description of each parameter follows: 232 % 233 % o image_info: Specifies a pointer to an ImageInfo structure. 234 % 235 % o exception: return any errors or warnings in this structure. 236 % 237 */ 238 static Image *ReadPALMImage(const ImageInfo *image_info, 239 ExceptionInfo *exception) 240 { 241 Image 242 *image; 243 244 MagickBooleanType 245 status; 246 247 MagickOffsetType 248 totalOffset, 249 seekNextDepth; 250 251 PixelInfo 252 transpix; 253 254 Quantum 255 index; 256 257 register ssize_t 258 i, 259 x; 260 261 register Quantum 262 *q; 263 264 size_t 265 bytes_per_row, 266 flags, 267 bits_per_pixel, 268 version, 269 nextDepthOffset, 270 transparentIndex, 271 compressionType, 272 byte, 273 mask, 274 redbits, 275 greenbits, 276 bluebits, 277 one, 278 pad, 279 size, 280 bit; 281 282 ssize_t 283 count, 284 y; 285 286 unsigned char 287 *lastrow, 288 *one_row, 289 *ptr; 290 291 unsigned short 292 color16; 293 294 /* 295 Open image file. 296 */ 297 assert(image_info != (const ImageInfo *) NULL); 298 assert(image_info->signature == MagickCoreSignature); 299 if (image_info->debug != MagickFalse) 300 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 301 image_info->filename); 302 assert(exception != (ExceptionInfo *) NULL); 303 assert(exception->signature == MagickCoreSignature); 304 image=AcquireImage(image_info,exception); 305 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 306 if (status == MagickFalse) 307 { 308 (void) DestroyImageList(image); 309 return((Image *) NULL); 310 } 311 totalOffset=0; 312 do 313 { 314 image->columns=ReadBlobMSBShort(image); 315 image->rows=ReadBlobMSBShort(image); 316 if (EOFBlob(image) != MagickFalse) 317 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 318 if ((image->columns == 0) || (image->rows == 0)) 319 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize"); 320 status=SetImageExtent(image,image->columns,image->rows,exception); 321 if (status == MagickFalse) 322 return(DestroyImageList(image)); 323 bytes_per_row=ReadBlobMSBShort(image); 324 flags=ReadBlobMSBShort(image); 325 bits_per_pixel=(size_t) ReadBlobByte(image); 326 if ((bits_per_pixel != 1) && (bits_per_pixel != 2) && 327 (bits_per_pixel != 4) && (bits_per_pixel != 8) && 328 (bits_per_pixel != 16)) 329 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel"); 330 version=(size_t) ReadBlobByte(image); 331 if ((version != 0) && (version != 1) && (version != 2)) 332 ThrowReaderException(CorruptImageError,"FileFormatVersionMismatch"); 333 nextDepthOffset=(size_t) ReadBlobMSBShort(image); 334 transparentIndex=(size_t) ReadBlobByte(image); 335 compressionType=(size_t) ReadBlobByte(image); 336 if ((compressionType != PALM_COMPRESSION_NONE) && 337 (compressionType != PALM_COMPRESSION_SCANLINE ) && 338 (compressionType != PALM_COMPRESSION_RLE)) 339 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression"); 340 pad=ReadBlobMSBShort(image); 341 (void) pad; 342 /* 343 Initialize image colormap. 344 */ 345 one=1; 346 if ((bits_per_pixel < 16) && 347 (AcquireImageColormap(image,one << bits_per_pixel,exception) == MagickFalse)) 348 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 349 GetPixelInfo(image,&transpix); 350 if (bits_per_pixel == 16) /* Direct Color */ 351 { 352 redbits=(size_t) ReadBlobByte(image); /* # of bits of red */ 353 (void) redbits; 354 greenbits=(size_t) ReadBlobByte(image); /* # of bits of green */ 355 (void) greenbits; 356 bluebits=(size_t) ReadBlobByte(image); /* # of bits of blue */ 357 (void) bluebits; 358 ReadBlobByte(image); /* reserved by Palm */ 359 ReadBlobByte(image); /* reserved by Palm */ 360 transpix.red=(double) (QuantumRange*ReadBlobByte(image)/31); 361 transpix.green=(double) (QuantumRange*ReadBlobByte(image)/63); 362 transpix.blue=(double) (QuantumRange*ReadBlobByte(image)/31); 363 } 364 if (bits_per_pixel == 8) 365 { 366 ssize_t 367 index; 368 369 if (flags & PALM_HAS_COLORMAP_FLAG) 370 { 371 count=(ssize_t) ReadBlobMSBShort(image); 372 for (i=0; i < (ssize_t) count; i++) 373 { 374 ReadBlobByte(image); 375 index=ConstrainColormapIndex(image,255-i,exception); 376 image->colormap[index].red=(MagickRealType) 377 ScaleCharToQuantum((unsigned char) ReadBlobByte(image)); 378 image->colormap[index].green=(MagickRealType) 379 ScaleCharToQuantum((unsigned char) ReadBlobByte(image)); 380 image->colormap[index].blue=(MagickRealType) 381 ScaleCharToQuantum((unsigned char) ReadBlobByte(image)); 382 } 383 } 384 else 385 for (i=0; i < (ssize_t) (1L << bits_per_pixel); i++) 386 { 387 index=ConstrainColormapIndex(image,255-i,exception); 388 image->colormap[index].red=(MagickRealType) 389 ScaleCharToQuantum(PalmPalette[i][0]); 390 image->colormap[index].green=(MagickRealType) 391 ScaleCharToQuantum(PalmPalette[i][1]); 392 image->colormap[index].blue=(MagickRealType) 393 ScaleCharToQuantum(PalmPalette[i][2]); 394 } 395 } 396 if (flags & PALM_IS_COMPRESSED_FLAG) 397 size=ReadBlobMSBShort(image); 398 (void) size; 399 image->storage_class=DirectClass; 400 if (bits_per_pixel < 16) 401 { 402 image->storage_class=PseudoClass; 403 image->depth=8; 404 } 405 if (image_info->ping != MagickFalse) 406 { 407 (void) CloseBlob(image); 408 return(image); 409 } 410 status=SetImageExtent(image,image->columns,image->rows,exception); 411 if (status == MagickFalse) 412 return(DestroyImageList(image)); 413 one_row=(unsigned char *) AcquireQuantumMemory(MagickMax(bytes_per_row, 414 2*image->columns),sizeof(*one_row)); 415 if (one_row == (unsigned char *) NULL) 416 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 417 lastrow=(unsigned char *) NULL; 418 if (compressionType == PALM_COMPRESSION_SCANLINE) { 419 lastrow=(unsigned char *) AcquireQuantumMemory(MagickMax(bytes_per_row, 420 2*image->columns),sizeof(*lastrow)); 421 if (lastrow == (unsigned char *) NULL) 422 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 423 } 424 mask=(size_t) (1U << bits_per_pixel)-1; 425 for (y=0; y < (ssize_t) image->rows; y++) 426 { 427 if ((flags & PALM_IS_COMPRESSED_FLAG) == 0) 428 { 429 /* TODO move out of loop! */ 430 image->compression=NoCompression; 431 count=ReadBlob(image,bytes_per_row,one_row); 432 if (count != (ssize_t) bytes_per_row) 433 break; 434 } 435 else 436 { 437 if (compressionType == PALM_COMPRESSION_RLE) 438 { 439 /* TODO move out of loop! */ 440 image->compression=RLECompression; 441 for (i=0; i < (ssize_t) bytes_per_row; ) 442 { 443 count=(ssize_t) ReadBlobByte(image); 444 if (count < 0) 445 break; 446 count=MagickMin(count,(ssize_t) bytes_per_row-i); 447 byte=(size_t) ReadBlobByte(image); 448 (void) ResetMagickMemory(one_row+i,(int) byte,(size_t) count); 449 i+=count; 450 } 451 } 452 else 453 if (compressionType == PALM_COMPRESSION_SCANLINE) 454 { 455 size_t 456 one; 457 458 /* TODO move out of loop! */ 459 one=1; 460 image->compression=FaxCompression; 461 for (i=0; i < (ssize_t) bytes_per_row; i+=8) 462 { 463 count=(ssize_t) ReadBlobByte(image); 464 if (count < 0) 465 break; 466 byte=(size_t) MagickMin((ssize_t) bytes_per_row-i,8); 467 for (bit=0; bit < byte; bit++) 468 { 469 if ((y == 0) || (count & (one << (7 - bit)))) 470 one_row[i+bit]=(unsigned char) ReadBlobByte(image); 471 else 472 one_row[i+bit]=lastrow[i+bit]; 473 } 474 } 475 (void) CopyMagickMemory(lastrow, one_row, bytes_per_row); 476 } 477 } 478 ptr=one_row; 479 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 480 if (q == (Quantum *) NULL) 481 break; 482 if (bits_per_pixel == 16) 483 { 484 if (image->columns > (2*bytes_per_row)) 485 ThrowReaderException(CorruptImageError,"CorruptImage"); 486 for (x=0; x < (ssize_t) image->columns; x++) 487 { 488 color16=(*ptr++ << 8); 489 color16|=(*ptr++); 490 SetPixelRed(image,(Quantum) ((QuantumRange*((color16 >> 11) & 491 0x1f))/0x1f),q); 492 SetPixelGreen(image,(Quantum) ((QuantumRange*((color16 >> 5) & 493 0x3f))/0x3f),q); 494 SetPixelBlue(image,(Quantum) ((QuantumRange*((color16 >> 0) & 495 0x1f))/0x1f),q); 496 SetPixelAlpha(image,OpaqueAlpha,q); 497 q+=GetPixelChannels(image); 498 } 499 } 500 else 501 { 502 bit=8-bits_per_pixel; 503 for (x=0; x < (ssize_t) image->columns; x++) 504 { 505 if ((size_t) (ptr-one_row) >= bytes_per_row) 506 ThrowReaderException(CorruptImageError,"CorruptImage"); 507 index=(Quantum) (mask-(((*ptr) & (mask << bit)) >> bit)); 508 SetPixelIndex(image,index,q); 509 SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q); 510 if (bit) 511 bit-=bits_per_pixel; 512 else 513 { 514 ptr++; 515 bit=8-bits_per_pixel; 516 } 517 q+=GetPixelChannels(image); 518 } 519 if (SyncAuthenticPixels(image,exception) == MagickFalse) 520 break; 521 } 522 if (image->previous == (Image *) NULL) 523 { 524 status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y, 525 image->rows); 526 if (status == MagickFalse) 527 break; 528 } 529 } 530 if (flags & PALM_HAS_TRANSPARENCY_FLAG) 531 { 532 ssize_t index=ConstrainColormapIndex(image,(ssize_t) (mask- 533 transparentIndex),exception); 534 if (bits_per_pixel != 16) 535 transpix=image->colormap[index]; 536 (void) TransparentPaintImage(image,&transpix,(Quantum) TransparentAlpha, 537 MagickFalse,exception); 538 } 539 one_row=(unsigned char *) RelinquishMagickMemory(one_row); 540 if (compressionType == PALM_COMPRESSION_SCANLINE) 541 lastrow=(unsigned char *) RelinquishMagickMemory(lastrow); 542 if (EOFBlob(image) != MagickFalse) 543 { 544 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 545 image->filename); 546 break; 547 } 548 /* 549 Proceed to next image. Copied from coders/pnm.c 550 */ 551 if (image_info->number_scenes != 0) 552 if (image->scene >= (image_info->scene+image_info->number_scenes-1)) 553 break; 554 if (nextDepthOffset != 0) 555 { 556 /* 557 Skip to next image. 558 */ 559 totalOffset+=(MagickOffsetType) (nextDepthOffset*4); 560 if (totalOffset >= (MagickOffsetType) GetBlobSize(image)) 561 ThrowReaderException(CorruptImageError,"ImproperImageHeader") 562 else 563 seekNextDepth=SeekBlob(image,totalOffset,SEEK_SET); 564 if (seekNextDepth != totalOffset) 565 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 566 /* 567 Allocate next image structure. Copied from coders/pnm.c 568 */ 569 AcquireNextImage(image_info,image,exception); 570 if (GetNextImageInList(image) == (Image *) NULL) 571 { 572 (void) DestroyImageList(image); 573 return((Image *) NULL); 574 } 575 image=SyncNextImageInList(image); 576 status=SetImageProgress(image,LoadImagesTag,TellBlob(image), 577 GetBlobSize(image)); 578 if (status == MagickFalse) 579 break; 580 } 581 } while (nextDepthOffset != 0); 582 (void) CloseBlob(image); 583 return(GetFirstImageInList(image)); 584 } 585 586 /* 588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 589 % % 590 % % 591 % % 592 % R e g i s t e r P A L M I m a g e % 593 % % 594 % % 595 % % 596 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 597 % 598 % RegisterPALMImage() adds properties for the PALM image format to the list of 599 % supported formats. The properties include the image format tag, a method to 600 % read and/or write the format, whether the format supports the saving of more 601 % than one frame to the same file or blob, whether the format supports native 602 % in-memory I/O, and a brief description of the format. 603 % 604 % The format of the RegisterPALMImage method is: 605 % 606 % size_t RegisterPALMImage(void) 607 % 608 */ 609 ModuleExport size_t RegisterPALMImage(void) 610 { 611 MagickInfo 612 *entry; 613 614 entry=AcquireMagickInfo("PALM","PALM","Palm pixmap"); 615 entry->decoder=(DecodeImageHandler *) ReadPALMImage; 616 entry->encoder=(EncodeImageHandler *) WritePALMImage; 617 entry->flags|=CoderSeekableStreamFlag; 618 (void) RegisterMagickInfo(entry); 619 return(MagickImageCoderSignature); 620 } 621 622 /* 624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 625 % % 626 % % 627 % % 628 % U n r e g i s t e r P A L M I m a g e % 629 % % 630 % % 631 % % 632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 633 % 634 % UnregisterPALMImage() removes format registrations made by the PALM 635 % module from the list of supported formats. 636 % 637 % The format of the UnregisterPALMImage method is: 638 % 639 % UnregisterPALMImage(void) 640 % 641 */ 642 ModuleExport void UnregisterPALMImage(void) 643 { 644 (void) UnregisterMagickInfo("PALM"); 645 } 646 647 /* 649 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 650 % % 651 % % 652 % % 653 % W r i t e P A L M I m a g e % 654 % % 655 % % 656 % % 657 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 658 % 659 % WritePALMImage() writes an image of raw bits in LSB order to a file. 660 % 661 % The format of the WritePALMImage method is: 662 % 663 % MagickBooleanType WritePALMImage(const ImageInfo *image_info, 664 % Image *image,ExceptionInfo *exception) 665 % 666 % A description of each parameter follows. 667 % 668 % o image_info: Specifies a pointer to an ImageInfo structure. 669 % 670 % o image: A pointer to a Image structure. 671 % 672 % o exception: return any errors or warnings in this structure. 673 % 674 */ 675 static MagickBooleanType WritePALMImage(const ImageInfo *image_info, 676 Image *image,ExceptionInfo *exception) 677 { 678 MagickBooleanType 679 status; 680 681 MagickOffsetType 682 currentOffset, 683 offset, 684 scene; 685 686 MagickSizeType 687 cc; 688 689 PixelInfo 690 transpix; 691 692 QuantizeInfo 693 *quantize_info; 694 695 register ssize_t 696 x; 697 698 register const Quantum 699 *p; 700 701 register Quantum 702 *q; 703 704 ssize_t 705 y; 706 707 size_t 708 count, 709 bits_per_pixel, 710 bytes_per_row, 711 nextDepthOffset, 712 one; 713 714 unsigned char 715 bit, 716 byte, 717 color, 718 *lastrow, 719 *one_row, 720 *ptr, 721 version; 722 723 unsigned int 724 transparentIndex; 725 726 unsigned short 727 color16, 728 flags; 729 730 /* 731 Open output image file. 732 */ 733 assert(image_info != (const ImageInfo *) NULL); 734 assert(image_info->signature == MagickCoreSignature); 735 assert(image != (Image *) NULL); 736 assert(image->signature == MagickCoreSignature); 737 if (image->debug != MagickFalse) 738 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 739 assert(exception != (ExceptionInfo *) NULL); 740 assert(exception->signature == MagickCoreSignature); 741 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 742 if (status == MagickFalse) 743 return(status); 744 quantize_info=AcquireQuantizeInfo(image_info); 745 flags=0; 746 currentOffset=0; 747 transparentIndex=0; 748 transpix.red=0.0; 749 transpix.green=0.0; 750 transpix.blue=0.0; 751 transpix.alpha=0.0; 752 one=1; 753 version=0; 754 scene=0; 755 do 756 { 757 (void) TransformImageColorspace(image,sRGBColorspace,exception); 758 count=GetNumberColors(image,NULL,exception); 759 for (bits_per_pixel=1; (one << bits_per_pixel) < count; bits_per_pixel*=2) ; 760 if (image_info->depth > 100) 761 bits_per_pixel=image_info->depth-100; 762 if (bits_per_pixel < 16) 763 (void) TransformImageColorspace(image,image->colorspace,exception); 764 if (bits_per_pixel < 8) 765 { 766 (void) TransformImageColorspace(image,GRAYColorspace,exception); 767 (void) SetImageType(image,PaletteType,exception); 768 (void) SortColormapByIntensity(image,exception); 769 } 770 if ((image->storage_class == PseudoClass) && (image->colors > 256)) 771 (void) SetImageStorageClass(image,DirectClass,exception); 772 if (image->storage_class == PseudoClass) 773 flags|=PALM_HAS_COLORMAP_FLAG; 774 else 775 flags|=PALM_IS_DIRECT_COLOR; 776 (void) WriteBlobMSBShort(image,(unsigned short) image->columns); /* width */ 777 (void) WriteBlobMSBShort(image,(unsigned short) image->rows); /* height */ 778 bytes_per_row=((image->columns+(16/bits_per_pixel-1))/(16/ 779 bits_per_pixel))*2; 780 (void) WriteBlobMSBShort(image,(unsigned short) bytes_per_row); 781 if ((image_info->compression == RLECompression) || 782 (image_info->compression == FaxCompression)) 783 flags|=PALM_IS_COMPRESSED_FLAG; 784 (void) WriteBlobMSBShort(image, flags); 785 (void) WriteBlobByte(image,(unsigned char) bits_per_pixel); 786 if (bits_per_pixel > 1) 787 version=1; 788 if ((image_info->compression == RLECompression) || 789 (image_info->compression == FaxCompression)) 790 version=2; 791 (void) WriteBlobByte(image,version); 792 (void) WriteBlobMSBShort(image,0); /* nextDepthOffset */ 793 (void) WriteBlobByte(image,(unsigned char) transparentIndex); 794 if (image_info->compression == RLECompression) 795 (void) WriteBlobByte(image,PALM_COMPRESSION_RLE); 796 else 797 if (image_info->compression == FaxCompression) 798 (void) WriteBlobByte(image,PALM_COMPRESSION_SCANLINE); 799 else 800 (void) WriteBlobByte(image,PALM_COMPRESSION_NONE); 801 (void) WriteBlobMSBShort(image,0); /* reserved */ 802 offset=16; 803 if (bits_per_pixel == 16) 804 { 805 (void) WriteBlobByte(image,5); /* # of bits of red */ 806 (void) WriteBlobByte(image,6); /* # of bits of green */ 807 (void) WriteBlobByte(image,5); /* # of bits of blue */ 808 (void) WriteBlobByte(image,0); /* reserved by Palm */ 809 (void) WriteBlobMSBLong(image,0); /* no transparent color, YET */ 810 offset+=8; 811 } 812 if (bits_per_pixel == 8) 813 { 814 if (flags & PALM_HAS_COLORMAP_FLAG) /* Write out colormap */ 815 { 816 quantize_info->dither_method=IdentifyPaletteImage(image,exception) 817 == MagickFalse ? RiemersmaDitherMethod : NoDitherMethod; 818 quantize_info->number_colors=image->colors; 819 (void) QuantizeImage(quantize_info,image,exception); 820 (void) WriteBlobMSBShort(image,(unsigned short) image->colors); 821 for (count = 0; count < image->colors; count++) 822 { 823 (void) WriteBlobByte(image,(unsigned char) count); 824 (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum( 825 image->colormap[count].red))); 826 (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum( 827 image->colormap[count].green))); 828 (void) WriteBlobByte(image,ScaleQuantumToChar(ClampToQuantum( 829 image->colormap[count].blue))); 830 } 831 offset+=2+count*4; 832 } 833 else /* Map colors to Palm standard colormap */ 834 { 835 Image 836 *affinity_image; 837 838 affinity_image=ConstituteImage(256,1,"RGB",CharPixel,&PalmPalette, 839 exception); 840 (void) TransformImageColorspace(affinity_image, 841 affinity_image->colorspace,exception); 842 (void) RemapImage(quantize_info,image,affinity_image,exception); 843 for (y=0; y < (ssize_t) image->rows; y++) 844 { 845 q=GetAuthenticPixels(image,0,y,image->columns,1,exception); 846 if (q == (Quantum *) NULL) 847 break; 848 for (x=0; x < (ssize_t) image->columns; x++) 849 { 850 SetPixelIndex(image,(Quantum) FindColor(&image->colormap[(ssize_t) 851 GetPixelIndex(image,q)]),q); 852 q+=GetPixelChannels(image); 853 } 854 } 855 affinity_image=DestroyImage(affinity_image); 856 } 857 } 858 if (flags & PALM_IS_COMPRESSED_FLAG) 859 (void) WriteBlobMSBShort(image,0); /* fill in size later */ 860 lastrow=(unsigned char *) NULL; 861 if (image_info->compression == FaxCompression) 862 lastrow=(unsigned char *) AcquireQuantumMemory(bytes_per_row, 863 sizeof(*lastrow)); 864 /* TODO check whether memory really was acquired? */ 865 one_row=(unsigned char *) AcquireQuantumMemory(bytes_per_row, 866 sizeof(*one_row)); 867 if (one_row == (unsigned char *) NULL) 868 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 869 for (y=0; y < (ssize_t) image->rows; y++) 870 { 871 ptr=one_row; 872 (void) ResetMagickMemory(ptr,0,bytes_per_row); 873 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 874 if (p == (const Quantum *) NULL) 875 break; 876 if (bits_per_pixel == 16) 877 { 878 for (x=0; x < (ssize_t) image->columns; x++) 879 { 880 color16=(unsigned short) ((((31*(size_t) GetPixelRed(image,p))/ 881 (size_t) QuantumRange) << 11) | (((63*(size_t) 882 GetPixelGreen(image,p))/(size_t) QuantumRange) << 5) | 883 ((31*(size_t) GetPixelBlue(image,p))/(size_t) QuantumRange)); 884 if (GetPixelAlpha(image,p) == (Quantum) TransparentAlpha) 885 { 886 transpix.red=(MagickRealType) GetPixelRed(image,p); 887 transpix.green=(MagickRealType) GetPixelGreen(image,p); 888 transpix.blue=(MagickRealType) GetPixelBlue(image,p); 889 transpix.alpha=(MagickRealType) GetPixelAlpha(image,p); 890 flags|=PALM_HAS_TRANSPARENCY_FLAG; 891 } 892 *ptr++=(unsigned char) ((color16 >> 8) & 0xff); 893 *ptr++=(unsigned char) (color16 & 0xff); 894 p+=GetPixelChannels(image); 895 } 896 } 897 else 898 { 899 byte=0x00; 900 bit=(unsigned char) (8-bits_per_pixel); 901 for (x=0; x < (ssize_t) image->columns; x++) 902 { 903 if (bits_per_pixel >= 8) 904 color=(unsigned char) GetPixelIndex(image,p); 905 else 906 color=(unsigned char) (GetPixelIndex(image,p)* 907 ((one << bits_per_pixel)-1)/MagickMax(1*image->colors-1,1)); 908 byte|=color << bit; 909 if (bit != 0) 910 bit-=(unsigned char) bits_per_pixel; 911 else 912 { 913 *ptr++=byte; 914 byte=0x00; 915 bit=(unsigned char) (8-bits_per_pixel); 916 } 917 p+=GetPixelChannels(image); 918 } 919 if ((image->columns % (8/bits_per_pixel)) != 0) 920 *ptr++=byte; 921 } 922 if (image_info->compression == RLECompression) 923 { 924 x=0; 925 while (x < (ssize_t) bytes_per_row) 926 { 927 byte=one_row[x]; 928 count=1; 929 while ((one_row[++x] == byte) && (count < 255) && 930 (x < (ssize_t) bytes_per_row)) 931 count++; 932 (void) WriteBlobByte(image,(unsigned char) count); 933 (void) WriteBlobByte(image,(unsigned char) byte); 934 } 935 } 936 else 937 if (image_info->compression == FaxCompression) 938 { 939 char 940 tmpbuf[8], 941 *tptr; 942 943 for (x = 0; x < (ssize_t) bytes_per_row; x += 8) 944 { 945 tptr = tmpbuf; 946 for (bit=0, byte=0; bit < (unsigned char) MagickMin(8,(ssize_t) bytes_per_row-x); bit++) 947 { 948 if ((y == 0) || (lastrow[x + bit] != one_row[x + bit])) 949 { 950 byte |= (1 << (7 - bit)); 951 *tptr++ = (char) one_row[x + bit]; 952 } 953 } 954 (void) WriteBlobByte(image, byte); 955 (void) WriteBlob(image,tptr-tmpbuf,(unsigned char *) tmpbuf); 956 } 957 (void) CopyMagickMemory(lastrow,one_row,bytes_per_row); 958 } 959 else 960 (void) WriteBlob(image,bytes_per_row,one_row); 961 } 962 if (flags & PALM_HAS_TRANSPARENCY_FLAG) 963 { 964 offset=SeekBlob(image,currentOffset+6,SEEK_SET); 965 (void) WriteBlobMSBShort(image,flags); 966 offset=SeekBlob(image,currentOffset+12,SEEK_SET); 967 (void) WriteBlobByte(image,(unsigned char) transparentIndex); /* trans index */ 968 } 969 if (bits_per_pixel == 16) 970 { 971 offset=SeekBlob(image,currentOffset+20,SEEK_SET); 972 (void) WriteBlobByte(image,0); /* reserved by Palm */ 973 (void) WriteBlobByte(image,(unsigned char) ((31*transpix.red)/QuantumRange)); 974 (void) WriteBlobByte(image,(unsigned char) ((63*transpix.green)/QuantumRange)); 975 (void) WriteBlobByte(image,(unsigned char) ((31*transpix.blue)/QuantumRange)); 976 } 977 if (flags & PALM_IS_COMPRESSED_FLAG) /* fill in size now */ 978 { 979 offset=SeekBlob(image,currentOffset+offset,SEEK_SET); 980 (void) WriteBlobMSBShort(image,(unsigned short) (GetBlobSize(image)- 981 currentOffset-offset)); 982 } 983 if (one_row != (unsigned char *) NULL) 984 one_row=(unsigned char *) RelinquishMagickMemory(one_row); 985 if (lastrow != (unsigned char *) NULL) 986 lastrow=(unsigned char *) RelinquishMagickMemory(lastrow); 987 if (GetNextImageInList(image) == (Image *) NULL) 988 break; 989 /* padding to 4 byte word */ 990 for (cc=(GetBlobSize(image)) % 4; cc > 0; cc--) 991 (void) WriteBlobByte(image,0); 992 /* write nextDepthOffset and return to end of image */ 993 offset=SeekBlob(image,currentOffset+10,SEEK_SET); 994 nextDepthOffset=(size_t) ((GetBlobSize(image)-currentOffset)/4); 995 (void) WriteBlobMSBShort(image,(unsigned short) nextDepthOffset); 996 currentOffset=(MagickOffsetType) GetBlobSize(image); 997 offset=SeekBlob(image,currentOffset,SEEK_SET); 998 image=SyncNextImageInList(image); 999 status=SetImageProgress(image,SaveImagesTag,scene++, 1000 GetImageListLength(image)); 1001 if (status == MagickFalse) 1002 break; 1003 } while (image_info->adjoin != MagickFalse); 1004 quantize_info=DestroyQuantizeInfo(quantize_info); 1005 (void) CloseBlob(image); 1006 return(MagickTrue); 1007 } 1008