1/* 2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3% % 4% % 5% % 6% DDDD IIIII BBBB % 7% D D I B B % 8% D D I BBBB % 9% D D I B B % 10% DDDD IIIII BBBB % 11% % 12% % 13% Read/Write Windows DIB 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/attribute.h" 44#include "MagickCore/blob.h" 45#include "MagickCore/blob-private.h" 46#include "MagickCore/cache.h" 47#include "MagickCore/color.h" 48#include "MagickCore/color-private.h" 49#include "MagickCore/colormap.h" 50#include "MagickCore/colormap-private.h" 51#include "MagickCore/colorspace.h" 52#include "MagickCore/colorspace-private.h" 53#include "MagickCore/draw.h" 54#include "MagickCore/exception.h" 55#include "MagickCore/exception-private.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/log.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/pixel-accessor.h" 66#include "MagickCore/quantum-private.h" 67#include "MagickCore/static.h" 68#include "MagickCore/string_.h" 69#include "MagickCore/module.h" 70#include "MagickCore/transform.h" 71 72/* 73 Typedef declarations. 74*/ 75typedef struct _DIBInfo 76{ 77 size_t 78 size; 79 80 ssize_t 81 width, 82 height; 83 84 unsigned short 85 planes, 86 bits_per_pixel; 87 88 size_t 89 compression, 90 image_size, 91 x_pixels, 92 y_pixels, 93 number_colors, 94 red_mask, 95 green_mask, 96 blue_mask, 97 alpha_mask, 98 colors_important; 99 100 ssize_t 101 colorspace; 102 103 PointInfo 104 red_primary, 105 green_primary, 106 blue_primary, 107 gamma_scale; 108} DIBInfo; 109 110/* 111 Forward declarations. 112*/ 113static MagickBooleanType 114 WriteDIBImage(const ImageInfo *,Image *,ExceptionInfo *); 115 116/* 117%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 118% % 119% % 120% % 121% D e c o d e I m a g e % 122% % 123% % 124% % 125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 126% 127% DecodeImage unpacks the packed image pixels into runlength-encoded 128% pixel packets. 129% 130% The format of the DecodeImage method is: 131% 132% MagickBooleanType DecodeImage(Image *image, 133% const MagickBooleanType compression,unsigned char *pixels) 134% 135% A description of each parameter follows: 136% 137% o image: the address of a structure of type Image. 138% 139% o compression: A value of 1 means the compressed pixels are runlength 140% encoded for a 256-color bitmap. A value of 2 means a 16-color bitmap. 141% 142% o pixels: The address of a byte (8 bits) array of pixel data created by 143% the decoding process. 144% 145*/ 146static MagickBooleanType DecodeImage(Image *image, 147 const MagickBooleanType compression,unsigned char *pixels) 148{ 149#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__) || defined(__MINGW64__) 150#define BI_RGB 0 151#define BI_RLE8 1 152#define BI_RLE4 2 153#define BI_BITFIELDS 3 154#undef BI_JPEG 155#define BI_JPEG 4 156#undef BI_PNG 157#define BI_PNG 5 158#endif 159 160 int 161 count; 162 163 ssize_t 164 y; 165 166 register ssize_t 167 i, 168 x; 169 170 register unsigned char 171 *p, 172 *q; 173 174 unsigned char 175 byte; 176 177 assert(image != (Image *) NULL); 178 assert(image->signature == MagickCoreSignature); 179 if (image->debug != MagickFalse) 180 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 181 assert(pixels != (unsigned char *) NULL); 182 (void) ResetMagickMemory(pixels,0,(size_t) image->columns*image->rows* 183 sizeof(*pixels)); 184 byte=0; 185 x=0; 186 p=pixels; 187 q=pixels+(size_t) image->columns*image->rows; 188 for (y=0; y < (ssize_t) image->rows; ) 189 { 190 if ((p < pixels) || (p >= q)) 191 break; 192 count=ReadBlobByte(image); 193 if (count == EOF) 194 break; 195 if (count != 0) 196 { 197 count=(int) MagickMin((size_t) count,(size_t) (q-p)); 198 /* 199 Encoded mode. 200 */ 201 byte=(unsigned char) ReadBlobByte(image); 202 if (compression == BI_RLE8) 203 { 204 for (i=0; i < count; i++) 205 *p++=(unsigned char) byte; 206 } 207 else 208 { 209 for (i=0; i < count; i++) 210 *p++=(unsigned char) 211 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f)); 212 } 213 x+=count; 214 } 215 else 216 { 217 /* 218 Escape mode. 219 */ 220 count=ReadBlobByte(image); 221 if (count == 0x01) 222 return(MagickTrue); 223 switch (count) 224 { 225 case 0x00: 226 { 227 /* 228 End of line. 229 */ 230 x=0; 231 y++; 232 p=pixels+y*image->columns; 233 break; 234 } 235 case 0x02: 236 { 237 /* 238 Delta mode. 239 */ 240 x+=ReadBlobByte(image); 241 y+=ReadBlobByte(image); 242 p=pixels+y*image->columns+x; 243 break; 244 } 245 default: 246 { 247 /* 248 Absolute mode. 249 */ 250 count=(int) MagickMin((size_t) count,(size_t) (q-p)); 251 if (compression == BI_RLE8) 252 for (i=0; i < count; i++) 253 *p++=(unsigned char) ReadBlobByte(image); 254 else 255 for (i=0; i < count; i++) 256 { 257 if ((i & 0x01) == 0) 258 byte=(unsigned char) ReadBlobByte(image); 259 *p++=(unsigned char) 260 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f)); 261 } 262 x+=count; 263 /* 264 Read pad byte. 265 */ 266 if (compression == BI_RLE8) 267 { 268 if ((count & 0x01) != 0) 269 (void) ReadBlobByte(image); 270 } 271 else 272 if (((count & 0x03) == 1) || ((count & 0x03) == 2)) 273 (void) ReadBlobByte(image); 274 break; 275 } 276 } 277 } 278 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse) 279 break; 280 } 281 (void) ReadBlobByte(image); /* end of line */ 282 (void) ReadBlobByte(image); 283 return(MagickTrue); 284} 285 286/* 287%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 288% % 289% % 290% % 291% E n c o d e I m a g e % 292% % 293% % 294% % 295%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 296% 297% EncodeImage compresses pixels using a runlength encoded format. 298% 299% The format of the EncodeImage method is: 300% 301% static MagickBooleanType EncodeImage(Image *image, 302% const size_t bytes_per_line,const unsigned char *pixels, 303% unsigned char *compressed_pixels) 304% 305% A description of each parameter follows: 306% 307% o image: The image. 308% 309% o bytes_per_line: the number of bytes in a scanline of compressed pixels 310% 311% o pixels: The address of a byte (8 bits) array of pixel data created by 312% the compression process. 313% 314% o compressed_pixels: The address of a byte (8 bits) array of compressed 315% pixel data. 316% 317*/ 318static size_t EncodeImage(Image *image,const size_t bytes_per_line, 319 const unsigned char *pixels,unsigned char *compressed_pixels) 320{ 321 ssize_t 322 y; 323 324 register const unsigned char 325 *p; 326 327 register ssize_t 328 i, 329 x; 330 331 register unsigned char 332 *q; 333 334 /* 335 Runlength encode pixels. 336 */ 337 assert(image != (Image *) NULL); 338 assert(image->signature == MagickCoreSignature); 339 if (image->debug != MagickFalse) 340 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 341 assert(pixels != (const unsigned char *) NULL); 342 assert(compressed_pixels != (unsigned char *) NULL); 343 p=pixels; 344 q=compressed_pixels; 345 i=0; 346 for (y=0; y < (ssize_t) image->rows; y++) 347 { 348 for (x=0; x < (ssize_t) bytes_per_line; x+=i) 349 { 350 /* 351 Determine runlength. 352 */ 353 for (i=1; ((x+i) < (ssize_t) bytes_per_line); i++) 354 if ((*(p+i) != *p) || (i == 255)) 355 break; 356 *q++=(unsigned char) i; 357 *q++=(*p); 358 p+=i; 359 } 360 /* 361 End of line. 362 */ 363 *q++=0x00; 364 *q++=0x00; 365 if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse) 366 break; 367 } 368 /* 369 End of bitmap. 370 */ 371 *q++=0; 372 *q++=0x01; 373 return((size_t) (q-compressed_pixels)); 374} 375 376/* 377%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 378% % 379% % 380% % 381% I s D I B % 382% % 383% % 384% % 385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 386% 387% IsDIB() returns MagickTrue if the image format type, identified by the 388% magick string, is DIB. 389% 390% The format of the IsDIB method is: 391% 392% MagickBooleanType IsDIB(const unsigned char *magick,const size_t length) 393% 394% A description of each parameter follows: 395% 396% o magick: compare image format pattern against these bytes. 397% 398% o length: Specifies the length of the magick string. 399% 400*/ 401static MagickBooleanType IsDIB(const unsigned char *magick,const size_t length) 402{ 403 if (length < 2) 404 return(MagickFalse); 405 if (memcmp(magick,"\050\000",2) == 0) 406 return(MagickTrue); 407 return(MagickFalse); 408} 409 410/* 411%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 412% % 413% % 414% % 415% R e a d D I B I m a g e % 416% % 417% % 418% % 419%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 420% 421% ReadDIBImage() reads a Microsoft Windows bitmap image file and 422% returns it. It allocates the memory necessary for the new Image structure 423% and returns a pointer to the new image. 424% 425% The format of the ReadDIBImage method is: 426% 427% image=ReadDIBImage(image_info) 428% 429% A description of each parameter follows: 430% 431% o image_info: the image info. 432% 433% o exception: return any errors or warnings in this structure. 434% 435*/ 436static Image *ReadDIBImage(const ImageInfo *image_info,ExceptionInfo *exception) 437{ 438 DIBInfo 439 dib_info; 440 441 Image 442 *image; 443 444 MagickBooleanType 445 status; 446 447 MemoryInfo 448 *pixel_info; 449 450 Quantum 451 index; 452 453 register ssize_t 454 x; 455 456 register Quantum 457 *q; 458 459 register ssize_t 460 i; 461 462 register unsigned char 463 *p; 464 465 size_t 466 bytes_per_line, 467 length; 468 469 ssize_t 470 bit, 471 count, 472 y; 473 474 475 unsigned char 476 *pixels; 477 478 /* 479 Open image file. 480 */ 481 assert(image_info != (const ImageInfo *) NULL); 482 assert(image_info->signature == MagickCoreSignature); 483 if (image_info->debug != MagickFalse) 484 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s", 485 image_info->filename); 486 assert(exception != (ExceptionInfo *) NULL); 487 assert(exception->signature == MagickCoreSignature); 488 image=AcquireImage(image_info,exception); 489 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception); 490 if (status == MagickFalse) 491 { 492 image=DestroyImageList(image); 493 return((Image *) NULL); 494 } 495 /* 496 Determine if this a DIB file. 497 */ 498 (void) ResetMagickMemory(&dib_info,0,sizeof(dib_info)); 499 dib_info.size=ReadBlobLSBLong(image); 500 if (dib_info.size != 40) 501 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 502 /* 503 Microsoft Windows 3.X DIB image file. 504 */ 505 dib_info.width=ReadBlobLSBSignedLong(image); 506 dib_info.height=ReadBlobLSBSignedLong(image); 507 dib_info.planes=ReadBlobLSBShort(image); 508 dib_info.bits_per_pixel=ReadBlobLSBShort(image); 509 if (dib_info.bits_per_pixel > 32) 510 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 511 dib_info.compression=ReadBlobLSBLong(image); 512 dib_info.image_size=ReadBlobLSBLong(image); 513 dib_info.x_pixels=ReadBlobLSBLong(image); 514 dib_info.y_pixels=ReadBlobLSBLong(image); 515 dib_info.number_colors=ReadBlobLSBLong(image); 516 dib_info.colors_important=ReadBlobLSBLong(image); 517 if ((dib_info.bits_per_pixel != 1) && (dib_info.bits_per_pixel != 4) && 518 (dib_info.bits_per_pixel != 8) && (dib_info.bits_per_pixel != 16) && 519 (dib_info.bits_per_pixel != 24) && (dib_info.bits_per_pixel != 32)) 520 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 521 if ((dib_info.compression == BI_BITFIELDS) && 522 ((dib_info.bits_per_pixel == 16) || (dib_info.bits_per_pixel == 32))) 523 { 524 dib_info.red_mask=ReadBlobLSBLong(image); 525 dib_info.green_mask=ReadBlobLSBLong(image); 526 dib_info.blue_mask=ReadBlobLSBLong(image); 527 } 528 if (EOFBlob(image) != MagickFalse) 529 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile"); 530 if (dib_info.width <= 0) 531 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize"); 532 if (dib_info.height == 0) 533 ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize"); 534 if (dib_info.planes != 1) 535 ThrowReaderException(CorruptImageError,"StaticPlanesValueNotEqualToOne"); 536 if ((dib_info.bits_per_pixel != 1) && (dib_info.bits_per_pixel != 4) && 537 (dib_info.bits_per_pixel != 8) && (dib_info.bits_per_pixel != 16) && 538 (dib_info.bits_per_pixel != 24) && (dib_info.bits_per_pixel != 32)) 539 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel"); 540 if (dib_info.bits_per_pixel < 16 && 541 dib_info.number_colors > (size_t) (1UL << dib_info.bits_per_pixel)) 542 ThrowReaderException(CorruptImageError,"UnrecognizedNumberOfColors"); 543 if ((dib_info.compression == 1) && (dib_info.bits_per_pixel != 8)) 544 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel"); 545 if ((dib_info.compression == 2) && (dib_info.bits_per_pixel != 4)) 546 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel"); 547 if ((dib_info.compression == 3) && (dib_info.bits_per_pixel < 16)) 548 ThrowReaderException(CorruptImageError,"UnrecognizedBitsPerPixel"); 549 switch (dib_info.compression) 550 { 551 case BI_RGB: 552 case BI_RLE8: 553 case BI_RLE4: 554 case BI_BITFIELDS: 555 break; 556 case BI_JPEG: 557 ThrowReaderException(CoderError,"JPEGCompressNotSupported"); 558 case BI_PNG: 559 ThrowReaderException(CoderError,"PNGCompressNotSupported"); 560 default: 561 ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression"); 562 } 563 image->columns=(size_t) MagickAbsoluteValue(dib_info.width); 564 image->rows=(size_t) MagickAbsoluteValue(dib_info.height); 565 image->depth=8; 566 image->alpha_trait=dib_info.bits_per_pixel == 32 ? BlendPixelTrait : 567 UndefinedPixelTrait; 568 if ((dib_info.number_colors > 256) || (dib_info.colors_important > 256)) 569 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 570 if ((dib_info.number_colors != 0) || (dib_info.bits_per_pixel < 16)) 571 { 572 size_t 573 one; 574 575 image->storage_class=PseudoClass; 576 image->colors=dib_info.number_colors; 577 one=1; 578 if (image->colors == 0) 579 image->colors=one << dib_info.bits_per_pixel; 580 } 581 if (image_info->size) 582 { 583 RectangleInfo 584 geometry; 585 586 MagickStatusType 587 flags; 588 589 flags=ParseAbsoluteGeometry(image_info->size,&geometry); 590 if (flags & WidthValue) 591 if ((geometry.width != 0) && (geometry.width < image->columns)) 592 image->columns=geometry.width; 593 if (flags & HeightValue) 594 if ((geometry.height != 0) && (geometry.height < image->rows)) 595 image->rows=geometry.height; 596 } 597 status=SetImageExtent(image,image->columns,image->rows,exception); 598 if (status == MagickFalse) 599 return(DestroyImageList(image)); 600 if (image->storage_class == PseudoClass) 601 { 602 size_t 603 length, 604 packet_size; 605 606 unsigned char 607 *dib_colormap; 608 609 /* 610 Read DIB raster colormap. 611 */ 612 if (AcquireImageColormap(image,image->colors,exception) == MagickFalse) 613 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 614 length=(size_t) image->colors; 615 dib_colormap=(unsigned char *) AcquireQuantumMemory(length, 616 4*sizeof(*dib_colormap)); 617 if (dib_colormap == (unsigned char *) NULL) 618 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 619 packet_size=4; 620 count=ReadBlob(image,packet_size*image->colors,dib_colormap); 621 if (count != (ssize_t) (packet_size*image->colors)) 622 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); 623 p=dib_colormap; 624 for (i=0; i < (ssize_t) image->colors; i++) 625 { 626 image->colormap[i].blue=ScaleCharToQuantum(*p++); 627 image->colormap[i].green=ScaleCharToQuantum(*p++); 628 image->colormap[i].red=ScaleCharToQuantum(*p++); 629 if (packet_size == 4) 630 p++; 631 } 632 dib_colormap=(unsigned char *) RelinquishMagickMemory(dib_colormap); 633 } 634 /* 635 Read image data. 636 */ 637 if (dib_info.compression == BI_RLE4) 638 dib_info.bits_per_pixel<<=1; 639 bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32); 640 length=bytes_per_line*image->rows; 641 pixel_info=AcquireVirtualMemory((size_t) image->rows,MagickMax( 642 bytes_per_line,image->columns+256UL)*sizeof(*pixels)); 643 if (pixel_info == (MemoryInfo *) NULL) 644 ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed"); 645 pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info); 646 if ((dib_info.compression == BI_RGB) || 647 (dib_info.compression == BI_BITFIELDS)) 648 { 649 count=ReadBlob(image,length,pixels); 650 if (count != (ssize_t) (length)) 651 ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile"); 652 } 653 else 654 { 655 /* 656 Convert run-length encoded raster pixels. 657 */ 658 status=DecodeImage(image,dib_info.compression ? MagickTrue : MagickFalse, 659 pixels); 660 if (status == MagickFalse) 661 ThrowReaderException(CorruptImageError,"UnableToRunlengthDecodeImage"); 662 } 663 /* 664 Initialize image structure. 665 */ 666 image->units=PixelsPerCentimeterResolution; 667 image->resolution.x=(double) dib_info.x_pixels/100.0; 668 image->resolution.y=(double) dib_info.y_pixels/100.0; 669 /* 670 Convert DIB raster image to pixel packets. 671 */ 672 switch (dib_info.bits_per_pixel) 673 { 674 case 1: 675 { 676 /* 677 Convert bitmap scanline. 678 */ 679 for (y=(ssize_t) image->rows-1; y >= 0; y--) 680 { 681 p=pixels+(image->rows-y-1)*bytes_per_line; 682 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 683 if (q == (Quantum *) NULL) 684 break; 685 for (x=0; x < ((ssize_t) image->columns-7); x+=8) 686 { 687 for (bit=0; bit < 8; bit++) 688 { 689 index=(Quantum) ((*p) & (0x80 >> bit) ? 0x01 : 0x00); 690 SetPixelIndex(image,index,q); 691 q+=GetPixelChannels(image); 692 } 693 p++; 694 } 695 if ((image->columns % 8) != 0) 696 { 697 for (bit=0; bit < (ssize_t) (image->columns % 8); bit++) 698 { 699 index=(Quantum) ((*p) & (0x80 >> bit) ? 0x01 : 0x00); 700 SetPixelIndex(image,index,q); 701 q+=GetPixelChannels(image); 702 } 703 p++; 704 } 705 if (SyncAuthenticPixels(image,exception) == MagickFalse) 706 break; 707 if (image->previous == (Image *) NULL) 708 { 709 status=SetImageProgress(image,LoadImageTag,image->rows-y-1, 710 image->rows); 711 if (status == MagickFalse) 712 break; 713 } 714 } 715 (void) SyncImage(image,exception); 716 break; 717 } 718 case 4: 719 { 720 /* 721 Convert PseudoColor scanline. 722 */ 723 for (y=(ssize_t) image->rows-1; y >= 0; y--) 724 { 725 p=pixels+(image->rows-y-1)*bytes_per_line; 726 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 727 if (q == (Quantum *) NULL) 728 break; 729 for (x=0; x < ((ssize_t) image->columns-1); x+=2) 730 { 731 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception); 732 SetPixelIndex(image,index,q); 733 q+=GetPixelChannels(image); 734 index=ConstrainColormapIndex(image,*p & 0xf,exception); 735 SetPixelIndex(image,index,q); 736 p++; 737 q+=GetPixelChannels(image); 738 } 739 if ((image->columns % 2) != 0) 740 { 741 index=ConstrainColormapIndex(image,(*p >> 4) & 0xf,exception); 742 SetPixelIndex(image,index,q); 743 q+=GetPixelChannels(image); 744 p++; 745 } 746 if (SyncAuthenticPixels(image,exception) == MagickFalse) 747 break; 748 if (image->previous == (Image *) NULL) 749 { 750 status=SetImageProgress(image,LoadImageTag,image->rows-y-1, 751 image->rows); 752 if (status == MagickFalse) 753 break; 754 } 755 } 756 (void) SyncImage(image,exception); 757 break; 758 } 759 case 8: 760 { 761 /* 762 Convert PseudoColor scanline. 763 */ 764 if ((dib_info.compression == BI_RLE8) || 765 (dib_info.compression == BI_RLE4)) 766 bytes_per_line=image->columns; 767 for (y=(ssize_t) image->rows-1; y >= 0; y--) 768 { 769 p=pixels+(image->rows-y-1)*bytes_per_line; 770 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 771 if (q == (Quantum *) NULL) 772 break; 773 for (x=0; x < (ssize_t) image->columns; x++) 774 { 775 index=ConstrainColormapIndex(image,*p,exception); 776 SetPixelIndex(image,index,q); 777 p++; 778 q+=GetPixelChannels(image); 779 } 780 if (SyncAuthenticPixels(image,exception) == MagickFalse) 781 break; 782 if (image->previous == (Image *) NULL) 783 { 784 status=SetImageProgress(image,LoadImageTag,image->rows-y-1, 785 image->rows); 786 if (status == MagickFalse) 787 break; 788 } 789 } 790 (void) SyncImage(image,exception); 791 break; 792 } 793 case 16: 794 { 795 unsigned short 796 word; 797 798 /* 799 Convert PseudoColor scanline. 800 */ 801 image->storage_class=DirectClass; 802 if (dib_info.compression == BI_RLE8) 803 bytes_per_line=2*image->columns; 804 for (y=(ssize_t) image->rows-1; y >= 0; y--) 805 { 806 p=pixels+(image->rows-y-1)*bytes_per_line; 807 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 808 if (q == (Quantum *) NULL) 809 break; 810 for (x=0; x < (ssize_t) image->columns; x++) 811 { 812 word=(*p++); 813 word|=(*p++ << 8); 814 if (dib_info.red_mask == 0) 815 { 816 SetPixelRed(image,ScaleCharToQuantum(ScaleColor5to8( 817 (unsigned char) ((word >> 10) & 0x1f))),q); 818 SetPixelGreen(image,ScaleCharToQuantum(ScaleColor5to8( 819 (unsigned char) ((word >> 5) & 0x1f))),q); 820 SetPixelBlue(image,ScaleCharToQuantum(ScaleColor5to8( 821 (unsigned char) (word & 0x1f))),q); 822 } 823 else 824 { 825 SetPixelRed(image,ScaleCharToQuantum(ScaleColor5to8( 826 (unsigned char) ((word >> 11) & 0x1f))),q); 827 SetPixelGreen(image,ScaleCharToQuantum(ScaleColor6to8( 828 (unsigned char) ((word >> 5) & 0x3f))),q); 829 SetPixelBlue(image,ScaleCharToQuantum(ScaleColor5to8( 830 (unsigned char) (word & 0x1f))),q); 831 } 832 q+=GetPixelChannels(image); 833 } 834 if (SyncAuthenticPixels(image,exception) == MagickFalse) 835 break; 836 if (image->previous == (Image *) NULL) 837 { 838 status=SetImageProgress(image,LoadImageTag,image->rows-y-1, 839 image->rows); 840 if (status == MagickFalse) 841 break; 842 } 843 } 844 break; 845 } 846 case 24: 847 case 32: 848 { 849 /* 850 Convert DirectColor scanline. 851 */ 852 for (y=(ssize_t) image->rows-1; y >= 0; y--) 853 { 854 p=pixels+(image->rows-y-1)*bytes_per_line; 855 q=QueueAuthenticPixels(image,0,y,image->columns,1,exception); 856 if (q == (Quantum *) NULL) 857 break; 858 for (x=0; x < (ssize_t) image->columns; x++) 859 { 860 SetPixelBlue(image,ScaleCharToQuantum(*p++),q); 861 SetPixelGreen(image,ScaleCharToQuantum(*p++),q); 862 SetPixelRed(image,ScaleCharToQuantum(*p++),q); 863 if (image->alpha_trait != UndefinedPixelTrait) 864 SetPixelAlpha(image,ScaleCharToQuantum(*p++),q); 865 q+=GetPixelChannels(image); 866 } 867 if (SyncAuthenticPixels(image,exception) == MagickFalse) 868 break; 869 if (image->previous == (Image *) NULL) 870 { 871 status=SetImageProgress(image,LoadImageTag,image->rows-y-1, 872 image->rows); 873 if (status == MagickFalse) 874 break; 875 } 876 } 877 break; 878 } 879 default: 880 ThrowReaderException(CorruptImageError,"ImproperImageHeader"); 881 } 882 pixel_info=RelinquishVirtualMemory(pixel_info); 883 if (EOFBlob(image) != MagickFalse) 884 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile", 885 image->filename); 886 if (dib_info.height < 0) 887 { 888 Image 889 *flipped_image; 890 891 /* 892 Correct image orientation. 893 */ 894 flipped_image=FlipImage(image,exception); 895 if (flipped_image != (Image *) NULL) 896 { 897 DuplicateBlob(flipped_image,image); 898 image=DestroyImage(image); 899 image=flipped_image; 900 } 901 } 902 (void) CloseBlob(image); 903 return(GetFirstImageInList(image)); 904} 905 906/* 907%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 908% % 909% % 910% % 911% R e g i s t e r D I B I m a g e % 912% % 913% % 914% % 915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 916% 917% RegisterDIBImage() adds attributes for the DIB image format to 918% the list of supported formats. The attributes include the image format 919% tag, a method to read and/or write the format, whether the format 920% supports the saving of more than one frame to the same file or blob, 921% whether the format supports native in-memory I/O, and a brief 922% description of the format. 923% 924% The format of the RegisterDIBImage method is: 925% 926% size_t RegisterDIBImage(void) 927% 928*/ 929ModuleExport size_t RegisterDIBImage(void) 930{ 931 MagickInfo 932 *entry; 933 934 entry=AcquireMagickInfo("DIB","DIB", 935 "Microsoft Windows 3.X Packed Device-Independent Bitmap"); 936 entry->decoder=(DecodeImageHandler *) ReadDIBImage; 937 entry->encoder=(EncodeImageHandler *) WriteDIBImage; 938 entry->magick=(IsImageFormatHandler *) IsDIB; 939 entry->flags^=CoderAdjoinFlag; 940 entry->flags|=CoderStealthFlag; 941 (void) RegisterMagickInfo(entry); 942 return(MagickImageCoderSignature); 943} 944 945/* 946%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 947% % 948% % 949% % 950% U n r e g i s t e r D I B I m a g e % 951% % 952% % 953% % 954%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 955% 956% UnregisterDIBImage() removes format registrations made by the 957% DIB module from the list of supported formats. 958% 959% The format of the UnregisterDIBImage method is: 960% 961% UnregisterDIBImage(void) 962% 963*/ 964ModuleExport void UnregisterDIBImage(void) 965{ 966 (void) UnregisterMagickInfo("DIB"); 967} 968 969/* 970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 971% % 972% % 973% % 974% W r i t e D I B I m a g e % 975% % 976% % 977% % 978%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 979% 980% WriteDIBImage() writes an image in Microsoft Windows bitmap encoded 981% image format. 982% 983% The format of the WriteDIBImage method is: 984% 985% MagickBooleanType WriteDIBImage(const ImageInfo *image_info, 986% Image *image,ExceptionInfo *exception) 987% 988% A description of each parameter follows. 989% 990% o image_info: the image info. 991% 992% o image: The image. 993% 994% o exception: return any errors or warnings in this structure. 995% 996*/ 997static MagickBooleanType WriteDIBImage(const ImageInfo *image_info,Image *image, 998 ExceptionInfo *exception) 999{ 1000 DIBInfo 1001 dib_info; 1002 1003 MagickBooleanType 1004 status; 1005 1006 register const Quantum 1007 *p; 1008 1009 register ssize_t 1010 i, 1011 x; 1012 1013 register unsigned char 1014 *q; 1015 1016 size_t 1017 bytes_per_line; 1018 1019 ssize_t 1020 y; 1021 1022 unsigned char 1023 *dib_data, 1024 *pixels; 1025 1026 /* 1027 Open output image file. 1028 */ 1029 assert(image_info != (const ImageInfo *) NULL); 1030 assert(image_info->signature == MagickCoreSignature); 1031 assert(image != (Image *) NULL); 1032 assert(image->signature == MagickCoreSignature); 1033 if (image->debug != MagickFalse) 1034 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1035 assert(exception != (ExceptionInfo *) NULL); 1036 assert(exception->signature == MagickCoreSignature); 1037 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception); 1038 if (status == MagickFalse) 1039 return(status); 1040 /* 1041 Initialize DIB raster file header. 1042 */ 1043 (void) TransformImageColorspace(image,sRGBColorspace,exception); 1044 if (image->storage_class == DirectClass) 1045 { 1046 /* 1047 Full color DIB raster. 1048 */ 1049 dib_info.number_colors=0; 1050 dib_info.bits_per_pixel=(unsigned short) (image->alpha_trait ? 32 : 24); 1051 } 1052 else 1053 { 1054 /* 1055 Colormapped DIB raster. 1056 */ 1057 dib_info.bits_per_pixel=8; 1058 if (image_info->depth > 8) 1059 dib_info.bits_per_pixel=16; 1060 if (SetImageMonochrome(image,exception) != MagickFalse) 1061 dib_info.bits_per_pixel=1; 1062 dib_info.number_colors=(dib_info.bits_per_pixel == 16) ? 0 : 1063 (1UL << dib_info.bits_per_pixel); 1064 } 1065 bytes_per_line=4*((image->columns*dib_info.bits_per_pixel+31)/32); 1066 dib_info.size=40; 1067 dib_info.width=(ssize_t) image->columns; 1068 dib_info.height=(ssize_t) image->rows; 1069 dib_info.planes=1; 1070 dib_info.compression=(size_t) (dib_info.bits_per_pixel == 16 ? 1071 BI_BITFIELDS : BI_RGB); 1072 dib_info.image_size=bytes_per_line*image->rows; 1073 dib_info.x_pixels=75*39; 1074 dib_info.y_pixels=75*39; 1075 switch (image->units) 1076 { 1077 case UndefinedResolution: 1078 case PixelsPerInchResolution: 1079 { 1080 dib_info.x_pixels=(size_t) (100.0*image->resolution.x/2.54); 1081 dib_info.y_pixels=(size_t) (100.0*image->resolution.y/2.54); 1082 break; 1083 } 1084 case PixelsPerCentimeterResolution: 1085 { 1086 dib_info.x_pixels=(size_t) (100.0*image->resolution.x); 1087 dib_info.y_pixels=(size_t) (100.0*image->resolution.y); 1088 break; 1089 } 1090 } 1091 dib_info.colors_important=dib_info.number_colors; 1092 /* 1093 Convert MIFF to DIB raster pixels. 1094 */ 1095 pixels=(unsigned char *) AcquireQuantumMemory(dib_info.image_size, 1096 sizeof(*pixels)); 1097 if (pixels == (unsigned char *) NULL) 1098 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 1099 (void) ResetMagickMemory(pixels,0,dib_info.image_size); 1100 switch (dib_info.bits_per_pixel) 1101 { 1102 case 1: 1103 { 1104 register unsigned char 1105 bit, 1106 byte; 1107 1108 /* 1109 Convert PseudoClass image to a DIB monochrome image. 1110 */ 1111 for (y=0; y < (ssize_t) image->rows; y++) 1112 { 1113 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1114 if (p == (const Quantum *) NULL) 1115 break; 1116 q=pixels+(image->rows-y-1)*bytes_per_line; 1117 bit=0; 1118 byte=0; 1119 for (x=0; x < (ssize_t) image->columns; x++) 1120 { 1121 byte<<=1; 1122 byte|=GetPixelIndex(image,p) != 0 ? 0x01 : 0x00; 1123 bit++; 1124 if (bit == 8) 1125 { 1126 *q++=byte; 1127 bit=0; 1128 byte=0; 1129 } 1130 p+=GetPixelChannels(image); 1131 } 1132 if (bit != 0) 1133 { 1134 *q++=(unsigned char) (byte << (8-bit)); 1135 x++; 1136 } 1137 for (x=(ssize_t) (image->columns+7)/8; x < (ssize_t) bytes_per_line; x++) 1138 *q++=0x00; 1139 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1140 image->rows); 1141 if (status == MagickFalse) 1142 break; 1143 } 1144 break; 1145 } 1146 case 8: 1147 { 1148 /* 1149 Convert PseudoClass packet to DIB pixel. 1150 */ 1151 for (y=0; y < (ssize_t) image->rows; y++) 1152 { 1153 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1154 if (p == (const Quantum *) NULL) 1155 break; 1156 q=pixels+(image->rows-y-1)*bytes_per_line; 1157 for (x=0; x < (ssize_t) image->columns; x++) 1158 { 1159 *q++=(unsigned char) GetPixelIndex(image,p); 1160 p+=GetPixelChannels(image); 1161 } 1162 for ( ; x < (ssize_t) bytes_per_line; x++) 1163 *q++=0x00; 1164 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1165 image->rows); 1166 if (status == MagickFalse) 1167 break; 1168 } 1169 break; 1170 } 1171 case 16: 1172 { 1173 unsigned short 1174 word; 1175 /* 1176 Convert PseudoClass packet to DIB pixel. 1177 */ 1178 for (y=0; y < (ssize_t) image->rows; y++) 1179 { 1180 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1181 if (p == (const Quantum *) NULL) 1182 break; 1183 q=pixels+(image->rows-y-1)*bytes_per_line; 1184 for (x=0; x < (ssize_t) image->columns; x++) 1185 { 1186 word=(unsigned short) ((ScaleColor8to5((unsigned char) 1187 ScaleQuantumToChar(GetPixelRed(image,p))) << 11) | (ScaleColor8to6( 1188 (unsigned char) ScaleQuantumToChar(GetPixelGreen(image,p))) << 5) | 1189 (ScaleColor8to5((unsigned char) ScaleQuantumToChar((unsigned char) 1190 GetPixelBlue(image,p)) << 0))); 1191 *q++=(unsigned char)(word & 0xff); 1192 *q++=(unsigned char)(word >> 8); 1193 p+=GetPixelChannels(image); 1194 } 1195 for (x=(ssize_t) (2*image->columns); x < (ssize_t) bytes_per_line; x++) 1196 *q++=0x00; 1197 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1198 image->rows); 1199 if (status == MagickFalse) 1200 break; 1201 } 1202 break; 1203 } 1204 case 24: 1205 case 32: 1206 { 1207 /* 1208 Convert DirectClass packet to DIB RGB pixel. 1209 */ 1210 for (y=0; y < (ssize_t) image->rows; y++) 1211 { 1212 p=GetVirtualPixels(image,0,y,image->columns,1,exception); 1213 if (p == (const Quantum *) NULL) 1214 break; 1215 q=pixels+(image->rows-y-1)*bytes_per_line; 1216 for (x=0; x < (ssize_t) image->columns; x++) 1217 { 1218 *q++=ScaleQuantumToChar(GetPixelBlue(image,p)); 1219 *q++=ScaleQuantumToChar(GetPixelGreen(image,p)); 1220 *q++=ScaleQuantumToChar(GetPixelRed(image,p)); 1221 if (image->alpha_trait != UndefinedPixelTrait) 1222 *q++=ScaleQuantumToChar(GetPixelAlpha(image,p)); 1223 p+=GetPixelChannels(image); 1224 } 1225 if (dib_info.bits_per_pixel == 24) 1226 for (x=(ssize_t) (3*image->columns); x < (ssize_t) bytes_per_line; x++) 1227 *q++=0x00; 1228 status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y, 1229 image->rows); 1230 if (status == MagickFalse) 1231 break; 1232 } 1233 break; 1234 } 1235 } 1236 if (dib_info.bits_per_pixel == 8) 1237 if (image_info->compression != NoCompression) 1238 { 1239 size_t 1240 length; 1241 1242 /* 1243 Convert run-length encoded raster pixels. 1244 */ 1245 length=2UL*(bytes_per_line+2UL)+2UL; 1246 dib_data=(unsigned char *) AcquireQuantumMemory(length, 1247 (image->rows+2UL)*sizeof(*dib_data)); 1248 if (dib_data == (unsigned char *) NULL) 1249 { 1250 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1251 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 1252 } 1253 dib_info.image_size=(size_t) EncodeImage(image,bytes_per_line, 1254 pixels,dib_data); 1255 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1256 pixels=dib_data; 1257 dib_info.compression = BI_RLE8; 1258 } 1259 /* 1260 Write DIB header. 1261 */ 1262 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.size); 1263 (void) WriteBlobLSBLong(image,dib_info.width); 1264 (void) WriteBlobLSBLong(image,(unsigned short) dib_info.height); 1265 (void) WriteBlobLSBShort(image,(unsigned short) dib_info.planes); 1266 (void) WriteBlobLSBShort(image,dib_info.bits_per_pixel); 1267 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.compression); 1268 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.image_size); 1269 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.x_pixels); 1270 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.y_pixels); 1271 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.number_colors); 1272 (void) WriteBlobLSBLong(image,(unsigned int) dib_info.colors_important); 1273 if (image->storage_class == PseudoClass) 1274 { 1275 if (dib_info.bits_per_pixel <= 8) 1276 { 1277 unsigned char 1278 *dib_colormap; 1279 1280 /* 1281 Dump colormap to file. 1282 */ 1283 dib_colormap=(unsigned char *) AcquireQuantumMemory((size_t) 1284 (1UL << dib_info.bits_per_pixel),4*sizeof(*dib_colormap)); 1285 if (dib_colormap == (unsigned char *) NULL) 1286 ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed"); 1287 q=dib_colormap; 1288 for (i=0; i < (ssize_t) MagickMin(image->colors,dib_info.number_colors); i++) 1289 { 1290 *q++=ScaleQuantumToChar(image->colormap[i].blue); 1291 *q++=ScaleQuantumToChar(image->colormap[i].green); 1292 *q++=ScaleQuantumToChar(image->colormap[i].red); 1293 *q++=(Quantum) 0x0; 1294 } 1295 for ( ; i < (ssize_t) (1L << dib_info.bits_per_pixel); i++) 1296 { 1297 *q++=(Quantum) 0x0; 1298 *q++=(Quantum) 0x0; 1299 *q++=(Quantum) 0x0; 1300 *q++=(Quantum) 0x0; 1301 } 1302 (void) WriteBlob(image,(size_t) (4*(1 << dib_info.bits_per_pixel)), 1303 dib_colormap); 1304 dib_colormap=(unsigned char *) RelinquishMagickMemory(dib_colormap); 1305 } 1306 else 1307 if ((dib_info.bits_per_pixel == 16) && 1308 (dib_info.compression == BI_BITFIELDS)) 1309 { 1310 (void) WriteBlobLSBLong(image,0xf800); 1311 (void) WriteBlobLSBLong(image,0x07e0); 1312 (void) WriteBlobLSBLong(image,0x001f); 1313 } 1314 } 1315 (void) WriteBlob(image,dib_info.image_size,pixels); 1316 pixels=(unsigned char *) RelinquishMagickMemory(pixels); 1317 (void) CloseBlob(image); 1318 return(MagickTrue); 1319} 1320