Files
kiss-vscode/projects/blades-engine/source/Bmp.c.hx.ktxt2

229 lines
109 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

|||/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% BBBB M M PPPP %
% B B MM MM P P %
% BBBB M M M PPPP %
% B B M M P %
% BBBB M M P %
% %
% %
% Read/Write Microsoft Windows Bitmap Image Format %
% %
% Software Design %
% Cristy %
% Glenn Randers-Pehrson %
% December 2001 %
% %
% %
% Copyright @ 2001 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
% https://imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/
↵|>|||||||/*
Include declarations.
*/
#include "MagickCore/studio.h"
#include "MagickCore/blob.h"
#include "MagickCore/blob-private.h"
#include "MagickCore/cache.h"
#include "MagickCore/colormap-private.h"
#include "MagickCore/color-private.h"
#include "MagickCore/colormap.h"
#include "MagickCore/colorspace.h"
#include "MagickCore/colorspace-private.h"
#include "MagickCore/exception.h"
#include "MagickCore/exception-private.h"
#include "MagickCore/image.h"
#include "MagickCore/image-private.h"
#include "MagickCore/list.h"
#include "MagickCore/log.h"
#include "MagickCore/magick.h"
#include "MagickCore/memory_.h"
#include "MagickCore/monitor.h"
#include "MagickCore/monitor-private.h"
#include "MagickCore/option.h"
#include "MagickCore/pixel-accessor.h"
#include "MagickCore/profile.h"
#include "MagickCore/quantum-private.h"
#include "MagickCore/static.h"
#include "MagickCore/string_.h"
#include "MagickCore/module.h"
#include "MagickCore/transform.h"
↵|>|||||||/*
Macro definitions (from Windows wingdi.h).
*/
#undef BI_JPEG
#define BI_JPEG 4
#undef BI_PNG
#define BI_PNG 5
#if !defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__MINGW32__)
#undef BI_RGB
#define BI_RGB 0
#undef BI_RLE8
#define BI_RLE8 1
#undef BI_RLE4
#define BI_RLE4 2
#undef BI_BITFIELDS
#define BI_BITFIELDS 3
#undef LCS_CALIBRATED_RBG
#define LCS_CALIBRATED_RBG 0
#undef LCS_sRGB
#define LCS_sRGB 1
#undef LCS_WINDOWS_COLOR_SPACE
#define LCS_WINDOWS_COLOR_SPACE 2
#undef PROFILE_LINKED
#define PROFILE_LINKED 3
#undef PROFILE_EMBEDDED
#define PROFILE_EMBEDDED 4
#undef LCS_GM_BUSINESS
#define LCS_GM_BUSINESS 1 /* Saturation */
#undef LCS_GM_GRAPHICS
#define LCS_GM_GRAPHICS 2 /* Relative */
#undef LCS_GM_IMAGES
#define LCS_GM_IMAGES 4 /* Perceptual */
#undef LCS_GM_ABS_COLORIMETRIC
#define LCS_GM_ABS_COLORIMETRIC 8 /* Absolute */
#endif
↵|>|||||||/*
Enumerated declaractions.
*/
typedef enum
{
UndefinedSubtype,
RGB555,
RGB565,
ARGB4444,
ARGB1555
} BMPSubtype;¶|>|||||||/*
Typedef declarations.
*/
typedef struct _BMPInfo
{↵|>||||||| unsigned int
file_size,↵|>||||||| ba_offset,↵|>||||||| offset_bits,↵|>||||||| size;¶|>||||||| ssize_t
width,↵|>||||||| height;¶|>||||||| unsigned short
planes,↵|>||||||| bits_per_pixel;¶|>||||||| unsigned int
compression,↵|>||||||| image_size,↵|>||||||| x_pixels,↵|>||||||| y_pixels,↵|>||||||| number_colors,↵|>||||||| red_mask,↵|>||||||| green_mask,↵|>||||||| blue_mask,↵|>||||||| alpha_mask,↵|>||||||| colors_important;¶|>||||||| long
colorspace;¶|>||||||| PrimaryInfo
red_primary,↵|>||||||| green_primary,↵|>||||||| blue_primary,↵|>||||||| gamma_scale;↵|>|||||||} BMPInfo;
↵|>|||||||/*
Forward declarations.
*/
static MagickBooleanType
WriteBMPImage(const ImageInfo *,Image *,ExceptionInfo *);
↵|>|||||||/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% D e c o d e I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% DecodeImage unpacks the packed image pixels into runlength-encoded
% pixel packets.
%
% The format of the DecodeImage method is:
%
% MagickBooleanType DecodeImage(Image *image,const size_t compression,
% unsigned char *pixels,const size_t number_pixels)
%
% A description of each parameter follows:
%
% o image: the address of a structure of type Image.
%
% o compression: Zero means uncompressed. A value of 1 means the
% compressed pixels are runlength encoded for a 256-color bitmap.
% A value of 2 means a 16-color bitmap. A value of 3 means bitfields
% encoding.
%
% o pixels: The address of a byte (8 bits) array of pixel data created by
% the decoding process.
%
% o number_pixels: The number of pixels.
%
*/↵|>|||||||static MagickBooleanType DecodeImage(Image *image,const size_t compression,
unsigned char *pixels,const size_t number_pixels)
{↵|>||||||| int
byte,↵|>||||||| count;¶|>||||||| ssize_t
i,↵|>||||||| x;¶|>||||||| unsigned char
*p,↵|>||||||| *q;¶|>||||||| ssize_t
y;¶|>||||||| assert(image != (Image *) NULL);
assert(image->signature == MagickCoreSignature);
assert(pixels != (unsigned char *) NULL);↵|>||||||| if (IsEventLogging() != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);↵|>||||||| (void) memset(pixels,0,number_pixels*sizeof(*pixels));↵|>||||||| byte=0;↵|>||||||| x=0;↵|>||||||| p=pixels;↵|>||||||| q=pixels+number_pixels;↵|>||||||| for (y=0; y < (ssize_t) image->rows; )
{↵|>||||||| MagickBooleanType
status;¶|>||||||| if ((p < pixels) || (p > q))↵|>||||||| break;↵|>||||||| count=ReadBlobByte(image);↵|>||||||| if (count == EOF)↵|>||||||| break;↵|>||||||| if (count > 0)↵|>||||||| {↵|>||||||| /*↵|>||||||| Encoded mode.↵|>||||||| */↵|>||||||| count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));↵|>||||||| byte=ReadBlobByte(image);↵|>||||||| if (byte == EOF)↵|>||||||| break;↵|>||||||| if (compression == BI_RLE8)↵|>||||||| {↵|>||||||| for (i=0; i < (ssize_t) count; i++)↵|>||||||| *p++=(unsigned char) byte;↵|>||||||| }↵|>||||||| else↵|>||||||| {↵|>||||||| for (i=0; i < (ssize_t) count; i++)↵|>||||||| *p++=(unsigned char)↵|>||||||| ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));↵|>||||||| }↵|>||||||| x+=count;↵|>||||||| }↵|>||||||| else↵|>||||||| {↵|>||||||| /*↵|>||||||| Escape mode.↵|>||||||| */↵|>||||||| count=ReadBlobByte(image);↵|>||||||| if (count == EOF)↵|>||||||| break;↵|>||||||| if (count == 0x01)↵|>||||||| return(MagickTrue);↵|>||||||| switch (count)↵|>||||||| {↵|>||||||| case 0x00:↵|>||||||| {↵|>||||||| /*↵|>||||||| End of line.↵|>||||||| */↵|>||||||| x=0;↵|>||||||| y++;↵|>||||||| p=pixels+y*image->columns;↵|>||||||| break;↵|>||||||| }↵|>||||||| case 0x02:↵|>||||||| {↵|>||||||| /*↵|>||||||| Delta mode.↵|>||||||| */↵|>||||||| x+=ReadBlobByte(image);↵|>||||||| y+=ReadBlobByte(image);↵|>||||||| p=pixels+y*image->columns+x;↵|>||||||| break;↵|>||||||| }↵|>||||||| default:↵|>||||||| {↵|>||||||| /*↵|>||||||| Absolute mode.↵|>||||||| */↵|>||||||| count=(int) MagickMin((ssize_t) count,(ssize_t) (q-p));↵|>||||||| if (compression == BI_RLE8)↵|>||||||| for (i=0; i < (ssize_t) count; i++)↵|>||||||| {↵|>||||||| byte=ReadBlobByte(image);↵|>||||||| if (byte == EOF)↵|>||||||| break;↵|>||||||| *p++=(unsigned char) byte;↵|>||||||| }↵|>||||||| else↵|>||||||| for (i=0; i < (ssize_t) count; i++)↵|>||||||| {↵|>||||||| if ((i & 0x01) == 0)↵|>||||||| {↵|>||||||| byte=ReadBlobByte(image);↵|>||||||| if (byte == EOF)↵|>||||||| break;↵|>||||||| }↵|>||||||| *p++=(unsigned char)↵|>||||||| ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));↵|>||||||| }↵|>||||||| x+=count;↵|>||||||| /*↵|>||||||| Read pad byte.↵|>||||||| */↵|>||||||| if (compression == BI_RLE8)↵|>||||||| {↵|>||||||| if ((count & 0x01) != 0)↵|>||||||| if (ReadBlobByte(image) == EOF)↵|>||||||| break;↵|>||||||| }↵|>||||||| else↵|>||||||| if (((count & 0x03) == 1) || ((count & 0x03) == 2))↵|>||||||| if (ReadBlobByte(image) == EOF)↵|>||||||| break;↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| }↵|>||||||| status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,↵|>||||||| image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| (void) ReadBlobByte(image); /* end of line */↵|>||||||| (void) ReadBlobByte(image);↵|>||||||| return(y < (ssize_t) image->rows ? MagickFalse : MagickTrue);↵|>|||||||}↵|>||||||| ↵|>|||||||/*↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% E n c o d e I m a g e %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||%↵|>|||||||% EncodeImage compresses pixels using a runlength encoded format.↵|>|||||||%↵|>|||||||% The format of the EncodeImage method is:↵|>|||||||%↵|>|||||||% static MagickBooleanType EncodeImage(Image *image,↵|>|||||||% const size_t bytes_per_line,const unsigned char *pixels,↵|>|||||||% unsigned char *compressed_pixels)↵|>|||||||%↵|>|||||||% A description of each parameter follows:↵|>|||||||%↵|>|||||||% o image: The image.↵|>|||||||%↵|>|||||||% o bytes_per_line: the number of bytes in a scanline of compressed pixels↵|>|||||||%↵|>|||||||% o pixels: The address of a byte (8 bits) array of pixel data created by↵|>|||||||% the compression process.↵|>|||||||%↵|>|||||||% o compressed_pixels: The address of a byte (8 bits) array of compressed↵|>|||||||% pixel data.↵|>|||||||%↵|>|||||||*/↵|>|||||||static size_t EncodeImage(Image *image,const size_t bytes_per_line,↵|>||||||| const unsigned char *pixels,unsigned char *compressed_pixels)↵|>|||||||{↵|>||||||| MagickBooleanType↵|>||||||| status;↵|>|||||||↵|>||||||| const unsigned char↵|>||||||| *p;↵|>|||||||↵|>||||||| ssize_t↵|>||||||| i,↵|>||||||| x;↵|>|||||||↵|>||||||| unsigned char↵|>||||||| *q;↵|>|||||||↵|>||||||| ssize_t↵|>||||||| y;↵|>|||||||↵|>||||||| /*↵|>||||||| Runlength encode pixels.↵|>||||||| */↵|>||||||| assert(image != (Image *) NULL);↵|>||||||| assert(image->signature == MagickCoreSignature);↵|>||||||| assert(pixels != (const unsigned char *) NULL);↵|>||||||| assert(compressed_pixels != (unsigned char *) NULL);↵|>||||||| if (IsEventLogging() != MagickFalse)↵|>||||||| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);↵|>||||||| p=pixels;↵|>||||||| q=compressed_pixels;↵|>||||||| i=0;↵|>||||||| for (y=0; y < (ssize_t) image->rows; y++)↵|>||||||| {↵|>||||||| for (x=0; x < (ssize_t) bytes_per_line; x+=i)↵|>||||||| {↵|>||||||| /*↵|>||||||| Determine runlength.↵|>||||||| */↵|>||||||| for (i=1; ((x+i) < (ssize_t) bytes_per_line); i++)↵|>||||||| if ((i == 255) || (*(p+i) != *p))↵|>||||||| break;↵|>||||||| *q++=(unsigned char) i;↵|>||||||| *q++=(*p);↵|>||||||| p+=i;↵|>||||||| }↵|>||||||| /*↵|>||||||| End of line.↵|>||||||| */↵|>||||||| *q++=(unsigned char) 0x00;↵|>||||||| *q++=(unsigned char) 0x00;↵|>||||||| status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,↵|>||||||| image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| /*↵|>||||||| End of bitmap.↵|>||||||| */↵|>||||||| *q++=(unsigned char) 0x00;↵|>||||||| *q++=(unsigned char) 0x01;↵|>||||||| return((size_t) (q-compressed_pixels));↵|>|||||||}↵|>||||||| ↵|>|||||||/*↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% I s B M P %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||%↵|>|||||||% IsBMP() returns MagickTrue if the image format type, identified by the↵|>|||||||% magick string, is BMP.↵|>|||||||%↵|>|||||||% The format of the IsBMP method is:↵|>|||||||%↵|>|||||||% MagickBooleanType IsBMP(const unsigned char *magick,const size_t length)↵|>|||||||%↵|>|||||||% A description of each parameter follows:↵|>|||||||%↵|>|||||||% o magick: compare image format pattern against these bytes.↵|>|||||||%↵|>|||||||% o length: Specifies the length of the magick string.↵|>|||||||%↵|>|||||||*/↵|>|||||||static MagickBooleanType IsBMP(const unsigned char *magick,const size_t length)↵|>|||||||{↵|>||||||| if (length < 2)↵|>||||||| return(MagickFalse);↵|>||||||| if ((LocaleNCompare((char *) magick,"BA",2) == 0) ||↵|>||||||| (LocaleNCompare((char *) magick,"BM",2) == 0) ||↵|>||||||| (LocaleNCompare((char *) magick,"IC",2) == 0) ||↵|>||||||| (LocaleNCompare((char *) magick,"PI",2) == 0) ||↵|>||||||| (LocaleNCompare((char *) magick,"CI",2) == 0) ||↵|>||||||| (LocaleNCompare((char *) magick,"CP",2) == 0))↵|>||||||| return(MagickTrue);↵|>||||||| return(MagickFalse);↵|>|||||||}↵|>||||||| ↵|>|||||||/*↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% R e a d B M P I m a g e %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||%↵|>|||||||% ReadBMPImage() reads a Microsoft Windows bitmap image file, Version
% 2, 3 (for Windows or NT), or 4, and returns it. It allocates the memory
% necessary for the new Image structure and returns a pointer to the new
% image.
%
% The format of the ReadBMPImage method is:
%
% image=ReadBMPImage(image_info)
%
% A description of each parameter follows:
%
% o image_info: the image info.
%
% o exception: return any errors or warnings in this structure.
%
*/¶|>|||||||static Image *ReadBMPImage(const ImageInfo *image_info,ExceptionInfo *exception)
{↵|>||||||| BMPInfo
bmp_info;¶|>||||||| Image
*image;¶|>||||||| MagickBooleanType
status;¶|>||||||| MagickOffsetType
offset,↵|>||||||| profile_data,↵|>||||||| profile_size,↵|>||||||| start_position;¶|>||||||| MagickSizeType
blob_size;¶|>||||||| MemoryInfo
*pixel_info;¶|>||||||| Quantum
index;¶|>||||||| Quantum
*q;¶|>||||||| ssize_t
i,↵|>||||||| x;¶|>||||||| unsigned char
*p;¶|>||||||| size_t
bit,↵|>||||||| bytes_per_line,↵|>||||||| length;¶|>||||||| ssize_t
count,↵|>||||||| y;¶|>||||||| unsigned char
magick[12],↵|>||||||| *pixels;¶|>||||||| unsigned int
blue,↵|>||||||| green,↵|>||||||| offset_bits,↵|>||||||| red;¶|>||||||| /*
Open image file.
*/↵|>||||||| assert(image_info != (const ImageInfo *) NULL);
assert(image_info->signature == MagickCoreSignature);↵|>||||||| if (IsEventLogging() != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
image_info->filename);↵|>||||||| assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickCoreSignature);↵|>||||||| image=AcquireImage(image_info,exception);↵|>||||||| status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);↵|>||||||| if (status == MagickFalse)
{
image=DestroyImageList(image);
return((Image *) NULL);
}↵|>||||||| /*
Determine if this a BMP file.
*/↵|>||||||| (void) memset(&bmp_info,0,sizeof(bmp_info));↵|>||||||| bmp_info.ba_offset=0;↵|>||||||| start_position=0;↵|>||||||| offset_bits=0;↵|>||||||| count=ReadBlob(image,2,magick);↵|>||||||| if (count != 2)
ThrowReaderException(CorruptImageError,"ImproperImageHeader");↵|>||||||| blob_size=GetBlobSize(image);↵|>||||||| do
{↵|>||||||| PixelInfo
quantum_bits;¶|>||||||| PixelPacket
shift;¶|>||||||| /*
Verify BMP identifier.
*/↵|>||||||| start_position=TellBlob(image)-2;↵|>||||||| bmp_info.ba_offset=0;↵|>||||||| while (LocaleNCompare((char *) magick,"BA",2) == 0)
{↵|>||||||| bmp_info.file_size=ReadBlobLSBLong(image);↵|>||||||| bmp_info.ba_offset=ReadBlobLSBLong(image);↵|>||||||| bmp_info.offset_bits=ReadBlobLSBLong(image);↵|>||||||| count=ReadBlob(image,2,magick);↵|>||||||| if (count != 2)
break;↵|>||||||| }↵|>||||||| if (image->debug != MagickFalse)
(void) LogMagickEvent(CoderEvent,GetMagickModule()," Magick: %c%c",
magick[0],magick[1]);↵|>||||||| if ((count != 2) || ((LocaleNCompare((char *) magick,"BM",2) != 0) &&
(LocaleNCompare((char *) magick,"CI",2) != 0)))↵|>||||||| ThrowReaderException(CorruptImageError,"ImproperImageHeader");↵|>||||||| bmp_info.file_size=ReadBlobLSBLong(image);↵|>||||||| (void) ReadBlobLSBLong(image);↵|>||||||| bmp_info.offset_bits=ReadBlobLSBLong(image);↵|>||||||| bmp_info.size=ReadBlobLSBLong(image);↵|>||||||| if (image->debug != MagickFalse)↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " BMP header size: %u",bmp_info.size);↵|>||||||| if (bmp_info.size > 124)↵|>||||||| ThrowReaderException(CorruptImageError,"ImproperImageHeader");↵|>||||||| profile_data=0;↵|>||||||| profile_size=0;↵|>||||||| if (bmp_info.size == 12)↵|>||||||| {↵|>||||||| /*↵|>||||||| OS/2 BMP image file.↵|>||||||| */↵|>||||||| (void) CopyMagickString(image->magick,"BMP2",MagickPathExtent);↵|>||||||| bmp_info.width=(ssize_t) ((short) ReadBlobLSBShort(image));↵|>||||||| bmp_info.height=(ssize_t) ((short) ReadBlobLSBShort(image));↵|>||||||| bmp_info.planes=ReadBlobLSBShort(image);↵|>||||||| bmp_info.bits_per_pixel=ReadBlobLSBShort(image);↵|>||||||| bmp_info.x_pixels=0;↵|>||||||| bmp_info.y_pixels=0;↵|>||||||| bmp_info.number_colors=0;↵|>||||||| bmp_info.compression=BI_RGB;↵|>||||||| bmp_info.image_size=0;↵|>||||||| bmp_info.alpha_mask=0;↵|>||||||| if (image->debug != MagickFalse)↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Format: OS/2 Bitmap");↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Geometry: %.20gx%.20g",(double) bmp_info.width,(double)↵|>||||||| bmp_info.height);↵|>||||||| }↵|>||||||| }↵|>||||||| else↵|>||||||| {↵|>||||||| /*↵|>||||||| Microsoft Windows BMP image file.↵|>||||||| */↵|>||||||| bmp_info.width=(ssize_t) ReadBlobLSBSignedLong(image);↵|>||||||| bmp_info.height=(ssize_t) ReadBlobLSBSignedLong(image);↵|>||||||| bmp_info.planes=ReadBlobLSBShort(image);↵|>||||||| bmp_info.bits_per_pixel=ReadBlobLSBShort(image);↵|>||||||| bmp_info.compression=ReadBlobLSBLong(image);↵|>||||||| if (bmp_info.size > 16)↵|>||||||| {↵|>||||||| bmp_info.image_size=ReadBlobLSBLong(image);↵|>||||||| bmp_info.x_pixels=ReadBlobLSBLong(image);↵|>||||||| bmp_info.y_pixels=ReadBlobLSBLong(image);↵|>||||||| bmp_info.number_colors=ReadBlobLSBLong(image);↵|>||||||| if ((MagickSizeType) bmp_info.number_colors > blob_size)↵|>||||||| ThrowReaderException(CorruptImageError,↵|>||||||| "InsufficientImageDataInFile");↵|>||||||| bmp_info.colors_important=ReadBlobLSBLong(image);↵|>||||||| }↵|>||||||| if (image->debug != MagickFalse)↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Format: MS Windows bitmap");↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Geometry: %.20gx%.20g",(double) bmp_info.width,(double)↵|>||||||| bmp_info.height);↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Bits per pixel: %.20g",(double) bmp_info.bits_per_pixel);↵|>||||||| switch (bmp_info.compression)↵|>||||||| {↵|>||||||| case BI_RGB:↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Compression: BI_RGB");↵|>||||||| break;↵|>||||||| }↵|>||||||| case BI_RLE4:↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Compression: BI_RLE4");↵|>||||||| break;↵|>||||||| }↵|>||||||| case BI_RLE8:↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Compression: BI_RLE8");↵|>||||||| break;↵|>||||||| }↵|>||||||| case BI_BITFIELDS:↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Compression: BI_BITFIELDS");↵|>||||||| break;↵|>||||||| }↵|>||||||| case BI_PNG:↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Compression: BI_PNG");↵|>||||||| break;↵|>||||||| }↵|>||||||| case BI_JPEG:↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Compression: BI_JPEG");↵|>||||||| break;↵|>||||||| }↵|>||||||| default:↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Compression: UNKNOWN (%u)",bmp_info.compression);↵|>||||||| }↵|>||||||| }↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Number of colors: %u",bmp_info.number_colors);↵|>||||||| }↵|>||||||| if ((bmp_info.size > 40) || (bmp_info.compression == BI_BITFIELDS))↵|>||||||| {↵|>||||||| bmp_info.red_mask=ReadBlobLSBLong(image);↵|>||||||| bmp_info.green_mask=ReadBlobLSBLong(image);↵|>||||||| bmp_info.blue_mask=ReadBlobLSBLong(image);↵|>||||||| }↵|>||||||| if (bmp_info.size > 40)↵|>||||||| {↵|>||||||| double↵|>||||||| gamma;↵|>|||||||↵|>||||||| /*↵|>||||||| Read color management information.↵|>||||||| */↵|>||||||| bmp_info.alpha_mask=ReadBlobLSBLong(image);↵|>||||||| bmp_info.colorspace=ReadBlobLSBSignedLong(image);↵|>||||||| /*↵|>||||||| Decode 2^30 fixed point formatted CIE primaries.↵|>||||||| */↵|>|||||||# define BMP_DENOM ((double) 0x40000000)↵|>||||||| bmp_info.red_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;↵|>||||||| bmp_info.red_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;↵|>||||||| bmp_info.red_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;↵|>||||||| bmp_info.green_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;↵|>||||||| bmp_info.green_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;↵|>||||||| bmp_info.green_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;↵|>||||||| bmp_info.blue_primary.x=(double) ReadBlobLSBLong(image)/BMP_DENOM;↵|>||||||| bmp_info.blue_primary.y=(double) ReadBlobLSBLong(image)/BMP_DENOM;↵|>||||||| bmp_info.blue_primary.z=(double) ReadBlobLSBLong(image)/BMP_DENOM;↵|>|||||||↵|>||||||| gamma=bmp_info.red_primary.x+bmp_info.red_primary.y+↵|>||||||| bmp_info.red_primary.z;↵|>||||||| gamma=PerceptibleReciprocal(gamma);↵|>||||||| bmp_info.red_primary.x*=gamma;↵|>||||||| bmp_info.red_primary.y*=gamma;↵|>||||||| image->chromaticity.red_primary.x=bmp_info.red_primary.x;↵|>||||||| image->chromaticity.red_primary.y=bmp_info.red_primary.y;↵|>|||||||↵|>||||||| gamma=bmp_info.green_primary.x+bmp_info.green_primary.y+↵|>||||||| bmp_info.green_primary.z;↵|>||||||| gamma=PerceptibleReciprocal(gamma);↵|>||||||| bmp_info.green_primary.x*=gamma;↵|>||||||| bmp_info.green_primary.y*=gamma;↵|>||||||| image->chromaticity.green_primary.x=bmp_info.green_primary.x;↵|>||||||| image->chromaticity.green_primary.y=bmp_info.green_primary.y;↵|>|||||||↵|>||||||| gamma=bmp_info.blue_primary.x+bmp_info.blue_primary.y+↵|>||||||| bmp_info.blue_primary.z;↵|>||||||| gamma=PerceptibleReciprocal(gamma);↵|>||||||| bmp_info.blue_primary.x*=gamma;↵|>||||||| bmp_info.blue_primary.y*=gamma;↵|>||||||| image->chromaticity.blue_primary.x=bmp_info.blue_primary.x;↵|>||||||| image->chromaticity.blue_primary.y=bmp_info.blue_primary.y;↵|>|||||||↵|>||||||| /*↵|>||||||| Decode 16^16 fixed point formatted gamma_scales.↵|>||||||| */↵|>||||||| bmp_info.gamma_scale.x=(double) ReadBlobLSBLong(image)/0x10000;↵|>||||||| bmp_info.gamma_scale.y=(double) ReadBlobLSBLong(image)/0x10000;↵|>||||||| bmp_info.gamma_scale.z=(double) ReadBlobLSBLong(image)/0x10000;↵|>||||||| /*↵|>||||||| Compute a single gamma from the BMP 3-channel gamma.↵|>||||||| */↵|>||||||| image->gamma=(bmp_info.gamma_scale.x+bmp_info.gamma_scale.y+↵|>||||||| bmp_info.gamma_scale.z)/3.0;↵|>||||||| }↵|>||||||| else↵|>||||||| (void) CopyMagickString(image->magick,"BMP3",MagickPathExtent);↵|>|||||||↵|>||||||| if (bmp_info.size > 108)↵|>||||||| {↵|>||||||| size_t↵|>||||||| intent;↵|>|||||||↵|>||||||| /*↵|>||||||| Read BMP Version 5 color management information.↵|>||||||| */↵|>||||||| intent=ReadBlobLSBLong(image);↵|>||||||| switch ((int) intent)↵|>||||||| {↵|>||||||| case LCS_GM_BUSINESS:↵|>||||||| {↵|>||||||| image->rendering_intent=SaturationIntent;↵|>||||||| break;↵|>||||||| }↵|>||||||| case LCS_GM_GRAPHICS:↵|>||||||| {↵|>||||||| image->rendering_intent=RelativeIntent;↵|>||||||| break;↵|>||||||| }↵|>||||||| case LCS_GM_IMAGES:↵|>||||||| {↵|>||||||| image->rendering_intent=PerceptualIntent;↵|>||||||| break;↵|>||||||| }↵|>||||||| case LCS_GM_ABS_COLORIMETRIC:↵|>||||||| {↵|>||||||| image->rendering_intent=AbsoluteIntent;↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| profile_data=(MagickOffsetType)ReadBlobLSBLong(image);↵|>||||||| profile_size=(MagickOffsetType)ReadBlobLSBLong(image);↵|>||||||| (void) ReadBlobLSBLong(image); /* Reserved byte */↵|>||||||| }↵|>||||||| }↵|>||||||| if ((MagickSizeType) bmp_info.file_size != blob_size)↵|>||||||| {↵|>||||||| const char↵|>||||||| *option;↵|>|||||||↵|>||||||| option=GetImageOption(image_info,"bmp:ignore-filesize");↵|>||||||| if (IsStringTrue(option) == MagickFalse)↵|>||||||| (void) ThrowMagickException(exception,GetMagickModule(),↵|>||||||| CorruptImageError,"LengthAndFilesizeDoNotMatch","`%s'",↵|>||||||| image->filename);↵|>||||||| }↵|>||||||| if (bmp_info.width <= 0)↵|>||||||| ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");↵|>||||||| if (bmp_info.height == 0)↵|>||||||| ThrowReaderException(CorruptImageError,"NegativeOrZeroImageSize");↵|>||||||| if (bmp_info.planes != 1)↵|>||||||| ThrowReaderException(CorruptImageError,"StaticPlanesValueNotEqualToOne");↵|>||||||| if ((bmp_info.bits_per_pixel != 1) && (bmp_info.bits_per_pixel != 4) &&↵|>||||||| (bmp_info.bits_per_pixel != 8) && (bmp_info.bits_per_pixel != 16) &&↵|>||||||| (bmp_info.bits_per_pixel != 24) && (bmp_info.bits_per_pixel != 32))↵|>||||||| ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");↵|>||||||| if (bmp_info.bits_per_pixel < 16 &&↵|>||||||| bmp_info.number_colors > (1U << bmp_info.bits_per_pixel))↵|>||||||| ThrowReaderException(CorruptImageError,"UnrecognizedNumberOfColors");↵|>||||||| if ((bmp_info.compression == BI_RLE8) && (bmp_info.bits_per_pixel != 8))↵|>||||||| ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");↵|>||||||| if ((bmp_info.compression == BI_RLE4) && (bmp_info.bits_per_pixel != 4))↵|>||||||| ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");↵|>||||||| if ((bmp_info.compression == BI_BITFIELDS) && (bmp_info.bits_per_pixel < 16))↵|>||||||| ThrowReaderException(CorruptImageError,"UnsupportedBitsPerPixel");↵|>||||||| switch (bmp_info.compression)↵|>||||||| {↵|>||||||| case BI_RGB:↵|>||||||| image->compression=NoCompression;↵|>||||||| break;↵|>||||||| case BI_RLE8:↵|>||||||| case BI_RLE4:↵|>||||||| image->compression=RLECompression;↵|>||||||| break;↵|>||||||| case BI_BITFIELDS:↵|>||||||| break;↵|>||||||| case BI_JPEG:↵|>||||||| ThrowReaderException(CoderError,"JPEGCompressNotSupported");↵|>||||||| case BI_PNG:↵|>||||||| ThrowReaderException(CoderError,"PNGCompressNotSupported");↵|>||||||| default:↵|>||||||| ThrowReaderException(CorruptImageError,"UnrecognizedImageCompression");↵|>||||||| }↵|>||||||| image->columns=(size_t) MagickAbsoluteValue(bmp_info.width);↵|>||||||| image->rows=(size_t) MagickAbsoluteValue(bmp_info.height);↵|>||||||| image->depth=bmp_info.bits_per_pixel <= 8 ? bmp_info.bits_per_pixel : 8;↵|>||||||| image->alpha_trait=((bmp_info.alpha_mask != 0) &&↵|>||||||| (bmp_info.compression == BI_BITFIELDS)) ? BlendPixelTrait :↵|>||||||| UndefinedPixelTrait;↵|>||||||| if (bmp_info.bits_per_pixel < 16)↵|>||||||| {↵|>||||||| size_t↵|>||||||| one;↵|>|||||||↵|>||||||| image->storage_class=PseudoClass;↵|>||||||| image->colors=bmp_info.number_colors;↵|>||||||| one=1;↵|>||||||| if (image->colors == 0)↵|>||||||| image->colors=one << bmp_info.bits_per_pixel;↵|>||||||| }↵|>||||||| image->resolution.x=(double) bmp_info.x_pixels/100.0;↵|>||||||| image->resolution.y=(double) bmp_info.y_pixels/100.0;↵|>||||||| image->units=PixelsPerCentimeterResolution;↵|>||||||| if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))↵|>||||||| if (image->scene >= (image_info->scene+image_info->number_scenes-1))↵|>||||||| break;↵|>||||||| status=SetImageExtent(image,image->columns,image->rows,exception);↵|>||||||| if (status == MagickFalse)↵|>||||||| return(DestroyImageList(image));↵|>||||||| if (image->storage_class == PseudoClass)↵|>||||||| {↵|>||||||| unsigned char↵|>||||||| *bmp_colormap;↵|>|||||||↵|>||||||| size_t↵|>||||||| packet_size;↵|>|||||||↵|>||||||| /*↵|>||||||| Read BMP raster colormap.↵|>||||||| */↵|>||||||| if (image->debug != MagickFalse)↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Reading colormap of %.20g colors",(double) image->colors);↵|>||||||| if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)↵|>||||||| ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");↵|>||||||| bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t)↵|>||||||| image->colors,4*sizeof(*bmp_colormap));↵|>||||||| if (bmp_colormap == (unsigned char *) NULL)↵|>||||||| ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");↵|>||||||| if ((bmp_info.size == 12) || (bmp_info.size == 64))↵|>||||||| packet_size=3;↵|>||||||| else↵|>||||||| packet_size=4;↵|>||||||| offset=SeekBlob(image,start_position+14+bmp_info.size,SEEK_SET);↵|>||||||| if (offset < 0)↵|>||||||| {↵|>||||||| bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);↵|>||||||| ThrowReaderException(CorruptImageError,"ImproperImageHeader");↵|>||||||| }↵|>||||||| count=ReadBlob(image,packet_size*image->colors,bmp_colormap);↵|>||||||| if (count != (ssize_t) (packet_size*image->colors))↵|>||||||| {↵|>||||||| bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);↵|>||||||| ThrowReaderException(CorruptImageError,↵|>||||||| "InsufficientImageDataInFile");↵|>||||||| }↵|>||||||| p=bmp_colormap;↵|>||||||| for (i=0; i < (ssize_t) image->colors; i++)↵|>||||||| {↵|>||||||| image->colormap[i].blue=(MagickRealType) ScaleCharToQuantum(*p++);↵|>||||||| image->colormap[i].green=(MagickRealType) ScaleCharToQuantum(*p++);↵|>||||||| image->colormap[i].red=(MagickRealType) ScaleCharToQuantum(*p++);↵|>||||||| if (packet_size == 4)↵|>||||||| p++;↵|>||||||| }↵|>||||||| bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);↵|>||||||| }↵|>||||||| /*↵|>||||||| Read image data.↵|>||||||| */↵|>||||||| if (bmp_info.offset_bits == offset_bits)↵|>||||||| ThrowReaderException(CorruptImageError,"ImproperImageHeader");↵|>||||||| offset_bits=bmp_info.offset_bits;↵|>||||||| offset=SeekBlob(image,start_position+bmp_info.offset_bits,SEEK_SET);↵|>||||||| if (offset < 0)↵|>||||||| ThrowReaderException(CorruptImageError,"ImproperImageHeader");↵|>||||||| if (bmp_info.compression == BI_RLE4)↵|>||||||| bmp_info.bits_per_pixel<<=1;↵|>||||||| bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);↵|>||||||| length=(size_t) bytes_per_line*image->rows;↵|>||||||| if ((MagickSizeType) (length/256) > blob_size)↵|>||||||| ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");↵|>||||||| if ((bmp_info.compression == BI_RGB) ||↵|>||||||| (bmp_info.compression == BI_BITFIELDS))↵|>||||||| {↵|>||||||| pixel_info=AcquireVirtualMemory(image->rows,↵|>||||||| MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));↵|>||||||| if (pixel_info == (MemoryInfo *) NULL)↵|>||||||| ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");↵|>||||||| pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);↵|>||||||| if (image->debug != MagickFalse)↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Reading pixels (%.20g bytes)",(double) length);↵|>||||||| count=ReadBlob(image,length,pixels);↵|>||||||| if (count != (ssize_t) length)↵|>||||||| {↵|>||||||| pixel_info=RelinquishVirtualMemory(pixel_info);↵|>||||||| ThrowReaderException(CorruptImageError,↵|>||||||| "InsufficientImageDataInFile");↵|>||||||| }↵|>||||||| }↵|>||||||| else↵|>||||||| {↵|>||||||| /*↵|>||||||| Convert run-length encoded raster pixels.↵|>||||||| */↵|>||||||| pixel_info=AcquireVirtualMemory(image->rows,↵|>||||||| MagickMax(bytes_per_line,image->columns+256UL)*sizeof(*pixels));↵|>||||||| if (pixel_info == (MemoryInfo *) NULL)↵|>||||||| ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");↵|>||||||| pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);↵|>||||||| status=DecodeImage(image,bmp_info.compression,pixels,↵|>||||||| image->columns*image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| {↵|>||||||| pixel_info=RelinquishVirtualMemory(pixel_info);↵|>||||||| ThrowReaderException(CorruptImageError,↵|>||||||| "UnableToRunlengthDecodeImage");↵|>||||||| }↵|>||||||| }↵|>||||||| /*↵|>||||||| Convert BMP raster image to pixel packets.↵|>||||||| */↵|>||||||| if (bmp_info.compression == BI_RGB)↵|>||||||| {↵|>||||||| /*↵|>||||||| We should ignore the alpha value in BMP3 files but there have been↵|>||||||| reports about 32 bit files with alpha. We do a quick check to see if↵|>||||||| the alpha channel contains a value that is not zero (default value).↵|>||||||| If we find a non zero value we asume the program that wrote the file↵|>||||||| wants to use the alpha channel.↵|>||||||| */↵|>||||||| if ((image->alpha_trait == UndefinedPixelTrait) &&↵|>||||||| (bmp_info.size == 40) && (bmp_info.bits_per_pixel == 32))↵|>||||||| {↵|>||||||| bytes_per_line=4*(image->columns);↵|>||||||| for (y=(ssize_t) image->rows-1; y >= 0; y--)↵|>||||||| {↵|>||||||| p=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| for (x=0; x < (ssize_t) image->columns; x++)↵|>||||||| {↵|>||||||| if (*(p+3) != 0)↵|>||||||| {↵|>||||||| image->alpha_trait=BlendPixelTrait;↵|>||||||| y=-1;↵|>||||||| break;↵|>||||||| }↵|>||||||| p+=4;↵|>||||||| }↵|>||||||| }↵|>||||||| }↵|>||||||| bmp_info.alpha_mask=image->alpha_trait != UndefinedPixelTrait ?↵|>||||||| 0xff000000U : 0U;↵|>||||||| bmp_info.red_mask=0x00ff0000U;↵|>||||||| bmp_info.green_mask=0x0000ff00U;↵|>||||||| bmp_info.blue_mask=0x000000ffU;↵|>||||||| if (bmp_info.bits_per_pixel == 16)↵|>||||||| {↵|>||||||| /*↵|>||||||| RGB555.↵|>||||||| */↵|>||||||| bmp_info.red_mask=0x00007c00U;↵|>||||||| bmp_info.green_mask=0x000003e0U;↵|>||||||| bmp_info.blue_mask=0x0000001fU;↵|>||||||| }↵|>||||||| }↵|>||||||| (void) memset(&shift,0,sizeof(shift));↵|>||||||| (void) memset(&quantum_bits,0,sizeof(quantum_bits));↵|>||||||| if ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32))↵|>||||||| {↵|>||||||| unsigned int↵|>||||||| sample;↵|>|||||||↵|>||||||| /*↵|>||||||| Get shift and quantum bits info from bitfield masks.↵|>||||||| */↵|>||||||| if (bmp_info.red_mask != 0)↵|>||||||| while (((bmp_info.red_mask << shift.red) & 0x80000000UL) == 0)↵|>||||||| {↵|>||||||| shift.red++;↵|>||||||| if (shift.red >= 32U)↵|>||||||| break;↵|>||||||| }↵|>||||||| if (bmp_info.green_mask != 0)↵|>||||||| while (((bmp_info.green_mask << shift.green) & 0x80000000UL) == 0)↵|>||||||| {↵|>||||||| shift.green++;↵|>||||||| if (shift.green >= 32U)↵|>||||||| break;↵|>||||||| }↵|>||||||| if (bmp_info.blue_mask != 0)↵|>||||||| while (((bmp_info.blue_mask << shift.blue) & 0x80000000UL) == 0)↵|>||||||| {↵|>||||||| shift.blue++;↵|>||||||| if (shift.blue >= 32U)↵|>||||||| break;↵|>||||||| }↵|>||||||| if (bmp_info.alpha_mask != 0)↵|>||||||| while (((bmp_info.alpha_mask << shift.alpha) & 0x80000000UL) == 0)↵|>||||||| {↵|>||||||| shift.alpha++;↵|>||||||| if (shift.alpha >= 32U)↵|>||||||| break;↵|>||||||| }↵|>||||||| sample=shift.red;↵|>||||||| while (((bmp_info.red_mask << sample) & 0x80000000UL) != 0)↵|>||||||| {↵|>||||||| sample++;↵|>||||||| if (sample >= 32U)↵|>||||||| break;↵|>||||||| }↵|>||||||| quantum_bits.red=(MagickRealType) (sample-shift.red);↵|>||||||| sample=shift.green;↵|>||||||| while (((bmp_info.green_mask << sample) & 0x80000000UL) != 0)↵|>||||||| {↵|>||||||| sample++;↵|>||||||| if (sample >= 32U)↵|>||||||| break;↵|>||||||| }↵|>||||||| quantum_bits.green=(MagickRealType) (sample-shift.green);↵|>||||||| sample=shift.blue;↵|>||||||| while (((bmp_info.blue_mask << sample) & 0x80000000UL) != 0)↵|>||||||| {↵|>||||||| sample++;↵|>||||||| if (sample >= 32U)↵|>||||||| break;↵|>||||||| }↵|>||||||| quantum_bits.blue=(MagickRealType) (sample-shift.blue);↵|>||||||| sample=shift.alpha;↵|>||||||| while (((bmp_info.alpha_mask << sample) & 0x80000000UL) != 0)↵|>||||||| {↵|>||||||| sample++;↵|>||||||| if (sample >= 32U)↵|>||||||| break;↵|>||||||| }↵|>||||||| quantum_bits.alpha=(MagickRealType) (sample-shift.alpha);↵|>||||||| }↵|>||||||| switch (bmp_info.bits_per_pixel)↵|>||||||| {↵|>||||||| case 1:↵|>||||||| {↵|>||||||| /*↵|>||||||| Convert bitmap scanline.↵|>||||||| */↵|>||||||| for (y=(ssize_t) image->rows-1; y >= 0; y--)↵|>||||||| {↵|>||||||| p=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (q == (Quantum *) NULL)↵|>||||||| break;↵|>||||||| for (x=0; x < ((ssize_t) image->columns-7); x+=8)↵|>||||||| {↵|>||||||| for (bit=0; bit < 8; bit++)↵|>||||||| {↵|>||||||| index=(Quantum) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);↵|>||||||| SetPixelIndex(image,index,q);↵|>||||||| q+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| p++;↵|>||||||| }↵|>||||||| if ((image->columns % 8) != 0)↵|>||||||| {↵|>||||||| for (bit=0; bit < (image->columns % 8); bit++)↵|>||||||| {↵|>||||||| index=(Quantum) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);↵|>||||||| SetPixelIndex(image,index,q);↵|>||||||| q+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| p++;↵|>||||||| }↵|>||||||| if (SyncAuthenticPixels(image,exception) == MagickFalse)↵|>||||||| break;↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)↵|>||||||| (image->rows-y),image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| (void) SyncImage(image,exception);↵|>||||||| break;↵|>||||||| }↵|>||||||| case 4:↵|>||||||| {↵|>||||||| /*↵|>||||||| Convert PseudoColor scanline.↵|>||||||| */↵|>||||||| for (y=(ssize_t) image->rows-1; y >= 0; y--)↵|>||||||| {↵|>||||||| p=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (q == (Quantum *) NULL)↵|>||||||| break;↵|>||||||| for (x=0; x < ((ssize_t) image->columns-1); x+=2)↵|>||||||| {↵|>||||||| ValidateColormapValue(image,(ssize_t) ((*p >> 4) & 0x0f),&index,↵|>||||||| exception);↵|>||||||| SetPixelIndex(image,index,q);↵|>||||||| q+=GetPixelChannels(image);↵|>||||||| ValidateColormapValue(image,(ssize_t) (*p & 0x0f),&index,exception);↵|>||||||| SetPixelIndex(image,index,q);↵|>||||||| q+=GetPixelChannels(image);↵|>||||||| p++;↵|>||||||| }↵|>||||||| if ((image->columns % 2) != 0)↵|>||||||| {↵|>||||||| ValidateColormapValue(image,(ssize_t) ((*p >> 4) & 0xf),&index,↵|>||||||| exception);↵|>||||||| SetPixelIndex(image,index,q);↵|>||||||| q+=GetPixelChannels(image);↵|>||||||| p++;↵|>||||||| x++;↵|>||||||| }↵|>||||||| if (x < (ssize_t) image->columns)↵|>||||||| break;↵|>||||||| if (SyncAuthenticPixels(image,exception) == MagickFalse)↵|>||||||| break;↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)↵|>||||||| (image->rows-y),image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| (void) SyncImage(image,exception);↵|>||||||| break;↵|>||||||| }↵|>||||||| case 8:↵|>||||||| {↵|>||||||| /*↵|>||||||| Convert PseudoColor scanline.↵|>||||||| */↵|>||||||| if ((bmp_info.compression == BI_RLE8) ||↵|>||||||| (bmp_info.compression == BI_RLE4))↵|>||||||| bytes_per_line=image->columns;↵|>||||||| for (y=(ssize_t) image->rows-1; y >= 0; y--)↵|>||||||| {↵|>||||||| p=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (q == (Quantum *) NULL)↵|>||||||| break;↵|>||||||| for (x=(ssize_t) image->columns; x != 0; --x)↵|>||||||| {↵|>||||||| ValidateColormapValue(image,(ssize_t) *p++,&index,exception);↵|>||||||| SetPixelIndex(image,index,q);↵|>||||||| q+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| if (SyncAuthenticPixels(image,exception) == MagickFalse)↵|>||||||| break;↵|>||||||| offset=(MagickOffsetType) (image->rows-y-1);↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)↵|>||||||| (image->rows-y),image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| (void) SyncImage(image,exception);↵|>||||||| break;↵|>||||||| }↵|>||||||| case 16:↵|>||||||| {↵|>||||||| unsigned int↵|>||||||| alpha,↵|>||||||| pixel;↵|>|||||||↵|>||||||| /*↵|>||||||| Convert bitfield encoded 16-bit PseudoColor scanline.↵|>||||||| */↵|>||||||| if ((bmp_info.compression != BI_RGB) &&↵|>||||||| (bmp_info.compression != BI_BITFIELDS))↵|>||||||| {↵|>||||||| pixel_info=RelinquishVirtualMemory(pixel_info);↵|>||||||| ThrowReaderException(CorruptImageError,↵|>||||||| "UnrecognizedImageCompression");↵|>||||||| }↵|>||||||| bytes_per_line=2*(image->columns+image->columns % 2);↵|>||||||| image->storage_class=DirectClass;↵|>||||||| for (y=(ssize_t) image->rows-1; y >= 0; y--)↵|>||||||| {↵|>||||||| p=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (q == (Quantum *) NULL)↵|>||||||| break;↵|>||||||| for (x=0; x < (ssize_t) image->columns; x++)↵|>||||||| {↵|>||||||| pixel=(unsigned int) (*p++);↵|>||||||| pixel|=(*p++) << 8;↵|>||||||| red=((pixel & bmp_info.red_mask) << shift.red) >> 16;↵|>||||||| if (quantum_bits.red == 5)↵|>||||||| red|=((red & 0xe000) >> 5);↵|>||||||| if (quantum_bits.red <= 8)↵|>||||||| red|=((red & 0xff00) >> 8);↵|>||||||| green=((pixel & bmp_info.green_mask) << shift.green) >> 16;↵|>||||||| if (quantum_bits.green == 5)↵|>||||||| green|=((green & 0xe000) >> 5);↵|>||||||| if (quantum_bits.green == 6)↵|>||||||| green|=((green & 0xc000) >> 6);↵|>||||||| if (quantum_bits.green <= 8)↵|>||||||| green|=((green & 0xff00) >> 8);↵|>||||||| blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;↵|>||||||| if (quantum_bits.blue == 5)↵|>||||||| blue|=((blue & 0xe000) >> 5);↵|>||||||| if (quantum_bits.blue <= 8)↵|>||||||| blue|=((blue & 0xff00) >> 8);↵|>||||||| SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);↵|>||||||| SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);↵|>||||||| SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);↵|>||||||| SetPixelAlpha(image,OpaqueAlpha,q);↵|>||||||| if (image->alpha_trait != UndefinedPixelTrait)↵|>||||||| {↵|>||||||| alpha=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;↵|>||||||| if (quantum_bits.alpha <= 8)↵|>||||||| alpha|=((alpha & 0xff00) >> 8);↵|>||||||| SetPixelAlpha(image,ScaleShortToQuantum(↵|>||||||| (unsigned short) alpha),q);↵|>||||||| }↵|>||||||| q+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| if (SyncAuthenticPixels(image,exception) == MagickFalse)↵|>||||||| break;↵|>||||||| offset=(MagickOffsetType) (image->rows-y-1);↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)↵|>||||||| (image->rows-y),image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| break;↵|>||||||| }↵|>||||||| case 24:↵|>||||||| {↵|>||||||| /*↵|>||||||| Convert DirectColor scanline.↵|>||||||| */↵|>||||||| bytes_per_line=4*((image->columns*24+31)/32);↵|>||||||| for (y=(ssize_t) image->rows-1; y >= 0; y--)↵|>||||||| {↵|>||||||| p=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (q == (Quantum *) NULL)↵|>||||||| break;↵|>||||||| for (x=0; x < (ssize_t) image->columns; x++)↵|>||||||| {↵|>||||||| SetPixelBlue(image,ScaleCharToQuantum(*p++),q);↵|>||||||| SetPixelGreen(image,ScaleCharToQuantum(*p++),q);↵|>||||||| SetPixelRed(image,ScaleCharToQuantum(*p++),q);↵|>||||||| SetPixelAlpha(image,OpaqueAlpha,q);↵|>||||||| q+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| if (SyncAuthenticPixels(image,exception) == MagickFalse)↵|>||||||| break;↵|>||||||| offset=(MagickOffsetType) (image->rows-y-1);↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)↵|>||||||| (image->rows-y),image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| break;↵|>||||||| }↵|>||||||| case 32:↵|>||||||| {↵|>||||||| /*↵|>||||||| Convert bitfield encoded DirectColor scanline.↵|>||||||| */↵|>||||||| if ((bmp_info.compression != BI_RGB) &&↵|>||||||| (bmp_info.compression != BI_BITFIELDS))↵|>||||||| {↵|>||||||| pixel_info=RelinquishVirtualMemory(pixel_info);↵|>||||||| ThrowReaderException(CorruptImageError,↵|>||||||| "UnrecognizedImageCompression");↵|>||||||| }↵|>||||||| bytes_per_line=4*(image->columns);↵|>||||||| for (y=(ssize_t) image->rows-1; y >= 0; y--)↵|>||||||| {↵|>||||||| unsigned int↵|>||||||| alpha,↵|>||||||| pixel;↵|>|||||||↵|>||||||| p=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (q == (Quantum *) NULL)↵|>||||||| break;↵|>||||||| for (x=0; x < (ssize_t) image->columns; x++)↵|>||||||| {↵|>||||||| pixel=(unsigned int) (*p++);↵|>||||||| pixel|=((unsigned int) *p++ << 8);↵|>||||||| pixel|=((unsigned int) *p++ << 16);↵|>||||||| pixel|=((unsigned int) *p++ << 24);↵|>||||||| red=((pixel & bmp_info.red_mask) << shift.red) >> 16;↵|>||||||| if (quantum_bits.red == 8)↵|>||||||| red|=(red >> 8);↵|>||||||| green=((pixel & bmp_info.green_mask) << shift.green) >> 16;↵|>||||||| if (quantum_bits.green == 8)↵|>||||||| green|=(green >> 8);↵|>||||||| blue=((pixel & bmp_info.blue_mask) << shift.blue) >> 16;↵|>||||||| if (quantum_bits.blue == 8)↵|>||||||| blue|=(blue >> 8);↵|>||||||| SetPixelRed(image,ScaleShortToQuantum((unsigned short) red),q);↵|>||||||| SetPixelGreen(image,ScaleShortToQuantum((unsigned short) green),q);↵|>||||||| SetPixelBlue(image,ScaleShortToQuantum((unsigned short) blue),q);↵|>||||||| SetPixelAlpha(image,OpaqueAlpha,q);↵|>||||||| if (image->alpha_trait != UndefinedPixelTrait)↵|>||||||| {↵|>||||||| alpha=((pixel & bmp_info.alpha_mask) << shift.alpha) >> 16;↵|>||||||| if (quantum_bits.alpha == 8)↵|>||||||| alpha|=(alpha >> 8);↵|>||||||| SetPixelAlpha(image,ScaleShortToQuantum(↵|>||||||| (unsigned short) alpha),q);↵|>||||||| }↵|>||||||| q+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| if (SyncAuthenticPixels(image,exception) == MagickFalse)↵|>||||||| break;↵|>||||||| offset=(MagickOffsetType) (image->rows-y-1);↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,LoadImageTag,(MagickOffsetType)↵|>||||||| (image->rows-y),image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| break;↵|>||||||| }↵|>||||||| default:↵|>||||||| {↵|>||||||| pixel_info=RelinquishVirtualMemory(pixel_info);↵|>||||||| ThrowReaderException(CorruptImageError,"ImproperImageHeader");↵|>||||||| }↵|>||||||| }↵|>||||||| pixel_info=RelinquishVirtualMemory(pixel_info);↵|>||||||| if (y > 0)↵|>||||||| break;↵|>||||||| if (EOFBlob(image) != MagickFalse)↵|>||||||| {↵|>||||||| ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",↵|>||||||| image->filename);↵|>||||||| break;↵|>||||||| }↵|>||||||| if (bmp_info.height < 0)↵|>||||||| {↵|>||||||| Image↵|>||||||| *flipped_image;↵|>|||||||↵|>||||||| /*↵|>||||||| Correct image orientation.↵|>||||||| */↵|>||||||| flipped_image=FlipImage(image,exception);↵|>||||||| if (flipped_image != (Image *) NULL)↵|>||||||| {↵|>||||||| DuplicateBlob(flipped_image,image);↵|>||||||| ReplaceImageInList(&image, flipped_image);↵|>||||||| image=flipped_image;↵|>||||||| }↵|>||||||| }↵|>||||||| /*↵|>||||||| Read embeded ICC profile↵|>||||||| */↵|>||||||| if ((bmp_info.colorspace == 0x4D424544L) && (profile_data > 0) &&↵|>||||||| (profile_size > 0))↵|>||||||| {↵|>||||||| StringInfo↵|>||||||| *profile;↵|>|||||||↵|>||||||| unsigned char↵|>||||||| *datum;↵|>|||||||↵|>||||||| offset=start_position+14+profile_data;↵|>||||||| if ((offset < TellBlob(image)) ||↵|>||||||| (SeekBlob(image,offset,SEEK_SET) != offset) ||↵|>||||||| (blob_size < (MagickSizeType) (offset+profile_size)))↵|>||||||| ThrowReaderException(CorruptImageError,"ImproperImageHeader");↵|>||||||| profile=AcquireStringInfo((size_t) profile_size);↵|>||||||| if (profile == (StringInfo *) NULL)↵|>||||||| ThrowReaderException(CorruptImageError,"MemoryAllocationFailed");↵|>||||||| datum=GetStringInfoDatum(profile);↵|>||||||| if (ReadBlob(image,(size_t) profile_size,datum) == (ssize_t) profile_size)↵|>||||||| {↵|>||||||| MagickOffsetType↵|>||||||| profile_size_orig;↵|>|||||||↵|>||||||| /*↵|>||||||| Trimming padded bytes.↵|>||||||| */↵|>||||||| profile_size_orig=(MagickOffsetType) datum[0] << 24;↵|>||||||| profile_size_orig|=(MagickOffsetType) datum[1] << 16;↵|>||||||| profile_size_orig|=(MagickOffsetType) datum[2] << 8;↵|>||||||| profile_size_orig|=(MagickOffsetType) datum[3];↵|>||||||| if (profile_size_orig < profile_size)↵|>||||||| SetStringInfoLength(profile,(size_t) profile_size_orig);↵|>||||||| if (image->debug != MagickFalse)↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| "Profile: ICC, %u bytes",(unsigned int) profile_size_orig);↵|>||||||| (void) SetImageProfile(image,"icc",profile,exception);↵|>||||||| }↵|>||||||| profile=DestroyStringInfo(profile);↵|>||||||| }↵|>||||||| /*↵|>||||||| Proceed to next image.↵|>||||||| */↵|>||||||| if (image_info->number_scenes != 0)↵|>||||||| if (image->scene >= (image_info->scene+image_info->number_scenes-1))↵|>||||||| break;↵|>||||||| offset=(MagickOffsetType) bmp_info.ba_offset;↵|>||||||| if (offset != 0)↵|>||||||| if ((offset < TellBlob(image)) ||↵|>||||||| (SeekBlob(image,offset,SEEK_SET) != offset))↵|>||||||| ThrowReaderException(CorruptImageError,"ImproperImageHeader");↵|>||||||| *magick='\0';↵|>||||||| count=ReadBlob(image,2,magick);↵|>||||||| if ((count == 2) && (IsBMP(magick,2) != MagickFalse))↵|>||||||| {↵|>||||||| /*↵|>||||||| Acquire next image structure.↵|>||||||| */↵|>||||||| AcquireNextImage(image_info,image,exception);↵|>||||||| if (GetNextImageInList(image) == (Image *) NULL)↵|>||||||| {↵|>||||||| status=MagickFalse;↵|>||||||| break;↵|>||||||| }↵|>||||||| image=SyncNextImageInList(image);↵|>||||||| status=SetImageProgress(image,LoadImagesTag,TellBlob(image),blob_size);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| } while (IsBMP(magick,2) != MagickFalse);↵|>||||||| (void) CloseBlob(image);↵|>||||||| if (status == MagickFalse)↵|>||||||| return(DestroyImageList(image));↵|>||||||| return(GetFirstImageInList(image));↵|>|||||||}↵|>||||||| ↵|>|||||||/*↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% R e g i s t e r B M P I m a g e %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||%↵|>|||||||% RegisterBMPImage() adds attributes for the BMP image format to↵|>|||||||% the list of supported formats. The attributes include the image format↵|>|||||||% tag, a method to read and/or write the format, whether the format↵|>|||||||% supports the saving of more than one frame to the same file or blob,↵|>|||||||% whether the format supports native in-memory I/O, and a brief↵|>|||||||% description of the format.↵|>|||||||%↵|>|||||||% The format of the RegisterBMPImage method is:↵|>|||||||%↵|>|||||||% size_t RegisterBMPImage(void)↵|>|||||||%↵|>|||||||*/↵|>|||||||ModuleExport size_t RegisterBMPImage(void)↵|>|||||||{↵|>||||||| MagickInfo↵|>||||||| *entry;↵|>|||||||↵|>||||||| entry=AcquireMagickInfo("BMP","BMP","Microsoft Windows bitmap image");↵|>||||||| entry->decoder=(DecodeImageHandler *) ReadBMPImage;↵|>||||||| entry->encoder=(EncodeImageHandler *) WriteBMPImage;↵|>||||||| entry->magick=(IsImageFormatHandler *) IsBMP;↵|>||||||| entry->flags^=CoderAdjoinFlag;↵|>||||||| entry->flags|=CoderDecoderSeekableStreamFlag;↵|>||||||| entry->mime_type=ConstantString("image/bmp");↵|>||||||| (void) RegisterMagickInfo(entry);↵|>||||||| entry=AcquireMagickInfo("BMP","BMP2","Microsoft Windows bitmap image (V2)");↵|>||||||| entry->decoder=(DecodeImageHandler *) ReadBMPImage;↵|>||||||| entry->encoder=(EncodeImageHandler *) WriteBMPImage;↵|>||||||| entry->magick=(IsImageFormatHandler *) IsBMP;↵|>||||||| entry->flags^=CoderAdjoinFlag;↵|>||||||| entry->flags|=CoderDecoderSeekableStreamFlag;↵|>||||||| entry->mime_type=ConstantString("image/bmp");↵|>||||||| (void) RegisterMagickInfo(entry);↵|>||||||| entry=AcquireMagickInfo("BMP","BMP3","Microsoft Windows bitmap image (V3)");↵|>||||||| entry->decoder=(DecodeImageHandler *) ReadBMPImage;↵|>||||||| entry->encoder=(EncodeImageHandler *) WriteBMPImage;↵|>||||||| entry->magick=(IsImageFormatHandler *) IsBMP;↵|>||||||| entry->flags^=CoderAdjoinFlag;↵|>||||||| entry->flags|=CoderDecoderSeekableStreamFlag;↵|>||||||| entry->mime_type=ConstantString("image/bmp");↵|>||||||| (void) RegisterMagickInfo(entry);↵|>||||||| return(MagickImageCoderSignature);↵|>|||||||}↵|>||||||| ↵|>|||||||/*↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% U n r e g i s t e r B M P I m a g e %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||%↵|>|||||||% UnregisterBMPImage() removes format registrations made by the↵|>|||||||% BMP module from the list of supported formats.↵|>|||||||%↵|>|||||||% The format of the UnregisterBMPImage method is:↵|>|||||||%↵|>|||||||% UnregisterBMPImage(void)↵|>|||||||%↵|>|||||||*/↵|>|||||||ModuleExport void UnregisterBMPImage(void)↵|>|||||||{↵|>||||||| (void) UnregisterMagickInfo("BMP");↵|>||||||| (void) UnregisterMagickInfo("BMP2");↵|>||||||| (void) UnregisterMagickInfo("BMP3");↵|>|||||||}↵|>||||||| ↵|>|||||||/*↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% W r i t e B M P I m a g e %↵|>|||||||% %↵|>|||||||% %↵|>|||||||% %↵|>|||||||%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%↵|>|||||||%↵|>|||||||% WriteBMPImage() writes an image in Microsoft Windows bitmap encoded↵|>|||||||% image format, version 3 for Windows or (if the image has a matte channel)↵|>|||||||% version 4.↵|>|||||||%↵|>|||||||% The format of the WriteBMPImage method is:↵|>|||||||%↵|>|||||||% MagickBooleanType WriteBMPImage(const ImageInfo *image_info,↵|>|||||||% Image *image,ExceptionInfo *exception)↵|>|||||||%↵|>|||||||% A description of each parameter follows.↵|>|||||||%↵|>|||||||% o image_info: the image info.↵|>|||||||%↵|>|||||||% o image: The image.↵|>|||||||%↵|>|||||||% o exception: return any errors or warnings in this structure.↵|>|||||||%↵|>|||||||*/↵|>|||||||static MagickBooleanType WriteBMPImage(const ImageInfo *image_info,Image *image,↵|>||||||| ExceptionInfo *exception)↵|>|||||||{↵|>||||||| BMPInfo↵|>||||||| bmp_info;↵|>|||||||↵|>||||||| BMPSubtype↵|>||||||| bmp_subtype;↵|>|||||||↵|>||||||| const char↵|>||||||| *option;↵|>|||||||↵|>||||||| const StringInfo↵|>||||||| *profile;↵|>|||||||↵|>||||||| MagickBooleanType↵|>||||||| have_color_info,↵|>||||||| status;↵|>|||||||↵|>||||||| MagickOffsetType↵|>||||||| scene;↵|>|||||||↵|>||||||| MemoryInfo↵|>||||||| *pixel_info;↵|>|||||||↵|>||||||| const Quantum↵|>||||||| *p;↵|>|||||||↵|>||||||| ssize_t↵|>||||||| i,↵|>||||||| x;↵|>|||||||↵|>||||||| unsigned char↵|>||||||| *q;↵|>|||||||↵|>||||||| size_t↵|>||||||| bytes_per_line,↵|>||||||| imageListLength,↵|>||||||| type;↵|>|||||||↵|>||||||| ssize_t↵|>||||||| y;↵|>|||||||↵|>||||||| unsigned char↵|>||||||| *bmp_data,↵|>||||||| *pixels;↵|>|||||||↵|>||||||| MagickOffsetType↵|>||||||| profile_data,↵|>||||||| profile_size,↵|>||||||| profile_size_pad;↵|>|||||||↵|>||||||| /*↵|>||||||| Open output image file.↵|>||||||| */↵|>||||||| assert(image_info != (const ImageInfo *) NULL);↵|>||||||| assert(image_info->signature == MagickCoreSignature);↵|>||||||| assert(image != (Image *) NULL);↵|>||||||| assert(image->signature == MagickCoreSignature);↵|>||||||| assert(exception != (ExceptionInfo *) NULL);↵|>||||||| assert(exception->signature == MagickCoreSignature);↵|>||||||| if (IsEventLogging() != MagickFalse)↵|>||||||| (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);↵|>||||||| status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);↵|>||||||| if (status == MagickFalse)↵|>||||||| return(status);↵|>||||||| if (((image->columns << 3) != (size_t) ((int) (image->columns << 3))) ||↵|>||||||| ((image->rows << 3) != (size_t) ((int) (image->rows << 3))))↵|>||||||| ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");↵|>||||||| type=4;↵|>||||||| if (LocaleCompare(image_info->magick,"BMP2") == 0)↵|>||||||| type=2;↵|>||||||| else↵|>||||||| if (LocaleCompare(image_info->magick,"BMP3") == 0)↵|>||||||| type=3;↵|>||||||| option=GetImageOption(image_info,"bmp:format");↵|>||||||| if (option != (char *) NULL)↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Format=%s",option);↵|>||||||| if (LocaleCompare(option,"bmp2") == 0)↵|>||||||| type=2;↵|>||||||| if (LocaleCompare(option,"bmp3") == 0)↵|>||||||| type=3;↵|>||||||| if (LocaleCompare(option,"bmp4") == 0)↵|>||||||| type=4;↵|>||||||| }↵|>||||||| scene=0;↵|>||||||| imageListLength=GetImageListLength(image);↵|>||||||| do↵|>||||||| {↵|>||||||| /*↵|>||||||| Initialize BMP raster file header.↵|>||||||| */↵|>||||||| if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)↵|>||||||| (void) TransformImageColorspace(image,sRGBColorspace,exception);↵|>||||||| (void) memset(&bmp_info,0,sizeof(bmp_info));↵|>||||||| bmp_info.file_size=14+12;↵|>||||||| if (type > 2)↵|>||||||| bmp_info.file_size+=28;↵|>||||||| bmp_info.offset_bits=bmp_info.file_size;↵|>||||||| bmp_info.compression=BI_RGB;↵|>||||||| bmp_info.red_mask=0x00ff0000U;↵|>||||||| bmp_info.green_mask=0x0000ff00U;↵|>||||||| bmp_info.blue_mask=0x000000ffU;↵|>||||||| bmp_info.alpha_mask=0xff000000U;↵|>||||||| bmp_subtype=UndefinedSubtype;↵|>||||||| if ((image->storage_class == PseudoClass) && (image->colors > 256))↵|>||||||| (void) SetImageStorageClass(image,DirectClass,exception);↵|>||||||| if (image->storage_class != DirectClass)↵|>||||||| {↵|>||||||| /*↵|>||||||| Colormapped BMP raster.↵|>||||||| */↵|>||||||| bmp_info.bits_per_pixel=8;↵|>||||||| if (image->colors <= 2)↵|>||||||| bmp_info.bits_per_pixel=1;↵|>||||||| else↵|>||||||| if (image->colors <= 16)↵|>||||||| bmp_info.bits_per_pixel=4;↵|>||||||| else↵|>||||||| if (image->colors <= 256)↵|>||||||| bmp_info.bits_per_pixel=8;↵|>||||||| if (image_info->compression == RLECompression)↵|>||||||| bmp_info.bits_per_pixel=8;↵|>||||||| bmp_info.number_colors=1U << bmp_info.bits_per_pixel;↵|>||||||| if (image->alpha_trait != UndefinedPixelTrait)↵|>||||||| (void) SetImageStorageClass(image,DirectClass,exception);↵|>||||||| else↵|>||||||| if ((size_t) bmp_info.number_colors < image->colors)↵|>||||||| (void) SetImageStorageClass(image,DirectClass,exception);↵|>||||||| else↵|>||||||| {↵|>||||||| bmp_info.file_size+=3*(1UL << bmp_info.bits_per_pixel);↵|>||||||| bmp_info.offset_bits+=3*(1UL << bmp_info.bits_per_pixel);↵|>||||||| if (type > 2)↵|>||||||| {↵|>||||||| bmp_info.file_size+=(1UL << bmp_info.bits_per_pixel);↵|>||||||| bmp_info.offset_bits+=(1UL << bmp_info.bits_per_pixel);↵|>||||||| }↵|>||||||| }↵|>||||||| }↵|>||||||| if (image->storage_class == DirectClass)↵|>||||||| {↵|>||||||| /*↵|>||||||| Full color BMP raster.↵|>||||||| */↵|>||||||| bmp_info.number_colors=0;↵|>||||||| option=GetImageOption(image_info,"bmp:subtype");↵|>||||||| if (option != (const char *) NULL)↵|>||||||| {↵|>||||||| if (image->alpha_trait != UndefinedPixelTrait)↵|>||||||| {↵|>||||||| if (LocaleNCompare(option,"ARGB4444",8) == 0)↵|>||||||| {↵|>||||||| bmp_subtype=ARGB4444;↵|>||||||| bmp_info.red_mask=0x00000f00U;↵|>||||||| bmp_info.green_mask=0x000000f0U;↵|>||||||| bmp_info.blue_mask=0x0000000fU;↵|>||||||| bmp_info.alpha_mask=0x0000f000U;↵|>||||||| }↵|>||||||| else if (LocaleNCompare(option,"ARGB1555",8) == 0)↵|>||||||| {↵|>||||||| bmp_subtype=ARGB1555;↵|>||||||| bmp_info.red_mask=0x00007c00U;↵|>||||||| bmp_info.green_mask=0x000003e0U;↵|>||||||| bmp_info.blue_mask=0x0000001fU;↵|>||||||| bmp_info.alpha_mask=0x00008000U;↵|>||||||| }↵|>||||||| }↵|>||||||| else↵|>||||||| {↵|>||||||| if (LocaleNCompare(option,"RGB555",6) == 0)↵|>||||||| {↵|>||||||| bmp_subtype=RGB555;↵|>||||||| bmp_info.red_mask=0x00007c00U;↵|>||||||| bmp_info.green_mask=0x000003e0U;↵|>||||||| bmp_info.blue_mask=0x0000001fU;↵|>||||||| bmp_info.alpha_mask=0U;↵|>||||||| }↵|>||||||| else if (LocaleNCompare(option,"RGB565",6) == 0)↵|>||||||| {↵|>||||||| bmp_subtype=RGB565;↵|>||||||| bmp_info.red_mask=0x0000f800U;↵|>||||||| bmp_info.green_mask=0x000007e0U;↵|>||||||| bmp_info.blue_mask=0x0000001fU;↵|>||||||| bmp_info.alpha_mask=0U;↵|>||||||| }↵|>||||||| }↵|>||||||| }↵|>||||||| if (bmp_subtype != UndefinedSubtype)↵|>||||||| {↵|>||||||| bmp_info.bits_per_pixel=16;↵|>||||||| bmp_info.compression=BI_BITFIELDS;↵|>||||||| }↵|>||||||| else↵|>||||||| {↵|>||||||| bmp_info.bits_per_pixel=(unsigned short) ((type > 3) &&↵|>||||||| (image->alpha_trait != UndefinedPixelTrait) ? 32 : 24);↵|>||||||| bmp_info.compression=(unsigned int) ((type > 3) &&↵|>||||||| (image->alpha_trait != UndefinedPixelTrait) ? BI_BITFIELDS : BI_RGB);↵|>||||||| if ((type == 3) && (image->alpha_trait != UndefinedPixelTrait))↵|>||||||| {↵|>||||||| option=GetImageOption(image_info,"bmp3:alpha");↵|>||||||| if (IsStringTrue(option))↵|>||||||| bmp_info.bits_per_pixel=32;↵|>||||||| }↵|>||||||| }↵|>||||||| }↵|>||||||| bytes_per_line=4*((image->columns*bmp_info.bits_per_pixel+31)/32);↵|>||||||| bmp_info.ba_offset=0;↵|>||||||| profile=GetImageProfile(image,"icc");↵|>||||||| have_color_info=(image->rendering_intent != UndefinedIntent) ||↵|>||||||| (profile != (StringInfo *) NULL) || (image->gamma != 0.0) ? MagickTrue :↵|>||||||| MagickFalse;↵|>||||||| if (type == 2)↵|>||||||| bmp_info.size=12;↵|>||||||| else↵|>||||||| if ((type == 3) || ((image->alpha_trait == UndefinedPixelTrait) &&↵|>||||||| (have_color_info == MagickFalse)))↵|>||||||| {↵|>||||||| type=3;↵|>||||||| bmp_info.size=40;↵|>||||||| }↵|>||||||| else↵|>||||||| {↵|>||||||| int↵|>||||||| extra_size;↵|>|||||||↵|>||||||| bmp_info.size=108;↵|>||||||| extra_size=68;↵|>||||||| if ((image->rendering_intent != UndefinedIntent) ||↵|>||||||| (profile != (StringInfo *) NULL))↵|>||||||| {↵|>||||||| bmp_info.size=124;↵|>||||||| extra_size+=16;↵|>||||||| }↵|>||||||| bmp_info.file_size+=extra_size;↵|>||||||| bmp_info.offset_bits+=extra_size;↵|>||||||| }↵|>||||||| if (((ssize_t) image->columns != (ssize_t) ((signed int) image->columns)) ||↵|>||||||| ((ssize_t) image->rows != (ssize_t) ((signed int) image->rows)))↵|>||||||| ThrowWriterException(ImageError,"WidthOrHeightExceedsLimit");↵|>||||||| bmp_info.width=(ssize_t) image->columns;↵|>||||||| bmp_info.height=(ssize_t) image->rows;↵|>||||||| bmp_info.planes=1;↵|>||||||| bmp_info.image_size=(unsigned int) (bytes_per_line*image->rows);↵|>||||||| bmp_info.file_size+=bmp_info.image_size;↵|>||||||| bmp_info.x_pixels=75*39;↵|>||||||| bmp_info.y_pixels=75*39;↵|>||||||| switch (image->units)↵|>||||||| {↵|>||||||| case UndefinedResolution:↵|>||||||| case PixelsPerInchResolution:↵|>||||||| {↵|>||||||| bmp_info.x_pixels=(unsigned int) (100.0*image->resolution.x/2.54);↵|>||||||| bmp_info.y_pixels=(unsigned int) (100.0*image->resolution.y/2.54);↵|>||||||| break;↵|>||||||| }↵|>||||||| case PixelsPerCentimeterResolution:↵|>||||||| {↵|>||||||| bmp_info.x_pixels=(unsigned int) (100.0*image->resolution.x);↵|>||||||| bmp_info.y_pixels=(unsigned int) (100.0*image->resolution.y);↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| bmp_info.colors_important=bmp_info.number_colors;↵|>||||||| /*↵|>||||||| Convert MIFF to BMP raster pixels.↵|>||||||| */↵|>||||||| pixel_info=AcquireVirtualMemory(image->rows,MagickMax(bytes_per_line,↵|>||||||| image->columns+256UL)*sizeof(*pixels));↵|>||||||| if (pixel_info == (MemoryInfo *) NULL)↵|>||||||| ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");↵|>||||||| pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);↵|>||||||| (void) memset(pixels,0,(size_t) bmp_info.image_size);↵|>||||||| switch (bmp_info.bits_per_pixel)↵|>||||||| {↵|>||||||| case 1:↵|>||||||| {↵|>||||||| size_t↵|>||||||| bit,↵|>||||||| byte;↵|>|||||||↵|>||||||| /*↵|>||||||| Convert PseudoClass image to a BMP monochrome image.↵|>||||||| */↵|>||||||| for (y=0; y < (ssize_t) image->rows; y++)↵|>||||||| {↵|>||||||| ssize_t↵|>||||||| offset;↵|>|||||||↵|>||||||| p=GetVirtualPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (p == (const Quantum *) NULL)↵|>||||||| break;↵|>||||||| q=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| bit=0;↵|>||||||| byte=0;↵|>||||||| for (x=0; x < (ssize_t) image->columns; x++)↵|>||||||| {↵|>||||||| byte<<=1;↵|>||||||| byte|=GetPixelIndex(image,p) != 0 ? 0x01 : 0x00;↵|>||||||| bit++;↵|>||||||| if (bit == 8)↵|>||||||| {↵|>||||||| *q++=(unsigned char) byte;↵|>||||||| bit=0;↵|>||||||| byte=0;↵|>||||||| }↵|>||||||| p+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| if (bit != 0)↵|>||||||| {↵|>||||||| *q++=(unsigned char) (byte << (8-bit));↵|>||||||| x++;↵|>||||||| }↵|>||||||| offset=(ssize_t) (image->columns+7)/8;↵|>||||||| for (x=offset; x < (ssize_t) bytes_per_line; x++)↵|>||||||| *q++=0x00;↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,↵|>||||||| image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| break;↵|>||||||| }↵|>||||||| case 4:↵|>||||||| {↵|>||||||| unsigned int↵|>||||||| byte,↵|>||||||| nibble;↵|>|||||||↵|>||||||| ssize_t↵|>||||||| offset;↵|>|||||||↵|>||||||| /*↵|>||||||| Convert PseudoClass image to a BMP monochrome image.↵|>||||||| */↵|>||||||| for (y=0; y < (ssize_t) image->rows; y++)↵|>||||||| {↵|>||||||| p=GetVirtualPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (p == (const Quantum *) NULL)↵|>||||||| break;↵|>||||||| q=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| nibble=0;↵|>||||||| byte=0;↵|>||||||| for (x=0; x < (ssize_t) image->columns; x++)↵|>||||||| {↵|>||||||| byte<<=4;↵|>||||||| byte|=((unsigned int) GetPixelIndex(image,p) & 0x0f);↵|>||||||| nibble++;↵|>||||||| if (nibble == 2)↵|>||||||| {↵|>||||||| *q++=(unsigned char) byte;↵|>||||||| nibble=0;↵|>||||||| byte=0;↵|>||||||| }↵|>||||||| p+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| if (nibble != 0)↵|>||||||| {↵|>||||||| *q++=(unsigned char) (byte << 4);↵|>||||||| x++;↵|>||||||| }↵|>||||||| offset=(ssize_t) (image->columns+1)/2;↵|>||||||| for (x=offset; x < (ssize_t) bytes_per_line; x++)↵|>||||||| *q++=0x00;↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,↵|>||||||| image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| break;↵|>||||||| }↵|>||||||| case 8:↵|>||||||| {↵|>||||||| /*↵|>||||||| Convert PseudoClass packet to BMP pixel.↵|>||||||| */↵|>||||||| for (y=0; y < (ssize_t) image->rows; y++)↵|>||||||| {↵|>||||||| p=GetVirtualPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (p == (const Quantum *) NULL)↵|>||||||| break;↵|>||||||| q=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| for (x=0; x < (ssize_t) image->columns; x++)↵|>||||||| {↵|>||||||| *q++=(unsigned char) ((ssize_t) GetPixelIndex(image,p));↵|>||||||| p+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| for ( ; x < (ssize_t) bytes_per_line; x++)↵|>||||||| *q++=0x00;↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,↵|>||||||| image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| break;↵|>||||||| }↵|>||||||| case 16:↵|>||||||| {↵|>||||||| /*↵|>||||||| Convert DirectClass packet to BMP BGR888.↵|>||||||| */↵|>||||||| for (y=0; y < (ssize_t) image->rows; y++)↵|>||||||| {↵|>||||||| p=GetVirtualPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (p == (const Quantum *) NULL)↵|>||||||| break;↵|>||||||| q=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| for (x=0; x < (ssize_t) image->columns; x++)↵|>||||||| {↵|>||||||| unsigned short↵|>||||||| pixel;↵|>|||||||↵|>||||||| pixel=0;↵|>||||||| if (bmp_subtype == ARGB4444)↵|>||||||| {↵|>||||||| pixel=(unsigned short) (ScaleQuantumToAny(↵|>||||||| GetPixelAlpha(image,p),15) << 12);↵|>||||||| pixel|=(unsigned short) (ScaleQuantumToAny(↵|>||||||| GetPixelRed(image,p),15) << 8);↵|>||||||| pixel|=(unsigned short) (ScaleQuantumToAny(↵|>||||||| GetPixelGreen(image,p),15) << 4);↵|>||||||| pixel|=(unsigned short) (ScaleQuantumToAny(↵|>||||||| GetPixelBlue(image,p),15));↵|>||||||| }↵|>||||||| else if (bmp_subtype == RGB565)↵|>||||||| {↵|>||||||| pixel=(unsigned short) (ScaleQuantumToAny(↵|>||||||| GetPixelRed(image,p),31) << 11);↵|>||||||| pixel|=(unsigned short) (ScaleQuantumToAny(↵|>||||||| GetPixelGreen(image,p),63) << 5);↵|>||||||| pixel|=(unsigned short) (ScaleQuantumToAny(↵|>||||||| GetPixelBlue(image,p),31));↵|>||||||| }↵|>||||||| else↵|>||||||| {↵|>||||||| if (bmp_subtype == ARGB1555)↵|>||||||| pixel=(unsigned short) (ScaleQuantumToAny(↵|>||||||| GetPixelAlpha(image,p),1) << 15);↵|>||||||| pixel|=(unsigned short) (ScaleQuantumToAny(↵|>||||||| GetPixelRed(image,p),31) << 10);↵|>||||||| pixel|=(unsigned short) (ScaleQuantumToAny(↵|>||||||| GetPixelGreen(image,p),31) << 5);↵|>||||||| pixel|=(unsigned short) (ScaleQuantumToAny(↵|>||||||| GetPixelBlue(image,p),31));↵|>||||||| }↵|>||||||| *((unsigned short *) q)=pixel;↵|>||||||| q+=2;↵|>||||||| p+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| for (x=2L*(ssize_t) image->columns; x < (ssize_t) bytes_per_line; x++)↵|>||||||| *q++=0x00;↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,↵|>||||||| image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| break;↵|>||||||| }↵|>||||||| case 24:↵|>||||||| {↵|>||||||| /*↵|>||||||| Convert DirectClass packet to BMP BGR888.↵|>||||||| */↵|>||||||| for (y=0; y < (ssize_t) image->rows; y++)↵|>||||||| {↵|>||||||| p=GetVirtualPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (p == (const Quantum *) NULL)↵|>||||||| break;↵|>||||||| q=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| for (x=0; x < (ssize_t) image->columns; x++)↵|>||||||| {↵|>||||||| *q++=ScaleQuantumToChar(GetPixelBlue(image,p));↵|>||||||| *q++=ScaleQuantumToChar(GetPixelGreen(image,p));↵|>||||||| *q++=ScaleQuantumToChar(GetPixelRed(image,p));↵|>||||||| p+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| for (x=3L*(ssize_t) image->columns; x < (ssize_t) bytes_per_line; x++)↵|>||||||| *q++=0x00;↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,↵|>||||||| image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| break;↵|>||||||| }↵|>||||||| case 32:↵|>||||||| {↵|>||||||| /*↵|>||||||| Convert DirectClass packet to ARGB8888 pixel.↵|>||||||| */↵|>||||||| for (y=0; y < (ssize_t) image->rows; y++)↵|>||||||| {↵|>||||||| p=GetVirtualPixels(image,0,y,image->columns,1,exception);↵|>||||||| if (p == (const Quantum *) NULL)↵|>||||||| break;↵|>||||||| q=pixels+(image->rows-y-1)*bytes_per_line;↵|>||||||| for (x=0; x < (ssize_t) image->columns; x++)↵|>||||||| {↵|>||||||| *q++=ScaleQuantumToChar(GetPixelBlue(image,p));↵|>||||||| *q++=ScaleQuantumToChar(GetPixelGreen(image,p));↵|>||||||| *q++=ScaleQuantumToChar(GetPixelRed(image,p));↵|>||||||| *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));↵|>||||||| p+=GetPixelChannels(image);↵|>||||||| }↵|>||||||| if (image->previous == (Image *) NULL)↵|>||||||| {↵|>||||||| status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,↵|>||||||| image->rows);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| if ((type > 2) && (bmp_info.bits_per_pixel == 8))↵|>||||||| if (image_info->compression != NoCompression)↵|>||||||| {↵|>||||||| MemoryInfo↵|>||||||| *rle_info;↵|>|||||||↵|>||||||| /*↵|>||||||| Convert run-length encoded raster pixels.↵|>||||||| */↵|>||||||| rle_info=AcquireVirtualMemory((size_t) (2*(bytes_per_line+2)+2),↵|>||||||| (image->rows+2)*sizeof(*pixels));↵|>||||||| if (rle_info == (MemoryInfo *) NULL)↵|>||||||| {↵|>||||||| pixel_info=RelinquishVirtualMemory(pixel_info);↵|>||||||| ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");↵|>||||||| }↵|>||||||| bmp_data=(unsigned char *) GetVirtualMemoryBlob(rle_info);↵|>||||||| bmp_info.file_size-=bmp_info.image_size;↵|>||||||| bmp_info.image_size=(unsigned int) EncodeImage(image,bytes_per_line,↵|>||||||| pixels,bmp_data);↵|>||||||| bmp_info.file_size+=bmp_info.image_size;↵|>||||||| pixel_info=RelinquishVirtualMemory(pixel_info);↵|>||||||| pixel_info=rle_info;↵|>||||||| pixels=bmp_data;↵|>||||||| bmp_info.compression=BI_RLE8;↵|>||||||| }↵|>||||||| /*↵|>||||||| Write BMP for Windows, all versions, 14-byte header.↵|>||||||| */↵|>||||||| if (image->debug != MagickFalse)↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Writing BMP version %.20g datastream",(double) type);↵|>||||||| if (image->storage_class == DirectClass)↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Storage class=DirectClass");↵|>||||||| else↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Storage class=PseudoClass");↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Image depth=%.20g",(double) image->depth);↵|>||||||| if (image->alpha_trait != UndefinedPixelTrait)↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Matte=True");↵|>||||||| else↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Matte=MagickFalse");↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " BMP bits_per_pixel=%.20g",(double) bmp_info.bits_per_pixel);↵|>||||||| switch ((int) bmp_info.compression)↵|>||||||| {↵|>||||||| case BI_RGB:↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Compression=BI_RGB");↵|>||||||| break;↵|>||||||| }↵|>||||||| case BI_RLE8:↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Compression=BI_RLE8");↵|>||||||| break;↵|>||||||| }↵|>||||||| case BI_BITFIELDS:↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Compression=BI_BITFIELDS");↵|>||||||| break;↵|>||||||| }↵|>||||||| default:↵|>||||||| {↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Compression=UNKNOWN (%u)",bmp_info.compression);↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| if (bmp_info.number_colors == 0)↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Number_colors=unspecified");↵|>||||||| else↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Number_colors=%u",bmp_info.number_colors);↵|>||||||| }↵|>||||||| profile_data=0;↵|>||||||| profile_size=0;↵|>||||||| profile_size_pad=0;↵|>||||||| if (profile != (StringInfo *) NULL)↵|>||||||| {↵|>||||||| profile_data=(MagickOffsetType) bmp_info.file_size-14; /* from head of BMP info header */↵|>||||||| profile_size=(MagickOffsetType) GetStringInfoLength(profile);↵|>||||||| if ((profile_size % 4) > 0)↵|>||||||| profile_size_pad=4-(profile_size%4);↵|>||||||| bmp_info.file_size+=profile_size+profile_size_pad;↵|>||||||| }↵|>||||||| (void) WriteBlob(image,2,(unsigned char *) "BM");↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.file_size);↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.ba_offset); /* always 0 */↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.offset_bits);↵|>||||||| if (type == 2)↵|>||||||| {↵|>||||||| /*↵|>||||||| Write 12-byte version 2 bitmap header.↵|>||||||| */↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.size);↵|>||||||| (void) WriteBlobLSBSignedShort(image,(signed short) bmp_info.width);↵|>||||||| (void) WriteBlobLSBSignedShort(image,(signed short) bmp_info.height);↵|>||||||| (void) WriteBlobLSBShort(image,bmp_info.planes);↵|>||||||| (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);↵|>||||||| }↵|>||||||| else↵|>||||||| {↵|>||||||| /*↵|>||||||| Write 40-byte version 3+ bitmap header.↵|>||||||| */↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.size);↵|>||||||| (void) WriteBlobLSBSignedLong(image,(signed int) bmp_info.width);↵|>||||||| (void) WriteBlobLSBSignedLong(image,(signed int) bmp_info.height);↵|>||||||| (void) WriteBlobLSBShort(image,bmp_info.planes);↵|>||||||| (void) WriteBlobLSBShort(image,bmp_info.bits_per_pixel);↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.compression);↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.image_size);↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.x_pixels);↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.y_pixels);↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.number_colors);↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.colors_important);↵|>||||||| }↵|>||||||| if ((type > 3) && ((image->alpha_trait != UndefinedPixelTrait) ||↵|>||||||| (have_color_info != MagickFalse)))↵|>||||||| {↵|>||||||| /*↵|>||||||| Write the rest of the 108-byte BMP Version 4 header.↵|>||||||| */↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.red_mask);↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.green_mask);↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.blue_mask);↵|>||||||| (void) WriteBlobLSBLong(image,bmp_info.alpha_mask);↵|>||||||| if (profile != (StringInfo *) NULL)↵|>||||||| (void) WriteBlobLSBLong(image,0x4D424544U); /* PROFILE_EMBEDDED */↵|>||||||| else↵|>||||||| (void) WriteBlobLSBLong(image,0x73524742U); /* sRGB */↵|>||||||| ↵|>||||||| // bounds check, assign .0 if invalid value↵|>||||||| if (isgreater(image->chromaticity.red_primary.x, 1.0) ||↵|>||||||| !isgreater(image->chromaticity.red_primary.x, 0.0))↵|>||||||| image->chromaticity.red_primary.x = 0.0;↵|>||||||| if (isgreater(image->chromaticity.red_primary.y, 1.0) ||↵|>||||||| !isgreater(image->chromaticity.red_primary.y, 0.0))↵|>||||||| image->chromaticity.red_primary.y = 0.0;↵|>||||||| if (isgreater(image->chromaticity.green_primary.x, 1.0) ||↵|>||||||| !isgreater(image->chromaticity.green_primary.x, 0.0))↵|>||||||| image->chromaticity.green_primary.x = 0.0;↵|>||||||| if (isgreater(image->chromaticity.green_primary.y, 1.0) ||↵|>||||||| !isgreater(image->chromaticity.green_primary.y, 0.0))↵|>||||||| image->chromaticity.green_primary.y = 0.0;↵|>||||||| if (isgreater(image->chromaticity.blue_primary.x, 1.0) ||↵|>||||||| !isgreater(image->chromaticity.blue_primary.x, 0.0))↵|>||||||| image->chromaticity.blue_primary.x = 0.0;↵|>||||||| if (isgreater(image->chromaticity.blue_primary.y, 1.0) ||↵|>||||||| !isgreater(image->chromaticity.blue_primary.y, 0.0))↵|>||||||| image->chromaticity.blue_primary.y = 0.0;↵|>||||||| if (isgreater(bmp_info.gamma_scale.x, 1.0) ||↵|>||||||| !isgreater(bmp_info.gamma_scale.x, 0.0))↵|>||||||| bmp_info.gamma_scale.x = 0.0;↵|>||||||| if (isgreater(bmp_info.gamma_scale.y, 1.0) ||↵|>||||||| !isgreater(bmp_info.gamma_scale.y, 0.0))↵|>||||||| bmp_info.gamma_scale.y = 0.0;↵|>||||||| if (isgreater(bmp_info.gamma_scale.z, 1.0) ||↵|>||||||| !isgreater(bmp_info.gamma_scale.z, 0.0))↵|>||||||| bmp_info.gamma_scale.z = 0.0;↵|>|||||||↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| (image->chromaticity.red_primary.x*0x40000000));↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| (image->chromaticity.red_primary.y*0x40000000));↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| ((1.000f-(image->chromaticity.red_primary.x+↵|>||||||| image->chromaticity.red_primary.y))*0x40000000));↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| (image->chromaticity.green_primary.x*0x40000000));↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| (image->chromaticity.green_primary.y*0x40000000));↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| ((1.000f-(image->chromaticity.green_primary.x+↵|>||||||| image->chromaticity.green_primary.y))*0x40000000));↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| (image->chromaticity.blue_primary.x*0x40000000));↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| (image->chromaticity.blue_primary.y*0x40000000));↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| ((1.000f-(image->chromaticity.blue_primary.x+↵|>||||||| image->chromaticity.blue_primary.y))*0x40000000));↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| (bmp_info.gamma_scale.x*0x10000));↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| (bmp_info.gamma_scale.y*0x10000));↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| (bmp_info.gamma_scale.z*0x10000));↵|>||||||| if ((image->rendering_intent != UndefinedIntent) ||↵|>||||||| (profile != (StringInfo *) NULL))↵|>||||||| {↵|>||||||| ssize_t↵|>||||||| intent;↵|>|||||||↵|>||||||| switch ((int) image->rendering_intent)↵|>||||||| {↵|>||||||| case SaturationIntent:↵|>||||||| {↵|>||||||| intent=LCS_GM_BUSINESS;↵|>||||||| break;↵|>||||||| }↵|>||||||| case RelativeIntent:↵|>||||||| {↵|>||||||| intent=LCS_GM_GRAPHICS;↵|>||||||| break;↵|>||||||| }↵|>||||||| case PerceptualIntent:↵|>||||||| {↵|>||||||| intent=LCS_GM_IMAGES;↵|>||||||| break;↵|>||||||| }↵|>||||||| case AbsoluteIntent:↵|>||||||| {↵|>||||||| intent=LCS_GM_ABS_COLORIMETRIC;↵|>||||||| break;↵|>||||||| }↵|>||||||| default:↵|>||||||| {↵|>||||||| intent=0;↵|>||||||| break;↵|>||||||| }↵|>||||||| }↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int) intent);↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int) profile_data);↵|>||||||| (void) WriteBlobLSBLong(image,(unsigned int)↵|>||||||| (profile_size+profile_size_pad));↵|>||||||| (void) WriteBlobLSBLong(image,0x00); /* reserved */↵|>||||||| }↵|>||||||| }↵|>||||||| if (image->storage_class == PseudoClass)↵|>||||||| {↵|>||||||| unsigned char↵|>||||||| *bmp_colormap;↵|>|||||||↵|>||||||| /*↵|>||||||| Dump colormap to file.↵|>||||||| */↵|>||||||| if (image->debug != MagickFalse)↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Colormap: %.20g entries",(double) image->colors);↵|>||||||| bmp_colormap=(unsigned char *) AcquireQuantumMemory((size_t) (1UL <<↵|>||||||| bmp_info.bits_per_pixel),4*sizeof(*bmp_colormap));↵|>||||||| if (bmp_colormap == (unsigned char *) NULL)↵|>||||||| {↵|>||||||| pixel_info=RelinquishVirtualMemory(pixel_info);↵|>||||||| ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");↵|>||||||| }↵|>||||||| q=bmp_colormap;↵|>||||||| for (i=0; i < (ssize_t) MagickMin((ssize_t) image->colors,(ssize_t) bmp_info.number_colors); i++)↵|>||||||| {↵|>||||||| *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].blue));↵|>||||||| *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].green));↵|>||||||| *q++=ScaleQuantumToChar(ClampToQuantum(image->colormap[i].red));↵|>||||||| if (type > 2)↵|>||||||| *q++=(unsigned char) 0x0;↵|>||||||| }↵|>||||||| for ( ; i < (ssize_t) (1UL << bmp_info.bits_per_pixel); i++)↵|>||||||| {↵|>||||||| *q++=(unsigned char) 0x00;↵|>||||||| *q++=(unsigned char) 0x00;↵|>||||||| *q++=(unsigned char) 0x00;↵|>||||||| if (type > 2)↵|>||||||| *q++=(unsigned char) 0x00;↵|>||||||| }↵|>||||||| if (type <= 2)↵|>||||||| (void) WriteBlob(image,(size_t) (3*(1L << bmp_info.bits_per_pixel)),↵|>||||||| bmp_colormap);↵|>||||||| else↵|>||||||| (void) WriteBlob(image,(size_t) (4*(1L << bmp_info.bits_per_pixel)),↵|>||||||| bmp_colormap);↵|>||||||| bmp_colormap=(unsigned char *) RelinquishMagickMemory(bmp_colormap);↵|>||||||| }↵|>||||||| if (image->debug != MagickFalse)↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Pixels: %u bytes",bmp_info.image_size);↵|>||||||| (void) WriteBlob(image,(size_t) bmp_info.image_size,pixels);↵|>||||||| if (profile != (StringInfo *) NULL)↵|>||||||| {↵|>||||||| if (image->debug != MagickFalse)↵|>||||||| (void) LogMagickEvent(CoderEvent,GetMagickModule(),↵|>||||||| " Profile: %g bytes",(double) profile_size+profile_size_pad);↵|>||||||| (void) WriteBlob(image,(size_t) profile_size,GetStringInfoDatum(profile));↵|>||||||| if (profile_size_pad > 0) /* padding for 4 bytes multiple */↵|>||||||| (void) WriteBlob(image,(size_t) profile_size_pad,"\0\0\0");↵|>||||||| }↵|>||||||| pixel_info=RelinquishVirtualMemory(pixel_info);↵|>||||||| if (GetNextImageInList(image) == (Image *) NULL)↵|>||||||| break;↵|>||||||| image=SyncNextImageInList(image);↵|>||||||| status=SetImageProgress(image,SaveImagesTag,scene++,imageListLength);↵|>||||||| if (status == MagickFalse)↵|>||||||| break;↵|>||||||| } while (image_info->adjoin != MagickFalse);↵|>||||||| (void) CloseBlob(image);↵|>||||||| return(MagickTrue);↵|>|||||||}↵|>||||||||>||||