00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
#include "magick/studio.h"
00044
#include "magick/blob.h"
00045
#include "magick/blob_private.h"
00046
#include "magick/color_private.h"
00047
#include "magick/colorspace.h"
00048
#include "magick/error.h"
00049
#include "magick/error_private.h"
00050
#include "magick/image.h"
00051
#include "magick/image_private.h"
00052
#include "magick/list.h"
00053
#include "magick/log.h"
00054
#include "magick/magick.h"
00055
#include "magick/memory_.h"
00056
#include "magick/monitor.h"
00057
#include "magick/profile.h"
00058
#include "magick/static.h"
00059
#include "magick/string_.h"
00060
#include "magick/transform.h"
00061
00062
00063
00064
00065
#undef BI_JPEG
00066 #define BI_JPEG 4
00067
#undef BI_PNG
00068 #define BI_PNG 5
00069
#if !defined(__WINDOWS__) || defined(__MINGW32__)
00070 #define BI_RGB 0
00071 #define BI_RLE8 1
00072 #define BI_RLE4 2
00073 #define BI_BITFIELDS 3
00074
00075 #define LCS_CALIBRATED_RBG 0
00076 #define LCS_sRGB 1
00077 #define LCS_WINDOWS_COLOR_SPACE 2
00078 #define PROFILE_LINKED 3
00079 #define PROFILE_EMBEDDED 4
00080
00081 #define LCS_GM_BUSINESS 1
00082 #define LCS_GM_GRAPHICS 2
00083 #define LCS_GM_IMAGES 4
00084 #define LCS_GM_ABS_COLORIMETRIC 8
00085
#endif
00086
00087
00088
00089
00090
typedef struct _BMPInfo
00091 {
00092
unsigned long
00093 file_size,
00094
ba_offset,
00095
offset_bits,
00096
size;
00097
00098
long
00099 width,
00100
height;
00101
00102
unsigned short
00103 planes,
00104
bits_per_pixel;
00105
00106
unsigned long
00107 compression,
00108
image_size,
00109
x_pixels,
00110
y_pixels,
00111
number_colors,
00112
red_mask,
00113
green_mask,
00114
blue_mask,
00115
alpha_mask,
00116
colors_important;
00117
00118
long
00119 colorspace;
00120
00121
PrimaryInfo
00122 red_primary,
00123
green_primary,
00124
blue_primary,
00125
gamma_scale;
00126 }
BMPInfo;
00127
00128
00129
00130
00131
static MagickBooleanType
00132
WriteBMPImage(
const ImageInfo *,
Image *);
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167 static MagickBooleanType DecodeImage(
Image *image,
00168
const MagickBooleanType compression,
unsigned char *pixels)
00169 {
00170
int
00171 count;
00172
00173
long
00174 y;
00175
00176
MagickBooleanType
00177 status;
00178
00179
register long
00180 i,
00181 x;
00182
00183
register unsigned char
00184 *p,
00185 *q;
00186
00187
unsigned char
00188 byte;
00189
00190
assert(image != (
Image *) NULL);
00191
assert(image->
signature ==
MagickSignature);
00192
if (image->
debug !=
MagickFalse)
00193 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
00194
assert(pixels != (
unsigned char *) NULL);
00195 (
void)
ResetMagickMemory(pixels,0,(size_t) image->
columns*image->
rows*
00196
sizeof(*pixels));
00197 byte=0;
00198 x=0;
00199 p=pixels;
00200 q=pixels+(size_t) image->
columns*image->
rows;
00201
for (y=0; y < (
long) image->
rows; )
00202 {
00203
if ((p < pixels) || (p >= q))
00204
break;
00205 count=
ReadBlobByte(image);
00206
if (count == EOF)
00207
break;
00208
if (count != 0)
00209 {
00210
00211
00212
00213 count=
Min(count,(
int) (q-p));
00214 byte=(
unsigned char)
ReadBlobByte(image);
00215
if (compression ==
BI_RLE8)
00216 {
00217
for (i=0; i < count; i++)
00218 *p++=(
unsigned char) byte;
00219 }
00220
else
00221 {
00222
for (i=0; i < count; i++)
00223 *p++=(
unsigned char)
00224 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
00225 }
00226 x+=count;
00227 }
00228
else
00229 {
00230
00231
00232
00233 count=
ReadBlobByte(image);
00234
if (count == 0x01)
00235
return(
MagickTrue);
00236
switch (count)
00237 {
00238
case 0x00:
00239 {
00240
00241
00242
00243 x=0;
00244 y++;
00245 p=pixels+y*image->
columns;
00246
break;
00247 }
00248
case 0x02:
00249 {
00250
00251
00252
00253 x+=
ReadBlobByte(image);
00254 y+=
ReadBlobByte(image);
00255 p=pixels+y*image->
columns+x;
00256
break;
00257 }
00258
default:
00259 {
00260
00261
00262
00263 count=
Min(count,(
int) (q-p));
00264
if (compression ==
BI_RLE8)
00265
for (i=0; i < count; i++)
00266 *p++=(
unsigned char)
ReadBlobByte(image);
00267
else
00268
for (i=0; i < count; i++)
00269 {
00270
if ((i & 0x01) == 0)
00271 byte=(
unsigned char)
ReadBlobByte(image);
00272 *p++=(
unsigned char)
00273 ((i & 0x01) != 0 ? (byte & 0x0f) : ((byte >> 4) & 0x0f));
00274 }
00275 x+=count;
00276
00277
00278
00279
if (compression ==
BI_RLE8)
00280 {
00281
if ((count & 0x01) != 0)
00282 (
void)
ReadBlobByte(image);
00283 }
00284
else
00285
if (((count & 0x03) == 1) || ((count & 0x03) == 2))
00286 (
void)
ReadBlobByte(image);
00287
break;
00288 }
00289 }
00290 }
00291
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
00292 (
QuantumTick(y,image->
rows) !=
MagickFalse))
00293 {
00294 status=image->
progress_monitor(
LoadImageTag,y,image->
rows,
00295 image->
client_data);
00296
if (status ==
MagickFalse)
00297
break;
00298 }
00299 }
00300 (
void)
ReadBlobByte(image);
00301 (
void)
ReadBlobByte(image);
00302
return(
MagickTrue);
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 static size_t
EncodeImage(
Image *image,
const unsigned long bytes_per_line,
00339
const unsigned char *pixels,
unsigned char *compressed_pixels)
00340 {
00341
long
00342 y;
00343
00344
MagickBooleanType
00345 status;
00346
00347
register const unsigned char
00348 *p;
00349
00350
register long
00351 i,
00352 x;
00353
00354
register unsigned char
00355 *q;
00356
00357
00358
00359
00360
assert(image != (
Image *) NULL);
00361
assert(image->
signature ==
MagickSignature);
00362
if (image->
debug !=
MagickFalse)
00363 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
00364
assert(pixels != (
const unsigned char *) NULL);
00365
assert(compressed_pixels != (
unsigned char *) NULL);
00366 p=pixels;
00367 q=compressed_pixels;
00368 i=0;
00369
for (y=0; y < (
long) image->
rows; y++)
00370 {
00371
for (x=0; x < (
long) bytes_per_line; x+=i)
00372 {
00373
00374
00375
00376
for (i=1; ((x+i) < (
long) bytes_per_line); i++)
00377
if ((i == 255) || (*(p+i) != *p))
00378
break;
00379 *q++=(
unsigned char) i;
00380 *q++=(*p);
00381 p+=i;
00382 }
00383
00384
00385
00386 *q++=(
unsigned char) 0x00;
00387 *q++=(
unsigned char) 0x00;
00388
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
00389 (
QuantumTick(y,image->
rows) !=
MagickFalse))
00390 {
00391 status=image->
progress_monitor(
SaveImageTag,y,image->
rows,
00392 image->
client_data);
00393
if (status ==
MagickFalse)
00394
break;
00395 }
00396 }
00397
00398
00399
00400 *q++=(
unsigned char) 0x00;
00401 *q++=(
unsigned char) 0x01;
00402
return((size_t) (q-compressed_pixels));
00403 }
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 static MagickBooleanType IsBMP(
const unsigned char *magick,
const size_t length)
00433 {
00434
if (length < 2)
00435
return(
MagickFalse);
00436
if ((
LocaleNCompare((
char *) magick,
"BA",2) == 0) ||
00437 (
LocaleNCompare((
char *) magick,
"BM",2) == 0) ||
00438 (
LocaleNCompare((
char *) magick,
"IC",2) == 0) ||
00439 (
LocaleNCompare((
char *) magick,
"PI",2) == 0) ||
00440 (
LocaleNCompare((
char *) magick,
"CI",2) == 0) ||
00441 (
LocaleNCompare((
char *) magick,
"CP",2) == 0))
00442
return(
MagickTrue);
00443
return(
MagickFalse);
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 static Image *
ReadBMPImage(
const ImageInfo *image_info,
ExceptionInfo *
exception)
00475 {
00476
BMPInfo
00477 bmp_info;
00478
00479
Image
00480 *image;
00481
00482
IndexPacket
00483 index;
00484
00485
long
00486 y;
00487
00488
MagickBooleanType
00489 status;
00490
00491
MagickOffsetType
00492 start_position;
00493
00494
register IndexPacket
00495 *indexes;
00496
00497
register long
00498 x;
00499
00500
register PixelPacket
00501 *q;
00502
00503
register long
00504 i;
00505
00506
register unsigned char
00507 *p;
00508
00509
ssize_t
00510 count;
00511
00512 size_t
00513 length;
00514
00515
unsigned char
00516 magick[12],
00517 *pixels;
00518
00519
unsigned long
00520 bit,
00521 blue,
00522 bytes_per_line,
00523 green,
00524 opacity,
00525 red;
00526
00527
00528
00529
00530
assert(image_info != (
const ImageInfo *) NULL);
00531
assert(image_info->
signature ==
MagickSignature);
00532
if (image_info->
debug !=
MagickFalse)
00533 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image_info->
filename);
00534
assert(exception != (
ExceptionInfo *) NULL);
00535
assert(exception->
signature ==
MagickSignature);
00536 image=
AllocateImage(image_info);
00537 status=
OpenBlob(image_info,image,
ReadBinaryBlobMode,exception);
00538
if (status ==
MagickFalse)
00539 {
00540
DestroyImageList(image);
00541
return((
Image *) NULL);
00542 }
00543
00544
00545
00546 (
void)
ResetMagickMemory(&bmp_info,0,
sizeof(bmp_info));
00547 bmp_info.ba_offset=0;
00548 start_position=0;
00549 count=
ReadBlob(image,2,magick);
00550
do
00551 {
00552
PixelPacket
00553 quantum_bits,
00554 shift;
00555
00556
unsigned long
00557 profile_data,
00558 profile_size;
00559
00560
00561
00562
00563
if (bmp_info.ba_offset == 0)
00564 start_position=
TellBlob(image)-2;
00565 bmp_info.ba_offset=0;
00566
while (
LocaleNCompare((
char *) magick,
"BA",2) == 0)
00567 {
00568 bmp_info.file_size=
ReadBlobLSBLong(image);
00569 bmp_info.ba_offset=
ReadBlobLSBLong(image);
00570 bmp_info.offset_bits=
ReadBlobLSBLong(image);
00571 count=
ReadBlob(image,2,magick);
00572
if (count == 0)
00573
break;
00574 }
00575
if (image->
debug !=
MagickFalse)
00576 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
" Magick: %c%c",
00577 magick[0],magick[1]);
00578
if ((count == 0) || ((
LocaleNCompare((
char *) magick,
"BM",2) != 0) &&
00579 (
LocaleNCompare((
char *) magick,
"CI",2) != 0)))
00580
ThrowReaderException(
CorruptImageError,
"ImproperImageHeader");
00581 bmp_info.file_size=
ReadBlobLSBLong(image);
00582 (
void)
ReadBlobLSBLong(image);
00583 bmp_info.offset_bits=
ReadBlobLSBLong(image);
00584 bmp_info.size=
ReadBlobLSBLong(image);
00585
if (image->
debug !=
MagickFalse)
00586 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
" BMP size: %lu",
00587 bmp_info.size);
00588
if (bmp_info.size == 12)
00589 {
00590
00591
00592
00593 bmp_info.width=(
short)
ReadBlobLSBShort(image);
00594 bmp_info.height=(
short)
ReadBlobLSBShort(image);
00595 bmp_info.planes=
ReadBlobLSBShort(image);
00596 bmp_info.bits_per_pixel=
ReadBlobLSBShort(image);
00597 bmp_info.x_pixels=0;
00598 bmp_info.y_pixels=0;
00599 bmp_info.number_colors=0;
00600 bmp_info.compression=
BI_RGB;
00601 bmp_info.image_size=0;
00602 bmp_info.alpha_mask=0;
00603
if (image->
debug !=
MagickFalse)
00604 {
00605 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00606
" Format: OS/2 Bitmap");
00607 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00608
" Geometry: %ldx%ld",bmp_info.width,bmp_info.height);
00609 }
00610 }
00611
else
00612 {
00613
00614
00615
00616
if (bmp_info.size < 40)
00617
ThrowReaderException(
CorruptImageError,
"NonOS2HeaderSizeError");
00618 bmp_info.width=(
short)
ReadBlobLSBLong(image);
00619 bmp_info.height=(
short)
ReadBlobLSBLong(image);
00620 bmp_info.planes=
ReadBlobLSBShort(image);
00621 bmp_info.bits_per_pixel=
ReadBlobLSBShort(image);
00622 bmp_info.compression=
ReadBlobLSBLong(image);
00623 bmp_info.image_size=
ReadBlobLSBLong(image);
00624 bmp_info.x_pixels=
ReadBlobLSBLong(image);
00625 bmp_info.y_pixels=
ReadBlobLSBLong(image);
00626 bmp_info.number_colors=
ReadBlobLSBLong(image);
00627 bmp_info.colors_important=
ReadBlobLSBLong(image);
00628 profile_data=0;
00629 profile_size=0;
00630
if (image->
debug !=
MagickFalse)
00631 {
00632 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00633
" Format: MS Windows bitmap");
00634 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00635
" Geometry: %ldx%ld",bmp_info.width,bmp_info.height);
00636 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00637
" Bits per pixel: %d",bmp_info.bits_per_pixel);
00638
switch ((
int) bmp_info.compression)
00639 {
00640
case BI_RGB:
00641 {
00642 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00643
" Compression: BI_RGB");
00644
break;
00645 }
00646
case BI_RLE4:
00647 {
00648 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00649
" Compression: BI_RLE4");
00650
break;
00651 }
00652
case BI_RLE8:
00653 {
00654 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00655
" Compression: BI_RLE8");
00656
break;
00657 }
00658
case BI_BITFIELDS:
00659 {
00660 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00661
" Compression: BI_BITFIELDS");
00662
break;
00663 }
00664
case BI_PNG:
00665 {
00666 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00667
" Compression: BI_PNG");
00668
break;
00669 }
00670
case BI_JPEG:
00671 {
00672 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00673
" Compression: BI_JPEG");
00674
break;
00675 }
00676
default:
00677 {
00678 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00679
" Compression: UNKNOWN (%lu)",bmp_info.compression);
00680 }
00681 }
00682 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00683
" Number of colors: %lu",bmp_info.number_colors);
00684 }
00685 bmp_info.red_mask=
ReadBlobLSBLong(image);
00686 bmp_info.green_mask=
ReadBlobLSBLong(image);
00687 bmp_info.blue_mask=
ReadBlobLSBLong(image);
00688
if (bmp_info.size > 40)
00689 {
00690
double
00691 sum;
00692
00693
00694
00695
00696 bmp_info.alpha_mask=
ReadBlobLSBLong(image);
00697 bmp_info.colorspace=(
long)
ReadBlobLSBLong(image);
00698
00699
00700
00701 bmp_info.red_primary.x=(
double)
00702
ReadBlobLSBLong(image)/0x3ffffff;
00703 bmp_info.red_primary.y=(
double)
00704
ReadBlobLSBLong(image)/0x3ffffff;
00705 bmp_info.red_primary.z=(
double)
00706
ReadBlobLSBLong(image)/0x3ffffff;
00707 bmp_info.green_primary.x=(
double)
00708
ReadBlobLSBLong(image)/0x3ffffff;
00709 bmp_info.green_primary.y=(
double)
00710
ReadBlobLSBLong(image)/0x3ffffff;
00711 bmp_info.green_primary.z=(
double)
00712
ReadBlobLSBLong(image)/0x3ffffff;
00713 bmp_info.blue_primary.x=(
double)
00714
ReadBlobLSBLong(image)/0x3ffffff;
00715 bmp_info.blue_primary.y=(
double)
00716
ReadBlobLSBLong(image)/0x3ffffff;
00717 bmp_info.blue_primary.z=(
double)
00718
ReadBlobLSBLong(image)/0x3ffffff;
00719 sum=bmp_info.red_primary.x+bmp_info.red_primary.x+
00720 bmp_info.red_primary.z;
00721 image->
chromaticity.
red_primary.
x/=sum;
00722 image->
chromaticity.
red_primary.
y/=sum;
00723 sum=bmp_info.green_primary.x+bmp_info.green_primary.x+
00724 bmp_info.green_primary.z;
00725 image->
chromaticity.
green_primary.
x/=sum;
00726 image->
chromaticity.
green_primary.
y/=sum;
00727 sum=bmp_info.blue_primary.x+bmp_info.blue_primary.x+
00728 bmp_info.blue_primary.z;
00729 image->
chromaticity.
blue_primary.
x/=sum;
00730 image->
chromaticity.
blue_primary.
y/=sum;
00731
00732
00733
00734 bmp_info.gamma_scale.x=(
double)
ReadBlobLSBLong(image)/0xffff;
00735 bmp_info.gamma_scale.y=(
double)
ReadBlobLSBLong(image)/0xffff;
00736 bmp_info.gamma_scale.z=(
double)
ReadBlobLSBLong(image)/0xffff;
00737
00738
00739
00740 image->
gamma=(bmp_info.gamma_scale.x+bmp_info.gamma_scale.y+
00741 bmp_info.gamma_scale.z)/3.0;
00742 }
00743
if (bmp_info.size > 108)
00744 {
00745
unsigned long
00746 intent;
00747
00748
00749
00750
00751 intent=
ReadBlobLSBLong(image);
00752
switch ((
int) intent)
00753 {
00754
case LCS_GM_BUSINESS:
00755 {
00756 image->
rendering_intent=
SaturationIntent;
00757
break;
00758 }
00759
case LCS_GM_GRAPHICS:
00760 {
00761 image->
rendering_intent=
RelativeIntent;
00762
break;
00763 }
00764
case LCS_GM_IMAGES:
00765 {
00766 image->
rendering_intent=
PerceptualIntent;
00767
break;
00768 }
00769
case LCS_GM_ABS_COLORIMETRIC:
00770 {
00771 image->
rendering_intent=
AbsoluteIntent;
00772
break;
00773 }
00774 }
00775 profile_data=
ReadBlobLSBLong(image);
00776 profile_size=
ReadBlobLSBLong(image);
00777 (
void)
ReadBlobLSBLong(image);
00778 }
00779 }
00780
if ((bmp_info.compression !=
BI_RGB) &&
00781 ((
MagickSizeType) bmp_info.file_size !=
GetBlobSize(image)))
00782 (
void)
ThrowMagickException(exception,
GetMagickModule(),
CorruptImageError,
00783
"LengthAndFilesizeDoNotMatch",image->
filename);
00784
if (bmp_info.width <= 0)
00785
ThrowReaderException(
CorruptImageError,
"NegativeOrZeroImageSize");
00786
if (bmp_info.height == 0)
00787
ThrowReaderException(
CorruptImageError,
"NegativeOrZeroImageSize");
00788
if ((bmp_info.height < 0) && (bmp_info.compression !=0))
00789
ThrowReaderException(
CorruptImageError,
"CompressionNotValid");
00790
if (bmp_info.planes != 1)
00791
ThrowReaderException(
CorruptImageError,
"StaticPlanesValueNotEqualToOne");
00792
if ((bmp_info.bits_per_pixel != 1) && (bmp_info.bits_per_pixel != 4) &&
00793 (bmp_info.bits_per_pixel != 8) && (bmp_info.bits_per_pixel != 16) &&
00794 (bmp_info.bits_per_pixel != 24) && (bmp_info.bits_per_pixel != 32))
00795
ThrowReaderException(
CorruptImageError,
"UnrecognizedBitsPerPixel");
00796
if (bmp_info.number_colors > (1UL << bmp_info.bits_per_pixel))
00797
ThrowReaderException(
CorruptImageError,
"UnrecognizedNumberOfColors");
00798
if (bmp_info.compression > 3)
00799
ThrowReaderException(
CorruptImageError,
"UnrecognizedImageCompression");
00800
if ((bmp_info.compression == 1) && (bmp_info.bits_per_pixel != 8))
00801
ThrowReaderException(
CorruptImageError,
"UnrecognizedBitsPerPixel");
00802
if ((bmp_info.compression == 2) && (bmp_info.bits_per_pixel != 4))
00803
ThrowReaderException(
CorruptImageError,
"UnrecognizedBitsPerPixel");
00804
if ((bmp_info.compression == 3) && (bmp_info.bits_per_pixel < 16))
00805
ThrowReaderException(
CorruptImageError,
"UnrecognizedBitsPerPixel");
00806
switch (bmp_info.compression)
00807 {
00808
case BI_RGB:
00809
case BI_RLE8:
00810
case BI_RLE4:
00811
case BI_BITFIELDS:
00812
break;
00813
case BI_JPEG:
00814
ThrowReaderException(
CoderError,
"JPEGCompressionNotSupported");
00815
case BI_PNG:
00816
ThrowReaderException(
CoderError,
"PNGCompressionNotSupported");
00817
default:
00818
ThrowReaderException(
CorruptImageError,
"UnrecognizedImageCompression");
00819 }
00820 image->
columns=(
unsigned long) bmp_info.width;
00821 image->
rows=(
unsigned long)
AbsoluteValue(bmp_info.height);
00822 image->
depth=8;
00823 image->
matte=(
MagickBooleanType) (bmp_info.alpha_mask != 0);
00824
if ((bmp_info.number_colors != 0) || (bmp_info.bits_per_pixel < 16))
00825 {
00826 image->
storage_class=
PseudoClass;
00827 image->
colors=bmp_info.number_colors;
00828
if (image->
colors == 0)
00829 image->
colors=1L << bmp_info.bits_per_pixel;
00830 }
00831
if (image->
storage_class ==
PseudoClass)
00832 {
00833
unsigned char
00834 *bmp_colormap;
00835
00836 size_t
00837 packet_size;
00838
00839
00840
00841
00842
if (image->
debug !=
MagickFalse)
00843 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00844
" Reading colormap of %ld colors",image->
colors);
00845
if (
AllocateImageColormap(image,image->
colors) ==
MagickFalse)
00846
ThrowReaderException(
ResourceLimitError,
"MemoryAllocationFailed");
00847 bmp_colormap=(
unsigned char *)
00848
AcquireMagickMemory((size_t) (4*image->
colors));
00849
if (bmp_colormap == (
unsigned char *) NULL)
00850
ThrowReaderException(
ResourceLimitError,
"MemoryAllocationFailed");
00851
if ((bmp_info.size == 12) || (bmp_info.size == 64))
00852 packet_size=3;
00853
else
00854 packet_size=4;
00855 (
void)
SeekBlob(image,start_position+14+bmp_info.size,SEEK_SET);
00856 (
void)
ReadBlob(image,packet_size*image->
colors,bmp_colormap);
00857 p=bmp_colormap;
00858
for (i=0; i < (
long) image->
colors; i++)
00859 {
00860 image->
colormap[i].
blue=
ScaleCharToQuantum(*p++);
00861 image->
colormap[i].
green=
ScaleCharToQuantum(*p++);
00862 image->
colormap[i].
red=
ScaleCharToQuantum(*p++);
00863
if (packet_size == 4)
00864 p++;
00865 }
00866 bmp_colormap=(
unsigned char *)
RelinquishMagickMemory(bmp_colormap);
00867 }
00868
if ((image_info->
ping !=
MagickFalse) && (image_info->
number_scenes != 0))
00869
if (image->
scene >= (image_info->
scene+image_info->
number_scenes-1))
00870
break;
00871
00872
00873
00874 (
void)
SeekBlob(image,start_position+bmp_info.offset_bits,SEEK_SET);
00875
if (bmp_info.compression ==
BI_RLE4)
00876 bmp_info.bits_per_pixel<<=1;
00877 bytes_per_line=4*((image->
columns*bmp_info.bits_per_pixel+31)/32);
00878 length=(size_t) bytes_per_line*image->
rows;
00879 pixels=(
unsigned char *)
AcquireMagickMemory((size_t)
00880
Max(bytes_per_line,image->
columns+256)*image->
rows*
sizeof(*pixels));
00881
if (pixels == (
unsigned char *) NULL)
00882
ThrowReaderException(
ResourceLimitError,
"MemoryAllocationFailed");
00883
if ((bmp_info.compression ==
BI_RGB) ||
00884 (bmp_info.compression ==
BI_BITFIELDS))
00885 {
00886
if (image->
debug !=
MagickFalse)
00887 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
00888
" Reading pixels (%ld bytes)",(
long) length);
00889 (
void)
ReadBlob(image,length,pixels);
00890 }
00891
else
00892 {
00893
00894
00895
00896 status=
DecodeImage(image,bmp_info.
compression,pixels);
00897
if (status ==
MagickFalse)
00898
ThrowReaderException(
CorruptImageError,
00899
"UnableToRunlengthDecodeImage");
00900 }
00901
00902
00903
00904 image->
x_resolution=(
double) bmp_info.x_pixels/100.0;
00905 image->
y_resolution=(
double) bmp_info.y_pixels/100.0;
00906
00907
00908
00909
if (bmp_info.compression ==
BI_RGB)
00910 {
00911 bmp_info.alpha_mask=0;
00912 bmp_info.red_mask=0x00ff0000UL;
00913 bmp_info.green_mask=0x0000ff00UL;
00914 bmp_info.blue_mask=0x000000ffUL;
00915
if (bmp_info.bits_per_pixel == 16)
00916 {
00917
00918
00919
00920 bmp_info.red_mask=0x00007c00UL;
00921 bmp_info.green_mask=0x000003e0UL;
00922 bmp_info.blue_mask=0x0000001fUL;
00923 }
00924 }
00925
if ((bmp_info.bits_per_pixel == 16) || (bmp_info.bits_per_pixel == 32))
00926 {
00927
register unsigned long
00928 sample;
00929
00930
00931
00932
00933 (
void)
ResetMagickMemory(&shift,0,
sizeof(shift));
00934 (
void)
ResetMagickMemory(&quantum_bits,0,
sizeof(quantum_bits));
00935
if (bmp_info.red_mask != 0)
00936
while (((bmp_info.red_mask << shift.red) & 0x80000000UL) == 0)
00937 shift.red++;
00938
if (bmp_info.green_mask != 0)
00939
while (((bmp_info.green_mask << shift.green) & 0x80000000UL) == 0)
00940 shift.green++;
00941
if (bmp_info.blue_mask != 0)
00942
while (((bmp_info.blue_mask << shift.blue) & 0x80000000UL) == 0)
00943 shift.blue++;
00944
if (bmp_info.alpha_mask != 0)
00945
while (((bmp_info.alpha_mask << shift.opacity) & 0x80000000UL) == 0)
00946 shift.opacity++;
00947 sample=shift.red;
00948
while (((bmp_info.red_mask << sample) & 0x80000000UL) != 0)
00949 sample++;
00950 quantum_bits.red=(
Quantum) (sample-shift.red);
00951 sample=shift.green;
00952
while (((bmp_info.green_mask << sample) & 0x80000000UL) != 0)
00953 sample++;
00954 quantum_bits.green=(
Quantum) (sample-shift.green);
00955 sample=shift.blue;
00956
while (((bmp_info.blue_mask << sample) & 0x80000000UL) != 0)
00957 sample++;
00958 quantum_bits.blue=(
Quantum) (sample-shift.blue);
00959 sample=shift.opacity;
00960
while (((bmp_info.alpha_mask << sample) & 0x80000000UL) != 0)
00961 sample++;
00962 quantum_bits.opacity=(
Quantum) (sample-shift.opacity);
00963 }
00964
switch (bmp_info.bits_per_pixel)
00965 {
00966
case 1:
00967 {
00968
00969
00970
00971
for (y=(
long) image->
rows-1; y >= 0; y--)
00972 {
00973 p=pixels+(image->
rows-y-1)*bytes_per_line;
00974 q=
SetImagePixels(image,0,y,image->
columns,1);
00975
if (q == (
PixelPacket *) NULL)
00976
break;
00977 indexes=
GetIndexes(image);
00978
for (x=0; x < ((
long) image->
columns-7); x+=8)
00979 {
00980
for (bit=0; bit < 8; bit++)
00981 {
00982 index=(
IndexPacket) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
00983 indexes[x+bit]=index;
00984 *q++=image->
colormap[index];
00985 }
00986 p++;
00987 }
00988
if ((image->
columns % 8) != 0)
00989 {
00990
for (bit=0; bit < (image->
columns % 8); bit++)
00991 {
00992 index=(
IndexPacket) (((*p) & (0x80 >> bit)) != 0 ? 0x01 : 0x00);
00993 indexes[x+bit]=index;
00994 *q++=image->
colormap[index];
00995 }
00996 p++;
00997 }
00998
if (
SyncImagePixels(image) ==
MagickFalse)
00999
break;
01000
if (image->
previous == (
Image *) NULL)
01001
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01002 (
QuantumTick(y,image->
rows) !=
MagickFalse))
01003 {
01004 status=image->
progress_monitor(
LoadImageTag,y,image->
rows,
01005 image->
client_data);
01006
if (status ==
MagickFalse)
01007
break;
01008 }
01009 }
01010
break;
01011 }
01012
case 4:
01013 {
01014
01015
01016
01017
for (y=(
long) image->
rows-1; y >= 0; y--)
01018 {
01019 p=pixels+(image->
rows-y-1)*bytes_per_line;
01020 q=
SetImagePixels(image,0,y,image->
columns,1);
01021
if (q == (
PixelPacket *) NULL)
01022
break;
01023 indexes=
GetIndexes(image);
01024
for (x=0; x < ((
long) image->
columns-1); x+=2)
01025 {
01026 index=
ConstrainColormapIndex(image,(*p >> 4) & 0x0f);
01027 indexes[x]=index;
01028 *q++=image->
colormap[index];
01029 index=
ConstrainColormapIndex(image,*p & 0x0f);
01030 indexes[x+1]=index;
01031 *q++=image->
colormap[index];
01032 p++;
01033 }
01034
if ((image->
columns % 2) != 0)
01035 {
01036 index=
ConstrainColormapIndex(image,(*p >> 4) & 0xf);
01037 indexes[x]=index;
01038 *q++=image->
colormap[index];
01039 p++;
01040 }
01041
if (
SyncImagePixels(image) ==
MagickFalse)
01042
break;
01043
if (image->
previous == (
Image *) NULL)
01044
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01045 (
QuantumTick(y,image->
rows) !=
MagickFalse))
01046 {
01047 status=image->
progress_monitor(
LoadImageTag,y,image->
rows,
01048 image->
client_data);
01049
if (status ==
MagickFalse)
01050
break;
01051 }
01052 }
01053
break;
01054 }
01055
case 8:
01056 {
01057
01058
01059
01060
if ((bmp_info.compression ==
BI_RLE8) ||
01061 (bmp_info.compression ==
BI_RLE4))
01062 bytes_per_line=image->
columns;
01063
for (y=(
long) image->
rows-1; y >= 0; y--)
01064 {
01065 p=pixels+(image->
rows-y-1)*bytes_per_line;
01066 q=
SetImagePixels(image,0,y,image->
columns,1);
01067
if (q == (
PixelPacket *) NULL)
01068
break;
01069 indexes=
GetIndexes(image);
01070
for (x = (
long)image->
columns; x != 0; --x)
01071 {
01072 index=
ConstrainColormapIndex(image,*p);
01073 *indexes++=index;
01074 *q=image->
colormap[index];
01075 p++;
01076 q++;
01077 }
01078
if (
SyncImagePixels(image) ==
MagickFalse)
01079
break;
01080
if (image->
previous == (
Image *) NULL)
01081
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01082 (
QuantumTick(image->
rows-y-1,image->
rows) !=
MagickFalse))
01083 {
01084 status=image->
progress_monitor(
LoadImageTag,(
MagickOffsetType)
01085 image->
rows-y-1,image->
rows,image->
client_data);
01086
if (status ==
MagickFalse)
01087
break;
01088 }
01089 }
01090
break;
01091 }
01092
case 16:
01093 {
01094
unsigned long
01095 pixel;
01096
01097
01098
01099
01100
if (bmp_info.compression !=
BI_RGB &&
01101 bmp_info.compression !=
BI_BITFIELDS)
01102
ThrowReaderException(
CorruptImageError,
01103
"UnrecognizedImageCompression");
01104 bytes_per_line=2*(image->
columns+image->
columns%2);
01105 image->
storage_class=
DirectClass;
01106
for (y=(
long) image->
rows-1; y >= 0; y--)
01107 {
01108 p=pixels+(image->
rows-y-1)*bytes_per_line;
01109 q=
SetImagePixels(image,0,y,image->
columns,1);
01110
if (q == (
PixelPacket *) NULL)
01111
break;
01112
for (x=0; x < (
long) image->
columns; x++)
01113 {
01114 pixel=(
unsigned long) (*p++);
01115 pixel|=(*p++) << 8;
01116 red=((pixel & bmp_info.red_mask) << shift.
red) >> 16;
01117
if (quantum_bits.
red == 5)
01118 red|=((red & 0xe000) >> 5);
01119
if (quantum_bits.
red <= 8)
01120 red|=((red & 0xff00) >> 8);
01121 green=((pixel & bmp_info.green_mask) << shift.
green) >> 16;
01122
if (quantum_bits.
green == 5)
01123 green|=((green & 0xe000) >> 5);
01124
if (quantum_bits.
green == 6)
01125 green|=((green & 0xc000) >> 6);
01126
if (quantum_bits.
green <= 8)
01127 green|=((green & 0xff00) >> 8);
01128 blue=((pixel & bmp_info.blue_mask) << shift.
blue) >> 16;
01129
if (quantum_bits.
blue == 5)
01130 blue|=((blue & 0xe000) >> 5);
01131
if (quantum_bits.
blue <= 8)
01132 blue|=((blue & 0xff00) >> 8);
01133 q->
red=
ScaleShortToQuantum(red);
01134 q->
green=
ScaleShortToQuantum(green);
01135 q->
blue=
ScaleShortToQuantum(blue);
01136
if (image->
matte !=
MagickFalse)
01137 {
01138 opacity=((pixel & bmp_info.alpha_mask) << shift.
opacity) >> 16;
01139
if (quantum_bits.
opacity <= 8)
01140 q->
opacity|=((q->
opacity & 0xff00) >> 8);
01141 q->
opacity=
ScaleShortToQuantum(opacity);
01142 }
01143 q++;
01144 }
01145
if (
SyncImagePixels(image) ==
MagickFalse)
01146
break;
01147
if (image->
previous == (
Image *) NULL)
01148
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01149 (
QuantumTick(image->
rows-y-1,image->
rows) !=
MagickFalse))
01150 {
01151 status=image->
progress_monitor(
LoadImageTag,(
MagickOffsetType)
01152 image->
rows-y-1,image->
rows,image->
client_data);
01153
if (status ==
MagickFalse)
01154
break;
01155 }
01156 }
01157
break;
01158 }
01159
case 24:
01160 {
01161
01162
01163
01164 bytes_per_line=4*((image->
columns*24+31)/32);
01165
for (y=(
long) image->
rows-1; y >= 0; y--)
01166 {
01167 p=pixels+(image->
rows-y-1)*bytes_per_line;
01168 q=
SetImagePixels(image,0,y,image->
columns,1);
01169
if (q == (
PixelPacket *) NULL)
01170
break;
01171
for (x=0; x < (
long) image->
columns; x++)
01172 {
01173 q->
blue=
ScaleCharToQuantum(*p++);
01174 q->
green=
ScaleCharToQuantum(*p++);
01175 q->
red=
ScaleCharToQuantum(*p++);
01176 q++;
01177 }
01178
if (
SyncImagePixels(image) ==
MagickFalse)
01179
break;
01180
if (image->
previous == (
Image *) NULL)
01181
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01182 (
QuantumTick(image->
rows-y-1,image->
rows) !=
MagickFalse))
01183 {
01184 status=image->
progress_monitor(
LoadImageTag,(
MagickOffsetType)
01185 image->
rows-y-1,image->
rows,image->
client_data);
01186
if (status ==
MagickFalse)
01187
break;
01188 }
01189 }
01190
break;
01191 }
01192
case 32:
01193 {
01194
01195
01196
01197
if ((bmp_info.compression !=
BI_RGB) &&
01198 (bmp_info.compression !=
BI_BITFIELDS))
01199
ThrowReaderException(
CorruptImageError,
01200
"UnrecognizedImageCompression");
01201 bytes_per_line=4*(image->
columns);
01202
for (y=(
long) image->
rows-1; y >= 0; y--)
01203 {
01204
unsigned long
01205 pixel;
01206
01207 p=pixels+(image->
rows-y-1)*bytes_per_line;
01208 q=
SetImagePixels(image,0,y,image->
columns,1);
01209
if (q == (
PixelPacket *) NULL)
01210
break;
01211
for (x=0; x < (
long) image->
columns; x++)
01212 {
01213 pixel=(
unsigned long) (*p++);
01214 pixel|=(*p++ << 8);
01215 pixel|=(*p++ << 16);
01216 pixel|=(*p++ << 24);
01217 red=((pixel & bmp_info.red_mask) << shift.
red) >> 16;
01218
if (quantum_bits.
red == 8)
01219 red|=(red >> 8);
01220 green=((pixel & bmp_info.green_mask) << shift.
green) >> 16;
01221
if (quantum_bits.
green == 8)
01222 green|=(green >> 8);
01223 blue=((pixel & bmp_info.blue_mask) << shift.
blue) >> 16;
01224
if (quantum_bits.
blue == 8)
01225 blue|=(blue >> 8);
01226
if (image->
matte !=
MagickFalse)
01227 {
01228 opacity=((pixel & bmp_info.alpha_mask) << shift.
opacity) >> 16;
01229
if (quantum_bits.
opacity == 8)
01230 opacity|=(opacity >> 8);
01231 q->
opacity=
ScaleShortToQuantum(opacity);
01232 }
01233 q->
red=
ScaleShortToQuantum(red);
01234 q->
green=
ScaleShortToQuantum(green);
01235 q->
blue=
ScaleShortToQuantum(blue);
01236 q++;
01237 }
01238
if (
SyncImagePixels(image) ==
MagickFalse)
01239
break;
01240
if (image->
previous == (
Image *) NULL)
01241
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01242 (
QuantumTick(image->
rows-y-1,image->
rows) !=
MagickFalse))
01243 {
01244 status=image->
progress_monitor(
LoadImageTag,(
MagickOffsetType)
01245 image->
rows-y-1,image->
rows,image->
client_data);
01246
if (status ==
MagickFalse)
01247
break;
01248 }
01249 }
01250
break;
01251 }
01252
default:
01253
ThrowReaderException(
CorruptImageError,
"ImproperImageHeader");
01254 }
01255 pixels=(
unsigned char *)
RelinquishMagickMemory(pixels);
01256
if (
EOFBlob(image) !=
MagickFalse)
01257 {
01258
ThrowFileException(exception,
CorruptImageError,
"UnexpectedEndOfFile",
01259 image->
filename);
01260
break;
01261 }
01262
if (bmp_info.height < 0)
01263 {
01264
Image
01265 *flipped_image;
01266
01267
01268
01269
01270 flipped_image=
FlipImage(image,exception);
01271
if (flipped_image == (
Image *) NULL)
01272 {
01273
DestroyImageList(image);
01274
return((
Image *) NULL);
01275 }
01276 image=
DestroyImage(image);
01277 image=flipped_image;
01278 }
01279
01280
01281
01282
if (image_info->
number_scenes != 0)
01283
if (image->
scene >= (image_info->
scene+image_info->
number_scenes-1))
01284
break;
01285 *magick=
'\0';
01286
if (bmp_info.ba_offset != 0)
01287 (
void)
SeekBlob(image,(
MagickOffsetType) bmp_info.ba_offset,SEEK_SET);
01288 (
void)
ReadBlob(image,2,magick);
01289
if (
IsBMP(magick,2) !=
MagickFalse)
01290 {
01291
01292
01293
01294
AllocateNextImage(image_info,image);
01295
if (image->
next == (
Image *) NULL)
01296 {
01297
DestroyImageList(image);
01298
return((
Image *) NULL);
01299 }
01300 image=
SyncNextImageInList(image);
01301
if (image->
progress_monitor != (
MagickProgressMonitor) NULL)
01302 {
01303 status=image->
progress_monitor(
LoadImagesTag,
TellBlob(image),
01304
GetBlobSize(image),image->
client_data);
01305
if (status ==
MagickFalse)
01306
break;
01307 }
01308 }
01309 }
while (
IsBMP(magick,2) !=
MagickFalse);
01310
CloseBlob(image);
01311
return(
GetFirstImageInList(image));
01312 }
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337 ModuleExport void RegisterBMPImage(
void)
01338 {
01339
MagickInfo
01340 *entry;
01341
01342 entry=
SetMagickInfo(
"BMP");
01343 entry->
decoder=(
DecoderHandler *)
ReadBMPImage;
01344 entry->
encoder=(
EncoderHandler *)
WriteBMPImage;
01345 entry->
magick=(
MagickHandler *)
IsBMP;
01346 entry->
description=
AcquireString(
"Microsoft Windows bitmap image");
01347 entry->
module=
AcquireString(
"BMP");
01348 entry->
adjoin=
MagickFalse;
01349 entry->
seekable_stream=
MagickTrue;
01350 (
void)
RegisterMagickInfo(entry);
01351 entry=
SetMagickInfo(
"BMP2");
01352 entry->
encoder=(
EncoderHandler *)
WriteBMPImage;
01353 entry->
magick=(
MagickHandler *)
IsBMP;
01354 entry->
description=
AcquireString(
"Microsoft Windows bitmap image v2");
01355 entry->
module=
AcquireString(
"BMP");
01356 entry->
adjoin=
MagickFalse;
01357 entry->
seekable_stream=
MagickTrue;
01358 (
void)
RegisterMagickInfo(entry);
01359 entry=
SetMagickInfo(
"BMP3");
01360 entry->
encoder=(
EncoderHandler *)
WriteBMPImage;
01361 entry->