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->
magick=(
MagickHandler *)
IsBMP;
01362 entry->
description=
AcquireString(
"Microsoft Windows bitmap image v3");
01363 entry->
module=
AcquireString(
"BMP");
01364 entry->
adjoin=
MagickFalse;
01365 entry->
seekable_stream=
MagickTrue;
01366 (
void)
RegisterMagickInfo(entry);
01367 }
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388 ModuleExport void UnregisterBMPImage(
void)
01389 {
01390 (
void)
UnregisterMagickInfo(
"BMP");
01391 (
void)
UnregisterMagickInfo(
"BMP2");
01392 (
void)
UnregisterMagickInfo(
"BMP3");
01393 }
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422 static MagickBooleanType WriteBMPImage(
const ImageInfo *image_info,
Image *image)
01423 {
01424
BMPInfo
01425 bmp_info;
01426
01427
long
01428 y;
01429
01430
MagickBooleanType
01431 have_color_info,
01432 status;
01433
01434
MagickOffsetType
01435 scene;
01436
01437
register const PixelPacket
01438 *p;
01439
01440
register IndexPacket
01441 *indexes;
01442
01443
register long
01444 i,
01445 x;
01446
01447
register unsigned char
01448 *q;
01449
01450
StringInfo
01451 *profile;
01452
01453
unsigned char
01454 *bmp_data,
01455 *pixels;
01456
01457
unsigned long
01458 bytes_per_line,
01459 type;
01460
01461
01462
01463
01464
assert(image_info != (
const ImageInfo *) NULL);
01465
assert(image_info->
signature ==
MagickSignature);
01466
assert(image != (
Image *) NULL);
01467
assert(image->
signature ==
MagickSignature);
01468
if (image->
debug !=
MagickFalse)
01469 (
void)
LogMagickEvent(
TraceEvent,
GetMagickModule(),image->
filename);
01470 status=
OpenBlob(image_info,image,
WriteBinaryBlobMode,&image->
exception);
01471
if (status ==
MagickFalse)
01472
return(status);
01473 type=4;
01474
if (
LocaleCompare(image_info->
magick,
"BMP2") == 0)
01475 type=2;
01476
else
01477
if (
LocaleCompare(image_info->
magick,
"BMP3") == 0)
01478 type=3;
01479 scene=0;
01480
do
01481 {
01482
01483
01484
01485 (
void)
SetImageColorspace(image,
RGBColorspace);
01486 (
void)
ResetMagickMemory(&bmp_info,0,
sizeof(bmp_info));
01487 bmp_info.file_size=14+12;
01488
if (type > 2)
01489 bmp_info.file_size+=28;
01490 bmp_info.offset_bits=bmp_info.file_size;
01491 bmp_info.compression=
BI_RGB;
01492
if ((image->
storage_class ==
PseudoClass) && (image->
colors > 256))
01493 image->
storage_class=
DirectClass;
01494
if (image->
storage_class !=
DirectClass)
01495 {
01496
01497
01498
01499 bmp_info.bits_per_pixel=8;
01500
if (image->
colors <= 2)
01501 bmp_info.bits_per_pixel=1;
01502
else
01503
if (image->
colors <= 16)
01504 bmp_info.bits_per_pixel=4;
01505
else
01506
if (image->
colors <= 256)
01507 bmp_info.bits_per_pixel=8;
01508
if (image->
compression ==
RLECompression)
01509 bmp_info.bits_per_pixel=8;
01510 bmp_info.number_colors=1 << bmp_info.bits_per_pixel;
01511
if (image->
matte !=
MagickFalse)
01512 image->
storage_class=
DirectClass;
01513
else
01514
if (bmp_info.number_colors < image->
colors)
01515 image->
storage_class=
DirectClass;
01516
else
01517 {
01518 bmp_info.file_size+=3*(1 << bmp_info.bits_per_pixel);
01519 bmp_info.offset_bits+=3*(1 << bmp_info.bits_per_pixel);
01520
if (type > 2)
01521 {
01522 bmp_info.file_size+=(1 << bmp_info.bits_per_pixel);
01523 bmp_info.offset_bits+=(1 << bmp_info.bits_per_pixel);
01524 }
01525 }
01526 }
01527
if (image->
storage_class ==
DirectClass)
01528 {
01529
01530
01531
01532 bmp_info.number_colors=0;
01533 bmp_info.bits_per_pixel=(
unsigned short)
01534 ((type > 3) && (image->
matte !=
MagickFalse) ? 32 : 24);
01535 bmp_info.compression=(
MagickBooleanType)
01536 ((type > 3) && (image->
matte !=
MagickFalse) ?
BI_BITFIELDS :
BI_RGB);
01537 }
01538 bytes_per_line=4*((image->
columns*bmp_info.bits_per_pixel+31)/32);
01539 bmp_info.ba_offset=0;
01540 profile=
GetImageProfile(image,
"icc");
01541 have_color_info=(
MagickBooleanType)
01542 (((image->
rendering_intent !=
UndefinedIntent) ||
01543 (profile != (
StringInfo *) NULL) || (image->
gamma != 0.0)));
01544
if (type == 2)
01545 bmp_info.size=12;
01546
else
01547
if ((type == 3) || ((image->
matte ==
MagickFalse) &&
01548 (have_color_info ==
MagickFalse)))
01549 {
01550 type=3;
01551 bmp_info.size=40;
01552 }
01553
else
01554 {
01555
int
01556 extra_size;
01557
01558 bmp_info.size=108;
01559 extra_size=68;
01560
if ((image->
rendering_intent !=
UndefinedIntent) ||
01561 (profile != (
StringInfo *) NULL))
01562 {
01563 bmp_info.size=124;
01564 extra_size+=16;
01565 }
01566 bmp_info.file_size+=extra_size;
01567 bmp_info.offset_bits+=extra_size;
01568 }
01569 bmp_info.width=(
long) image->
columns;
01570 bmp_info.height=(
long) image->
rows;
01571 bmp_info.planes=1;
01572 bmp_info.image_size=bytes_per_line*image->
rows;
01573 bmp_info.file_size+=bmp_info.image_size;
01574 bmp_info.x_pixels=75*39;
01575 bmp_info.y_pixels=75*39;
01576
switch (image->
units)
01577 {
01578
case UndefinedResolution:
01579
case PixelsPerInchResolution:
01580 {
01581 bmp_info.x_pixels=(
unsigned long) (100.0*image->
x_resolution/2.54);
01582 bmp_info.y_pixels=(
unsigned long) (100.0*image->
y_resolution/2.54);
01583
break;
01584 }
01585
case PixelsPerCentimeterResolution:
01586 {
01587 bmp_info.x_pixels=(
unsigned long) (100.0*image->
x_resolution);
01588 bmp_info.y_pixels=(
unsigned long) (100.0*image->
y_resolution);
01589
break;
01590 }
01591 }
01592 bmp_info.colors_important=bmp_info.number_colors;
01593
01594
01595
01596 pixels=(
unsigned char *)
AcquireMagickMemory((size_t) bmp_info.image_size);
01597
if (pixels == (
unsigned char *) NULL)
01598
ThrowWriterException(
ResourceLimitError,
"MemoryAllocationFailed");
01599 (
void)
ResetMagickMemory(pixels,0,(size_t) bmp_info.image_size);
01600
switch (bmp_info.bits_per_pixel)
01601 {
01602
case 1:
01603 {
01604
unsigned long
01605 bit,
01606 byte;
01607
01608
01609
01610
01611
for (y=0; y < (
long) image->
rows; y++)
01612 {
01613 p=
AcquireImagePixels(image,0,y,image->
columns,1,&image->
exception);
01614
if (p == (
const PixelPacket *) NULL)
01615
break;
01616 indexes=
GetIndexes(image);
01617 q=pixels+(image->
rows-y-1)*bytes_per_line;
01618 bit=0;
01619 byte=0;
01620
for (x=0; x < (
long) image->
columns; x++)
01621 {
01622 byte<<=1;
01623 byte|=indexes[x] != 0 ? 0x01 : 0x00;
01624 bit++;
01625
if (bit == 8)
01626 {
01627 *q++=(
unsigned char) byte;
01628 bit=0;
01629 byte=0;
01630 }
01631 }
01632
if (bit != 0)
01633 {
01634 *q++=(
unsigned char) (byte << (8-bit));
01635 x++;
01636 }
01637
for (x=(
long) (image->
columns+7)/8; x < (
long) bytes_per_line; x++)
01638 *q++=0x00;
01639
if (image->
previous == (
Image *) NULL)
01640
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01641 (
QuantumTick(y,image->
rows) !=
MagickFalse))
01642 {
01643 status=image->
progress_monitor(
SaveImageTag,y,image->
rows,
01644 image->
client_data);
01645
if (status ==
MagickFalse)
01646
break;
01647 }
01648 }
01649
break;
01650 }
01651
case 4:
01652 {
01653
unsigned long
01654 nibble,
01655 byte;
01656
01657
01658
01659
01660
for (y=0; y < (
long) image->
rows; y++)
01661 {
01662 p=
AcquireImagePixels(image,0,y,image->
columns,1,&image->
exception);
01663
if (p == (
const PixelPacket *) NULL)
01664
break;
01665 indexes=
GetIndexes(image);
01666 q=pixels+(image->
rows-y-1)*bytes_per_line;
01667 nibble=0;
01668 byte=0;
01669
for (x=0; x < (
long) image->
columns; x++)
01670 {
01671 byte<<=4;
01672 byte|=(indexes[x] & 0x0f);
01673 nibble++;
01674
if (nibble == 2)
01675 {
01676 *q++=(
unsigned char) byte;
01677 nibble=0;
01678 byte=0;
01679 }
01680 }
01681
if (nibble != 0)
01682 {
01683 *q++=(
unsigned char) (byte << 4);
01684 x++;
01685 }
01686
for (x=(
long) (image->
columns+1)/2; x < (
long) bytes_per_line; x++)
01687 *q++=0x00;
01688
if (image->
previous == (
Image *) NULL)
01689
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01690 (
QuantumTick(y,image->
rows) !=
MagickFalse))
01691 {
01692 status=image->
progress_monitor(
SaveImageTag,y,image->
rows,
01693 image->
client_data);
01694
if (status ==
MagickFalse)
01695
break;
01696 }
01697 }
01698
break;
01699 }
01700
case 8:
01701 {
01702
01703
01704
01705
for (y=0; y < (
long) image->
rows; y++)
01706 {
01707 p=
AcquireImagePixels(image,0,y,image->
columns,1,&image->
exception);
01708
if (p == (
const PixelPacket *) NULL)
01709
break;
01710 indexes=
GetIndexes(image);
01711 q=pixels+(image->
rows-y-1)*bytes_per_line;
01712
for (x=0; x < (
long) image->
columns; x++)
01713 *q++=(
unsigned char) indexes[x];
01714
for ( ; x < (
long) bytes_per_line; x++)
01715 *q++=0x00;
01716
if (image->
previous == (
Image *) NULL)
01717
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01718 (
QuantumTick(y,image->
rows) !=
MagickFalse))
01719 {
01720 status=image->
progress_monitor(
SaveImageTag,y,image->
rows,
01721 image->
client_data);
01722
if (status ==
MagickFalse)
01723
break;
01724 }
01725 }
01726
break;
01727 }
01728
case 24:
01729
case 32:
01730 {
01731
01732
01733
01734
for (y=0; y < (
long) image->
rows; y++)
01735 {
01736 p=
AcquireImagePixels(image,0,y,image->
columns,1,&image->
exception);
01737
if (p == (
const PixelPacket *) NULL)
01738
break;
01739 q=pixels+(image->
rows-y-1)*bytes_per_line;
01740
for (x=0; x < (
long) image->
columns; x++)
01741 {
01742 *q++=
ScaleQuantumToChar(p->
blue);
01743 *q++=
ScaleQuantumToChar(p->
green);
01744 *q++=
ScaleQuantumToChar(p->
red);
01745
if (bmp_info.bits_per_pixel == 32)
01746 *q++=
ScaleQuantumToChar(p->
opacity);
01747 p++;
01748 }
01749
if (bmp_info.bits_per_pixel == 24)
01750
for (x=3L*(
long) image->
columns; x < (
long) bytes_per_line; x++)
01751 *q++=0x00;
01752
if (image->
previous == (
Image *) NULL)
01753
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01754 (
QuantumTick(y,image->
rows) !=
MagickFalse))
01755 {
01756 status=image->
progress_monitor(
SaveImageTag,y,image->
rows,
01757 image->
client_data);
01758
if (status ==
MagickFalse)
01759
break;
01760 }
01761 }
01762
break;
01763 }
01764 }
01765
if ((type > 2) && (bmp_info.bits_per_pixel == 8))
01766
if (image->
compression !=
NoCompression)
01767 {
01768 size_t
01769 length;
01770
01771
01772
01773
01774 length=(size_t) (2*(bytes_per_line+2)*(image->
rows+2)+2);
01775 bmp_data=(
unsigned char *)
AcquireMagickMemory(length+bytes_per_line);
01776
if (bmp_data == (
unsigned char *) NULL)
01777 {
01778 pixels=(
unsigned char *)
RelinquishMagickMemory(pixels);
01779
ThrowWriterException(
ResourceLimitError,
"MemoryAllocationFailed");
01780 }
01781 bmp_info.file_size-=bmp_info.image_size;
01782 bmp_info.image_size=(
unsigned long)
01783
EncodeImage(image,bytes_per_line,pixels,bmp_data);
01784 bmp_info.file_size+=bmp_info.image_size;
01785 pixels=(
unsigned char *)
RelinquishMagickMemory(pixels);
01786 pixels=bmp_data;
01787 bmp_info.compression=
BI_RLE8;
01788 }
01789
01790
01791
01792
if (image->
debug !=
MagickFalse)
01793 {
01794 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01795
" Writing BMP version %ld datastream",type);
01796
if (image->
storage_class ==
DirectClass)
01797 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01798
" Storage class=DirectClass");
01799
else
01800 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01801
" Storage class=PseudoClass");
01802 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01803
" Image depth=%lu",image->
depth);
01804
if (image->
matte !=
MagickFalse)
01805 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01806
" Matte=True");
01807
else
01808 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01809
" Matte=MagickFalse");
01810 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01811
" BMP bits_per_pixel=%d",bmp_info.bits_per_pixel);
01812
switch ((
int) bmp_info.compression)
01813 {
01814
case BI_RGB:
01815 {
01816 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01817
" Compression=BI_RGB");
01818
break;
01819 }
01820
case BI_RLE8:
01821 {
01822 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01823
" Compression=BI_RLE8");
01824
break;
01825 }
01826
case BI_BITFIELDS:
01827 {
01828 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01829
" Compression=BI_BITFIELDS");
01830
break;
01831 }
01832
default:
01833 {
01834 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01835
" Compression=UNKNOWN (%lu)",bmp_info.compression);
01836
break;
01837 }
01838 }
01839
if (bmp_info.number_colors == 0)
01840 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01841
" Number_colors=unspecified");
01842
else
01843 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01844
" Number_colors=%lu",bmp_info.number_colors);
01845 }
01846 (
void)
WriteBlob(image,2,(
unsigned char *)
"BM");
01847 (
void)
WriteBlobLSBLong(image,bmp_info.file_size);
01848 (
void)
WriteBlobLSBLong(image,bmp_info.ba_offset);
01849 (
void)
WriteBlobLSBLong(image,bmp_info.offset_bits);
01850
if (type == 2)
01851 {
01852
01853
01854
01855 (
void)
WriteBlobLSBLong(image,bmp_info.size);
01856 (
void)
WriteBlobLSBShort(image,(
unsigned short) bmp_info.width);
01857 (
void)
WriteBlobLSBShort(image,(
unsigned short) bmp_info.height);
01858 (
void)
WriteBlobLSBShort(image,bmp_info.planes);
01859 (
void)
WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
01860 }
01861
else
01862 {
01863
01864
01865
01866 (
void)
WriteBlobLSBLong(image,bmp_info.size);
01867 (
void)
WriteBlobLSBLong(image,(
unsigned long) bmp_info.width);
01868 (
void)
WriteBlobLSBLong(image,(
unsigned long) bmp_info.height);
01869 (
void)
WriteBlobLSBShort(image,bmp_info.planes);
01870 (
void)
WriteBlobLSBShort(image,bmp_info.bits_per_pixel);
01871 (
void)
WriteBlobLSBLong(image,bmp_info.
compression);
01872 (
void)
WriteBlobLSBLong(image,bmp_info.image_size);
01873 (
void)
WriteBlobLSBLong(image,bmp_info.x_pixels);
01874 (
void)
WriteBlobLSBLong(image,bmp_info.y_pixels);
01875 (
void)
WriteBlobLSBLong(image,bmp_info.number_colors);
01876 (
void)
WriteBlobLSBLong(image,bmp_info.colors_important);
01877 }
01878
if ((type > 3) && ((image->
matte !=
MagickFalse) ||
01879 (have_color_info !=
MagickFalse)))
01880 {
01881
01882
01883
01884 (
void)
WriteBlobLSBLong(image,0x00ff0000UL);
01885 (
void)
WriteBlobLSBLong(image,0x0000ff00UL);
01886 (
void)
WriteBlobLSBLong(image,0x000000ffUL);
01887 (
void)
WriteBlobLSBLong(image,0xff000000UL);
01888 (
void)
WriteBlobLSBLong(image,0x00000001UL);
01889 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01890 image->
chromaticity.
red_primary.
x*0x3ffffff);
01891 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01892 image->
chromaticity.
red_primary.
y*0x3ffffff);
01893 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01894 (1.000f-(image->
chromaticity.
red_primary.
x+
01895 image->
chromaticity.
red_primary.
y)*0x3ffffff));
01896 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01897 image->
chromaticity.
green_primary.
x*0x3ffffff);
01898 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01899 image->
chromaticity.
green_primary.
y*0x3ffffff);
01900 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01901 (1.000f-(image->
chromaticity.
green_primary.
x+
01902 image->
chromaticity.
green_primary.
y)*0x3ffffff));
01903 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01904 image->
chromaticity.
blue_primary.
x*0x3ffffff);
01905 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01906 image->
chromaticity.
blue_primary.
y*0x3ffffff);
01907 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01908 (1.000f-(image->
chromaticity.
blue_primary.
x+
01909 image->
chromaticity.
blue_primary.
y)*0x3ffffff));
01910 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01911 bmp_info.gamma_scale.x*0xffff);
01912 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01913 bmp_info.gamma_scale.y*0xffff);
01914 (
void)
WriteBlobLSBLong(image,(
unsigned long)
01915 bmp_info.gamma_scale.z*0xffff);
01916
if ((image->
rendering_intent !=
UndefinedIntent) ||
01917 (profile != (
StringInfo *) NULL))
01918 {
01919
long
01920 intent;
01921
01922
switch ((
int) image->
rendering_intent)
01923 {
01924
case SaturationIntent:
01925 {
01926 intent=
LCS_GM_BUSINESS;
01927
break;
01928 }
01929
case RelativeIntent:
01930 {
01931 intent=
LCS_GM_GRAPHICS;
01932
break;
01933 }
01934
case PerceptualIntent:
01935 {
01936 intent=
LCS_GM_IMAGES;
01937
break;
01938 }
01939
case AbsoluteIntent:
01940 {
01941 intent=
LCS_GM_ABS_COLORIMETRIC;
01942
break;
01943 }
01944
default:
01945 {
01946 intent=0;
01947
break;
01948 }
01949 }
01950 (
void)
WriteBlobLSBLong(image,(
unsigned long) intent);
01951 (
void)
WriteBlobLSBLong(image,0x00);
01952 (
void)
WriteBlobLSBLong(image,0x00);
01953 (
void)
WriteBlobLSBLong(image,0x00);
01954 }
01955 }
01956
if (image->
storage_class ==
PseudoClass)
01957 {
01958
unsigned char
01959 *bmp_colormap;
01960
01961
01962
01963
01964
if (image->
debug !=
MagickFalse)
01965 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01966
" Colormap: %ld entries",image->
colors);
01967 bmp_colormap=(
unsigned char *)
01968
AcquireMagickMemory((size_t) (4*(1 << bmp_info.bits_per_pixel)));
01969
if (bmp_colormap == (
unsigned char *) NULL)
01970
ThrowWriterException(
ResourceLimitError,
"MemoryAllocationFailed");
01971 q=bmp_colormap;
01972
for (i=0; i < (
long) image->
colors; i++)
01973 {
01974 *q++=
ScaleQuantumToChar(image->
colormap[i].
blue);
01975 *q++=
ScaleQuantumToChar(image->
colormap[i].
green);
01976 *q++=
ScaleQuantumToChar(image->
colormap[i].
red);
01977
if (type > 2)
01978 *q++=(
unsigned char) 0x0;
01979 }
01980
for ( ; i < (
long) (1UL << bmp_info.bits_per_pixel); i++)
01981 {
01982 *q++=(
unsigned char) 0x00;
01983 *q++=(
unsigned char) 0x00;
01984 *q++=(
unsigned char) 0x00;
01985
if (type > 2)
01986 *q++=(
unsigned char) 0x00;
01987 }
01988
if (type <= 2)
01989 (
void)
WriteBlob(image,(size_t) (3*(1L << bmp_info.bits_per_pixel)),
01990 bmp_colormap);
01991
else
01992 (
void)
WriteBlob(image,(size_t) (4*(1L << bmp_info.bits_per_pixel)),
01993 bmp_colormap);
01994 bmp_colormap=(
unsigned char *)
RelinquishMagickMemory(bmp_colormap);
01995 }
01996
if (image->
debug !=
MagickFalse)
01997 (
void)
LogMagickEvent(
CoderEvent,
GetMagickModule(),
01998
" Pixels: %lu bytes",bmp_info.image_size);
01999 (
void)
WriteBlob(image,(size_t) bmp_info.image_size,pixels);
02000 pixels=(
unsigned char *)
RelinquishMagickMemory(pixels);
02001
if (image->
next == (
Image *) NULL)
02002
break;
02003 image=
SyncNextImageInList(image);
02004
if (image->
progress_monitor != (
MagickProgressMonitor) NULL)
02005 {
02006 status=image->
progress_monitor(
SaveImagesTag,scene,
02007
GetImageListLength(image),image->
client_data);
02008
if (status ==
MagickFalse)
02009
break;
02010 }
02011 scene++;
02012 }
while (image_info->
adjoin !=
MagickFalse);
02013
CloseBlob(image);
02014
return(
MagickTrue);
02015 }