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
00044
00045
00046
#include "magick/studio.h"
00047
#include "magick/attribute.h"
00048
#include "magick/blob.h"
00049
#include "magick/blob_private.h"
00050
#include "magick/color.h"
00051
#include "magick/color_private.h"
00052
#include "magick/colorspace.h"
00053
#include "magick/constitute.h"
00054
#include "magick/error.h"
00055
#include "magick/error_private.h"
00056
#include "magick/geometry.h"
00057
#include "magick/image.h"
00058
#include "magick/image_private.h"
00059
#include "magick/list.h"
00060
#include "magick/log.h"
00061
#include "magick/magick.h"
00062
#include "magick/memory_.h"
00063
#include "magick/monitor.h"
00064
#include "magick/option.h"
00065
#include "magick/profile.h"
00066
#include "magick/resource_.h"
00067
#include "magick/static.h"
00068
#include "magick/string_.h"
00069
#include "magick/utility.h"
00070
#include <setjmp.h>
00071
#if defined(HasJPEG)
00072
#define JPEG_INTERNAL_OPTIONS
00073
#if defined(__MINGW32__)
00074
# define XMD_H 1
00075
#endif
00076
#undef HAVE_STDLIB_H
00077
#include "jpeglib.h"
00078
#include "jerror.h"
00079
#endif
00080
00081
00082
00083
00084 #define ICC_MARKER (JPEG_APP0+2)
00085 #define ICC_PROFILE "ICC_PROFILE"
00086 #define IPTC_MARKER (JPEG_APP0+13)
00087 #define XML_MARKER (JPEG_APP0+1)
00088 #define MaxBufferExtent 8192
00089
00090
00091
00092
00093
#if defined(HasJPEG)
00094
typedef struct _DestinationManager
00095 {
00096
struct jpeg_destination_mgr
00097 manager;
00098
00099
Image
00100 *image;
00101
00102 JOCTET
00103 *buffer;
00104 } DestinationManager;
00105
00106
typedef struct _ErrorManager
00107 {
00108
Image
00109 *image;
00110
00111 jmp_buf
00112 error_recovery;
00113 } ErrorManager;
00114
00115
typedef struct _SourceManager
00116 {
00117
struct jpeg_source_mgr
00118 manager;
00119
00120
Image
00121 *image;
00122
00123 JOCTET
00124 *buffer;
00125
00126
boolean
00127 start_of_blob;
00128 } SourceManager;
00129
#endif
00130
00131
00132
00133
00134
#if defined(HasJPEG)
00135
static MagickBooleanType
00136 WriteJPEGImage(
const ImageInfo *,
Image *);
00137
#endif
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 static MagickBooleanType IsJPEG(
const unsigned char *magick,
const size_t length)
00167 {
00168
if (length < 3)
00169
return(
MagickFalse);
00170
if (memcmp(magick,
"\377\330\377",3) == 0)
00171
return(
MagickTrue);
00172
return(
MagickFalse);
00173 }
00174
00175
#if defined(HasJPEG)
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
static MagickBooleanType EmitMessage(j_common_ptr jpeg_info,
int level)
00206 {
00207
char
00208 message[JMSG_LENGTH_MAX];
00209
00210 ErrorManager
00211 *error_manager;
00212
00213
Image
00214 *image;
00215
00216 (jpeg_info->err->format_message)(jpeg_info,message);
00217 error_manager=(ErrorManager *) jpeg_info->client_data;
00218 image=error_manager->image;
00219
if (level < 0)
00220 {
00221
if ((jpeg_info->err->num_warnings == 0) ||
00222 (jpeg_info->err->trace_level >= 3))
00223
ThrowBinaryException(CorruptImageWarning,(
char *) message,
00224 image->
filename);
00225 jpeg_info->err->num_warnings++;
00226 }
00227
else
00228
if (jpeg_info->err->trace_level >= level)
00229
ThrowBinaryException(CoderError,(
char *) message,image->
filename);
00230
return(
MagickTrue);
00231 }
00232
00233
static boolean FillInputBuffer(j_decompress_ptr cinfo)
00234 {
00235 SourceManager
00236 *source;
00237
00238 source=(SourceManager *) cinfo->src;
00239 source->manager.bytes_in_buffer=(size_t)
00240
ReadBlob(source->image,MaxBufferExtent,source->buffer);
00241
if (source->manager.bytes_in_buffer == 0)
00242 {
00243
if (source->start_of_blob != 0)
00244 ERREXIT(cinfo,JERR_INPUT_EMPTY);
00245 WARNMS(cinfo,JWRN_JPEG_EOF);
00246 source->buffer[0]=(JOCTET) 0xff;
00247 source->buffer[1]=(JOCTET) JPEG_EOI;
00248 source->manager.bytes_in_buffer=2;
00249 }
00250 source->manager.next_input_byte=source->buffer;
00251 source->start_of_blob=FALSE;
00252
return(TRUE);
00253 }
00254
00255
static int GetCharacter(j_decompress_ptr jpeg_info)
00256 {
00257
if (jpeg_info->src->bytes_in_buffer == 0)
00258 (
void) (*jpeg_info->src->fill_input_buffer)(jpeg_info);
00259 jpeg_info->src->bytes_in_buffer--;
00260
return((
int) GETJOCTET(*jpeg_info->src->next_input_byte++));
00261 }
00262
00263
static void InitializeSource(j_decompress_ptr cinfo)
00264 {
00265 SourceManager
00266 *source;
00267
00268 source=(SourceManager *) cinfo->src;
00269 source->start_of_blob=TRUE;
00270 }
00271
00272
static void JPEGErrorHandler(j_common_ptr jpeg_info)
00273 {
00274 ErrorManager
00275 *error_manager;
00276
00277 (
void) EmitMessage(jpeg_info,0);
00278 error_manager=(ErrorManager *) jpeg_info->client_data;
00279 longjmp(error_manager->error_recovery,1);
00280 }
00281
00282
static boolean ReadComment(j_decompress_ptr jpeg_info)
00283 {
00284
char
00285 *comment;
00286
00287 ErrorManager
00288 *error_manager;
00289
00290
Image
00291 *image;
00292
00293
register char
00294 *p;
00295
00296
register long
00297 i;
00298
00299 size_t
00300 length;
00301
00302
00303
00304
00305 error_manager=(ErrorManager *) jpeg_info->
client_data;
00306 image=error_manager->image;
00307 length=(size_t) ((
unsigned long) GetCharacter(jpeg_info) << 8);
00308 length+=GetCharacter(jpeg_info);
00309 length-=2;
00310
if (length <= 0)
00311
return(
MagickTrue);
00312 comment=(
char *)
AcquireMagickMemory(length+MaxTextExtent);
00313
if (comment == (
char *) NULL)
00314
ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
00315 image->
filename);
00316
00317
00318
00319 i=(
long) length-1;
00320
for (p=comment; i-- >= 0; p++)
00321 *p=(
char) GetCharacter(jpeg_info);
00322 *p=
'\0';
00323 (
void)
SetImageAttribute(image,
"Comment",comment);
00324 comment=(
char *)
RelinquishMagickMemory(comment);
00325
return(
MagickTrue);
00326 }
00327
00328
static boolean ReadICCProfile(j_decompress_ptr jpeg_info)
00329 {
00330
char
00331 magick[12];
00332
00333 ErrorManager
00334 *error_manager;
00335
00336
Image
00337 *image;
00338
00339
MagickBooleanType
00340 status;
00341
00342
register long
00343 i;
00344
00345
register unsigned char
00346 *p;
00347
00348 size_t
00349 length;
00350
00351
StringInfo
00352 *icc_profile,
00353 *profile;
00354
00355
00356
00357
00358 length=(size_t) ((
unsigned long) GetCharacter(jpeg_info) << 8);
00359 length+=(size_t) GetCharacter(jpeg_info);
00360 length-=2;
00361
if (length <= 14)
00362 {
00363
while (length-- > 0)
00364 (
void) GetCharacter(jpeg_info);
00365
return(
MagickTrue);
00366 }
00367
for (i=0; i < 12; i++)
00368 magick[i]=(
char) GetCharacter(jpeg_info);
00369
if (
LocaleCompare(magick,ICC_PROFILE) != 0)
00370 {
00371
00372
00373
00374
for (i=0; i < (
long) (length-12); i++)
00375 (
void) GetCharacter(jpeg_info);
00376
return(
MagickTrue);
00377 }
00378 (
void) GetCharacter(jpeg_info);
00379 (
void) GetCharacter(jpeg_info);
00380 length-=14;
00381 error_manager=(ErrorManager *) jpeg_info->client_data;
00382 image=error_manager->image;
00383 profile=
AcquireStringInfo(length);
00384
if (profile == (
StringInfo *) NULL)
00385
ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
00386 image->
filename);
00387 p=profile->
datum;
00388
for (i=(
long) profile->
length-1; i >= 0; i--)
00389 *p++=(
unsigned char) GetCharacter(jpeg_info);
00390 icc_profile=
GetImageProfile(image,
"icc");
00391
if (icc_profile != (
StringInfo *) NULL)
00392 {
00393
ConcatenateStringInfo(icc_profile,profile);
00394 profile=
DestroyStringInfo(profile);
00395 }
00396
else
00397 {
00398 status=
SetImageProfile(image,
"icc",profile);
00399 profile=
DestroyStringInfo(profile);
00400
if (status ==
MagickFalse)
00401
ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
00402 image->
filename);
00403 }
00404
if (image->
debug !=
MagickFalse)
00405 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
00406
"Profile: ICC, %lu bytes",(
unsigned long) length);
00407
return(
MagickTrue);
00408 }
00409
00410
static boolean ReadIPTCProfile(j_decompress_ptr jpeg_info)
00411 {
00412
char
00413 magick[
MaxTextExtent];
00414
00415 ErrorManager
00416 *error_manager;
00417
00418
Image
00419 *image;
00420
00421
MagickBooleanType
00422 status;
00423
00424
register long
00425 i;
00426
00427
register unsigned char
00428 *p;
00429
00430 size_t
00431 length,
00432 tag_length;
00433
00434
StringInfo
00435 *iptc_profile,
00436 *profile;
00437
00438
#ifdef GET_ONLY_IPTC_DATA
00439
unsigned char
00440 tag[
MaxTextExtent];
00441
#endif
00442
00443
00444
00445
00446 length=(size_t) ((
unsigned long) GetCharacter(jpeg_info) << 8);
00447 length+=(size_t) GetCharacter(jpeg_info);
00448
if (length <= 2)
00449
return(
MagickTrue);
00450 length-=2;
00451 tag_length=0;
00452
#ifdef GET_ONLY_IPTC_DATA
00453
*tag=
'\0';
00454
#endif
00455
error_manager=(ErrorManager *) jpeg_info->client_data;
00456 image=error_manager->image;
00457 iptc_profile=
GetImageProfile(image,
"iptc");
00458
if (iptc_profile == (
StringInfo *) NULL)
00459 {
00460
#ifdef GET_ONLY_IPTC_DATA
00461
00462
00463
00464
for (*tag=
'\0'; length > 0; )
00465 {
00466 *tag=GetCharacter(jpeg_info);
00467 *(tag+1)=GetCharacter(jpeg_info);
00468 length-=2;
00469
if ((*tag == 0x1c) && (*(tag+1) == 0x02))
00470
break;
00471 }
00472 tag_length=2;
00473
#else
00474
00475
00476
00477
for (i=0; i < 10; i++)
00478 magick[i]=(
char) GetCharacter(jpeg_info);
00479 magick[10]=
'\0';
00480
if (length <= 10)
00481
return(
MagickTrue);
00482 length-=10;
00483
if (
LocaleCompare(magick,
"Photoshop ") != 0)
00484 {
00485
00486
00487
00488
for (i=0; i < (
long) length; i++)
00489 (
void) GetCharacter(jpeg_info);
00490
return(
MagickTrue);
00491 }
00492
00493
00494
00495
for (i=0; i < 4; i++)
00496 (
void) GetCharacter(jpeg_info);
00497
if (length <= 4)
00498
return(
MagickTrue);
00499 length-=4;
00500 tag_length=0;
00501
#endif
00502
}
00503
if (length == 0)
00504
return(
MagickTrue);
00505 profile=
AcquireStringInfo(length);
00506
if (profile == (
StringInfo *) NULL)
00507
ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
00508 image->
filename);
00509 p=profile->
datum;
00510
for (i=(
long) profile->
length-1; i >= 0; i--)
00511 *p++=(
unsigned char) GetCharacter(jpeg_info);
00512 iptc_profile=
GetImageProfile(image,
"iptc");
00513
if (iptc_profile != (
StringInfo *) NULL)
00514 {
00515
ConcatenateStringInfo(iptc_profile,profile);
00516 profile=
DestroyStringInfo(profile);
00517 }
00518
else
00519 {
00520 status=
SetImageProfile(image,
"iptc",profile);
00521 profile=
DestroyStringInfo(profile);
00522
if (status ==
MagickFalse)
00523
ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
00524 image->
filename);
00525 }
00526
if (image->
debug !=
MagickFalse)
00527 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
00528
"Profile: iptc, %lu bytes",(
unsigned long) length);
00529
return(
MagickTrue);
00530 }
00531
00532
static boolean ReadProfile(j_decompress_ptr jpeg_info)
00533 {
00534
char
00535
name[
MaxTextExtent];
00536
00537 ErrorManager
00538 *error_manager;
00539
00540
Image
00541 *image;
00542
00543
int
00544 marker;
00545
00546
MagickBooleanType
00547 status;
00548
00549
register long
00550 i;
00551
00552
register unsigned char
00553 *p;
00554
00555 size_t
00556 length;
00557
00558
StringInfo
00559 *profile;
00560
00561
00562
00563
00564 length=(size_t) ((
unsigned long) GetCharacter(jpeg_info) << 8);
00565 length+=(size_t) GetCharacter(jpeg_info);
00566
if (length <= 2)
00567
return(
MagickTrue);
00568 length-=2;
00569 marker=jpeg_info->unread_marker-JPEG_APP0;
00570 error_manager=(ErrorManager *) jpeg_info->client_data;
00571 image=error_manager->image;
00572 (
void)
FormatMagickString(name,MaxTextExtent,
"APP%d",marker);
00573 profile=
AcquireStringInfo(length);
00574
if (profile == (
StringInfo *) NULL)
00575
ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
00576 image->
filename);
00577 p=profile->
datum;
00578
for (i=(
long) profile->
length-1; i >= 0; i--)
00579 *p++=(
unsigned char) GetCharacter(jpeg_info);
00580
if (marker == 1)
00581 {
00582 p=profile->
datum;
00583
if ((length > 4) && (
LocaleNCompare((
char *) p,
"exif",4) == 0))
00584 (
void)
CopyMagickString(name,
"exif",MaxTextExtent);
00585
if ((length > 5) && (
LocaleNCompare((
char *) p,
"http:",5) == 0))
00586 (
void)
CopyMagickString(name,
"xmp",MaxTextExtent);
00587 }
00588 status=
SetImageProfile(image,name,profile);
00589 profile=
DestroyStringInfo(profile);
00590
if (status ==
MagickFalse)
00591
ThrowBinaryException(ResourceLimitError,
"MemoryAllocationFailed",
00592 image->
filename);
00593
if (image->
debug !=
MagickFalse)
00594 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
00595
"Profile: %s, %lu bytes",name,(
unsigned long) length);
00596
return(
MagickTrue);
00597 }
00598
00599
static void SkipInputData(j_decompress_ptr cinfo,
long number_bytes)
00600 {
00601 SourceManager
00602 *source;
00603
00604
if (number_bytes <= 0)
00605
return;
00606 source=(SourceManager *) cinfo->src;
00607
while (number_bytes > (
long) source->manager.bytes_in_buffer)
00608 {
00609 number_bytes-=(
long) source->manager.bytes_in_buffer;
00610 (
void) FillInputBuffer(cinfo);
00611 }
00612 source->manager.next_input_byte+=(size_t) number_bytes;
00613 source->manager.bytes_in_buffer-=(size_t) number_bytes;
00614 }
00615
00616
static void TerminateSource(j_decompress_ptr cinfo)
00617 {
00618 cinfo=cinfo;
00619 }
00620
00621
static void JPEGSourceManager(j_decompress_ptr cinfo,
Image *image)
00622 {
00623 SourceManager
00624 *source;
00625
00626 cinfo->src=(
struct jpeg_source_mgr *) (*cinfo->mem->alloc_small)
00627 ((j_common_ptr) cinfo,JPOOL_IMAGE,
sizeof(SourceManager));
00628 source=(SourceManager *) cinfo->src;
00629 source->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
00630 ((j_common_ptr) cinfo,JPOOL_IMAGE,
MaxBufferExtent*
sizeof(JOCTET));
00631 source=(SourceManager *) cinfo->src;
00632 source->manager.init_source=InitializeSource;
00633 source->manager.fill_input_buffer=FillInputBuffer;
00634 source->manager.skip_input_data=SkipInputData;
00635 source->manager.resync_to_restart=jpeg_resync_to_restart;
00636 source->manager.term_source=TerminateSource;
00637 source->manager.bytes_in_buffer=0;
00638 source->manager.next_input_byte=NULL;
00639 source->image=image;
00640 }
00641
00642
static Image *ReadJPEGImage(
const ImageInfo *image_info,
00643
ExceptionInfo *
exception)
00644 {
00645
char
00646 sampling_factors[
MaxTextExtent],
00647 value[
MaxTextExtent];
00648
00649 ErrorManager
00650 error_manager;
00651
00652
Image
00653 *image;
00654
00655
long
00656 x,
00657 y;
00658
00659 JSAMPLE
00660 *jpeg_pixels;
00661
00662 JSAMPROW
00663 scanline[1];
00664
00665
MagickBooleanType
00666 debug,
00667 status;
00668
00669
register IndexPacket
00670 *indexes;
00671
00672
register long
00673 i;
00674
00675
struct jpeg_decompress_struct
00676 jpeg_info;
00677
00678
struct jpeg_error_mgr
00679 jpeg_error;
00680
00681
register JSAMPLE
00682 *p;
00683
00684
register PixelPacket
00685 *q;
00686
00687
unsigned long
00688 index,
00689 number_pixels,
00690 units;
00691
00692
00693
00694
00695
assert(image_info != (
const ImageInfo *) NULL);
00696
assert(image_info->
signature == MagickSignature);
00697
if (image_info->
debug !=
MagickFalse)
00698 (
void)
LogMagickEvent(TraceEvent,
GetMagickModule(),image_info->
filename);
00699
assert(exception != (
ExceptionInfo *) NULL);
00700
assert(exception->
signature == MagickSignature);
00701 debug=
IsEventLogging();
00702 image=
AllocateImage(image_info);
00703 status=
OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
00704
if (status ==
MagickFalse)
00705 {
00706
DestroyImageList(image);
00707
return((
Image *) NULL);
00708 }
00709
00710
00711
00712 jpeg_info.err=jpeg_std_error(&jpeg_error);
00713 jpeg_info.err->emit_message=(void (*)(j_common_ptr,
int)) EmitMessage;
00714 jpeg_info.err->error_exit=(void (*)(j_common_ptr)) JPEGErrorHandler;
00715 jpeg_pixels=(JSAMPLE *) NULL;
00716 error_manager.image=image;
00717
if (setjmp(error_manager.error_recovery) != 0)
00718 {
00719 jpeg_destroy_decompress(&jpeg_info);
00720
InheritException(exception,&image->
exception);
00721
CloseBlob(image);
00722 number_pixels=image->
columns*image->
rows;
00723
if (number_pixels != 0)
00724
return(
GetFirstImageInList(image));
00725 image=
DestroyImage(image);
00726
return(image);
00727 }
00728 jpeg_info.client_data=(
void *) &error_manager;
00729 jpeg_create_decompress(&jpeg_info);
00730 JPEGSourceManager(&jpeg_info,image);
00731 jpeg_set_marker_processor(&jpeg_info,JPEG_COM,ReadComment);
00732 jpeg_set_marker_processor(&jpeg_info,ICC_MARKER,ReadICCProfile);
00733 jpeg_set_marker_processor(&jpeg_info,IPTC_MARKER,ReadIPTCProfile);
00734
for (i=1; i < 16; i++)
00735
if ((i != 2) && (i != 13) && (i != 14))
00736 jpeg_set_marker_processor(&jpeg_info,(
int) i+JPEG_APP0,ReadProfile);
00737 i=jpeg_read_header(&jpeg_info,MagickTrue);
00738
if (jpeg_info.out_color_space == JCS_CMYK)
00739 image->
colorspace=
CMYKColorspace;
00740
00741
00742
00743 units=0;
00744
if ((jpeg_info.saw_JFIF_marker != 0) && (jpeg_info.X_density != 1U) &&
00745 (jpeg_info.Y_density != 1U))
00746 {
00747 image->
x_resolution=(
double) jpeg_info.X_density;
00748 image->
y_resolution=(
double) jpeg_info.Y_density;
00749 units=(
unsigned long) jpeg_info.density_unit;
00750 }
00751
if (units == 1)
00752 image->
units=
PixelsPerInchResolution;
00753
if (units == 2)
00754 image->
units=
PixelsPerCentimeterResolution;
00755 number_pixels=image->
columns*image->
rows;
00756
if (number_pixels != 0)
00757 {
00758
double
00759 scale_factor;
00760
00761
00762
00763
00764 jpeg_calc_output_dimensions(&jpeg_info);
00765 image->
magick_columns=jpeg_info.output_width;
00766 image->
magick_rows=jpeg_info.output_height;
00767 scale_factor=(
double) jpeg_info.output_width/image->
columns;
00768
if (scale_factor > ((
double) jpeg_info.output_height/image->
rows))
00769 scale_factor=(
double) jpeg_info.output_height/image->
rows;
00770 jpeg_info.scale_denom=(
unsigned int) scale_factor;
00771 jpeg_calc_output_dimensions(&jpeg_info);
00772
if (image->
debug !=
MagickFalse)
00773 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
"Scale factor: %ld",
00774 (
long) scale_factor);
00775 }
00776
if (image_info->
subrange != 0)
00777 {
00778 jpeg_info.scale_denom=(
unsigned int) image_info->
subrange;
00779 jpeg_calc_output_dimensions(&jpeg_info);
00780 }
00781
#if (JPEG_LIB_VERSION >= 61) && defined(D_PROGRESSIVE_SUPPORTED)
00782
#ifdef D_LOSSLESS_SUPPORTED
00783
image->
interlace=
00784 jpeg_info.process == JPROC_PROGRESSIVE ?
PlaneInterlace :
NoInterlace;
00785 image->
compression=jpeg_info.process == JPROC_LOSSLESS ?
00786
LosslessJPEGCompression :
JPEGCompression;
00787
if (jpeg_info.data_precision > 8)
00788 (
void)
ThrowMagickException(exception,
GetMagickModule(),OptionError,
00789
"12-bit JPEG not supported. Reducing pixel data to 8 bits",
00790 image->
filename);
00791
#else
00792
image->
interlace=jpeg_info.progressive_mode != 0 ?
PlaneInterlace :
00793
NoInterlace;
00794 image->
compression=
JPEGCompression;
00795
#endif
00796
#else
00797
image->
compression=
JPEGCompression;
00798 image->
interlace=
PlaneInterlace;
00799
#endif
00800
if ((image_info->
colors != 0) && (image_info->
colors <= 256))
00801 {
00802
00803
00804
00805 jpeg_info.quantize_colors=
MagickTrue;
00806 jpeg_info.desired_number_of_colors=(
int) image_info->
colors;
00807
if (
AllocateImageColormap(image,image_info->
colors) ==
MagickFalse)
00808
ThrowReaderException(ResourceLimitError,
"MemoryAllocationFailed");
00809 }
00810 (
void) jpeg_start_decompress(&jpeg_info);
00811 image->
columns=jpeg_info.output_width;
00812 image->
rows=jpeg_info.output_height;
00813 image->
depth=(
unsigned long) jpeg_info.data_precision;
00814
if ((jpeg_info.output_components == 1) &&
00815 (jpeg_info.quantize_colors ==
MagickFalse))
00816 {
00817
if (
AllocateImageColormap(image,1UL << image->
depth) ==
MagickFalse)
00818
ThrowReaderException(ResourceLimitError,
"MemoryAllocationFailed");
00819 }
00820
if (image->
debug !=
MagickFalse)
00821 {
00822
if (image->
interlace ==
PlaneInterlace)
00823 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
00824
"Interlace: progressive");
00825
else
00826 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
00827
"Interlace: nonprogressive");
00828 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
"Data precision: %d",
00829 (
int) jpeg_info.data_precision);
00830 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
"Geometry: %dx%d",
00831 (
int) jpeg_info.output_width,(
int) jpeg_info.output_height);
00832 }
00833 image->
quality=0;
00834
#ifdef D_LOSSLESS_SUPPORTED
00835
if (image->
compression ==
LosslessJPEGCompression)
00836 {
00837 image->
quality=100;
00838 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
00839
"Quality: 100 (lossless)");
00840 }
00841
else
00842
#endif
00843
{
00844
int
00845 hashval,
00846 sum;
00847
00848
00849
00850
00851 sum=0;
00852
for (i=0; i < NUM_QUANT_TBLS; i++)
00853 {
00854
int
00855 j;
00856
00857
if (jpeg_info.quant_tbl_ptrs[i] != NULL)
00858
for (j=0; j < DCTSIZE2; j++)
00859 {
00860 UINT16
00861 *c;
00862
00863 c=jpeg_info.quant_tbl_ptrs[i]->quantval;
00864 sum+=c[j];
00865 }
00866 }
00867
if ((jpeg_info.quant_tbl_ptrs[0] != NULL) &&
00868 (jpeg_info.quant_tbl_ptrs[1] != NULL))
00869 {
00870
int
00871 hash[]=
00872 { 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645,
00873 632, 623, 613, 607, 600, 594, 589, 585, 581, 571,
00874 555, 542, 529, 514, 494, 474, 457, 439, 424, 410,
00875 397, 386, 373, 364, 351, 341, 334, 324, 317, 309,
00876 299, 294, 287, 279, 274, 267, 262, 257, 251, 247,
00877 243, 237, 232, 227, 222, 217, 213, 207, 202, 198,
00878 192, 188, 183, 177, 173, 168, 163, 157, 153, 148,
00879 143, 139, 132, 128, 125, 119, 115, 108, 104, 99,
00880 94, 90, 84, 79, 74, 70, 64, 59, 55, 49,
00881 45, 40, 34, 30, 25, 20, 15, 11, 6, 4,
00882 0
00883 },
00884 sums[]=
00885 { 32640,32635,32266,31495,30665,29804,29146,28599,28104,27670,
00886 27225,26725,26210,25716,25240,24789,24373,23946,23572,22846,
00887 21801,20842,19949,19121,18386,17651,16998,16349,15800,15247,
00888 14783,14321,13859,13535,13081,12702,12423,12056,11779,11513,
00889 11135,10955,10676,10392,10208, 9928, 9747, 9564, 9369, 9193,
00890 9017, 8822, 8639, 8458, 8270, 8084, 7896, 7710, 7527, 7347,
00891 7156, 6977, 6788, 6607, 6422, 6236, 6054, 5867, 5684, 5495,
00892 5305, 5128, 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698,
00893 3509, 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846,
00894 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201, 128,
00895 0
00896 };
00897
00898 hashval=(
int) (jpeg_info.quant_tbl_ptrs[0]->quantval[2]+
00899 jpeg_info.quant_tbl_ptrs[0]->quantval[53]+
00900 jpeg_info.quant_tbl_ptrs[1]->quantval[0]+
00901 jpeg_info.quant_tbl_ptrs[1]->quantval[DCTSIZE2-1]);
00902
for (i=0; i < 100; i++)
00903 {
00904
if ((hashval >= hash[i]) || (sum >= sums[i]))
00905 {
00906 image->
quality=(
unsigned long) i+1;
00907
if (image->
debug !=
MagickFalse)
00908 {
00909
if ((hashval > hash[i]) || (sum > sums[i]))
00910 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
00911
"Quality: %ld (approximate)",image->
quality);
00912
else
00913 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
00914
"Quality: %ld",image->
quality);
00915 }
00916
break;
00917 }
00918 }
00919 }
00920
else
00921
if (jpeg_info.quant_tbl_ptrs[0] != NULL)
00922 {
00923
int
00924 bwhash[]=
00925 { 510, 505, 422, 380, 355, 338, 326, 318, 311, 305,
00926 300, 297, 293, 291, 288, 286, 284, 283, 281, 280,
00927 279, 278, 277, 273, 262, 251, 243, 233, 225, 218,
00928 211, 205, 198, 193, 186, 181, 177, 172, 168, 164,
00929 158, 156, 152, 148, 145, 142, 139, 136, 133, 131,
00930 129, 126, 123, 120, 118, 115, 113, 110, 107, 105,
00931 102, 100, 97, 94, 92, 89, 87, 83, 81, 79,
00932 76, 74, 70, 68, 66, 63, 61, 57, 55, 52,
00933 50, 48, 44, 42, 39, 37, 34, 31, 29, 26,
00934 24, 21, 18, 16, 13, 11, 8, 6, 3, 2,
00935 0
00936 },
00937 bwsum[]=
00938 { 16320,16315,15946,15277,14655,14073,13623,13230,12859,12560,
00939 12240,11861,11456,11081,10714,10360,10027, 9679, 9368, 9056,
00940 8680, 8331, 7995, 7668, 7376, 7084, 6823, 6562, 6345, 6125,
00941 5939, 5756, 5571, 5421, 5240, 5086, 4976, 4829, 4719, 4616,
00942 4463, 4393, 4280, 4166, 4092, 3980, 3909, 3835, 3755, 3688,
00943 3621, 3541, 3467, 3396, 3323, 3247, 3170, 3096, 3021, 2952,
00944 2874, 2804, 2727, 2657, 2583, 2509, 2437, 2362, 2290, 2211,
00945 2136, 2068, 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477,
00946 1398, 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736,
00947 667, 592, 518, 441, 369, 292, 221, 151, 86, 64,
00948 0
00949 };
00950
00951 hashval=(
int) (jpeg_info.quant_tbl_ptrs[0]->quantval[2]+
00952 jpeg_info.quant_tbl_ptrs[0]->quantval[53]);
00953
for (i=0; i < 100; i++)
00954 {
00955
if ((hashval >= bwhash[i]) || (sum >= bwsum[i]))
00956 {
00957 image->
quality=(
unsigned long) i+1;
00958
if (image->
debug !=
MagickFalse)
00959 {
00960
if ((hashval > bwhash[i]) || (sum > bwsum[i]))
00961 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
00962
"Quality: %ld (approximate)",i+1);
00963
else
00964 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
00965
"Quality: %ld",i+1);
00966 }
00967
break;
00968 }
00969 }
00970 }
00971 }
00972 (
void)
FormatMagickString(value,MaxTextExtent,
"%ld",(
long)
00973 jpeg_info.out_color_space);
00974 (
void)
SetImageAttribute(image,
"JPEG-Colorspace",value);
00975
00976
00977
00978
switch (jpeg_info.out_color_space)
00979 {
00980
case JCS_CMYK:
00981 {
00982 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
"Colorspace: CMYK");
00983 (
void)
FormatMagickString(sampling_factors,MaxTextExtent,
00984
"%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info.comp_info[0].h_samp_factor,
00985 jpeg_info.comp_info[0].v_samp_factor,
00986 jpeg_info.comp_info[1].h_samp_factor,
00987 jpeg_info.comp_info[1].v_samp_factor,
00988 jpeg_info.comp_info[2].h_samp_factor,
00989 jpeg_info.comp_info[2].v_samp_factor,
00990 jpeg_info.comp_info[3].h_samp_factor,
00991 jpeg_info.comp_info[3].v_samp_factor);
00992
break;
00993 }
00994
case JCS_GRAYSCALE:
00995 {
00996 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
00997
"Colorspace: GRAYSCALE");
00998 (
void)
FormatMagickString(sampling_factors,MaxTextExtent,
"%dx%d",
00999 jpeg_info.comp_info[0].h_samp_factor,
01000 jpeg_info.comp_info[0].v_samp_factor);
01001
break;
01002 }
01003
case JCS_RGB:
01004 {
01005 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
"Colorspace: RGB");
01006 (
void)
FormatMagickString(sampling_factors,MaxTextExtent,
01007
"%dx%d,%dx%d,%dx%d",jpeg_info.comp_info[0].h_samp_factor,
01008 jpeg_info.comp_info[0].v_samp_factor,
01009 jpeg_info.comp_info[1].h_samp_factor,
01010 jpeg_info.comp_info[1].v_samp_factor,
01011 jpeg_info.comp_info[2].h_samp_factor,
01012 jpeg_info.comp_info[2].v_samp_factor);
01013
break;
01014 }
01015
default:
01016 {
01017 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
"Colorspace: %d",
01018 jpeg_info.out_color_space);
01019 (
void)
FormatMagickString(sampling_factors,MaxTextExtent,
01020
"%dx%d,%dx%d,%dx%d,%dx%d",jpeg_info.comp_info[0].h_samp_factor,
01021 jpeg_info.comp_info[0].v_samp_factor,
01022 jpeg_info.comp_info[1].h_samp_factor,
01023 jpeg_info.comp_info[1].v_samp_factor,
01024 jpeg_info.comp_info[2].h_samp_factor,
01025 jpeg_info.comp_info[2].v_samp_factor,
01026 jpeg_info.comp_info[3].h_samp_factor,
01027 jpeg_info.comp_info[3].v_samp_factor);
01028
break;
01029 }
01030 }
01031 (
void)
SetImageAttribute(image,
"JPEG-Sampling-factors",sampling_factors);
01032 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
01033
"Sampling Factors: %s",sampling_factors);
01034
if (image_info->
ping !=
MagickFalse)
01035 {
01036 jpeg_destroy_decompress(&jpeg_info);
01037
CloseBlob(image);
01038
return(
GetFirstImageInList(image));
01039 }
01040 jpeg_pixels=(JSAMPLE *)
AcquireMagickMemory((size_t)
01041 jpeg_info.output_components*image->
columns*
sizeof(JSAMPLE));
01042
if (jpeg_pixels == (JSAMPLE *) NULL)
01043
ThrowReaderException(ResourceLimitError,
"MemoryAllocationFailed");
01044
01045
01046
01047
if (setjmp(error_manager.error_recovery) != 0)
01048 {
01049 jpeg_pixels=(
unsigned char *)
RelinquishMagickMemory(jpeg_pixels);
01050 jpeg_destroy_decompress(&jpeg_info);
01051
InheritException(exception,&image->
exception);
01052
CloseBlob(image);
01053 number_pixels=image->
columns*image->
rows;
01054
if (number_pixels != 0)
01055
return(
GetFirstImageInList(image));
01056 image=
DestroyImage(image);
01057
return(image);
01058 }
01059 scanline[0]=(JSAMPROW) jpeg_pixels;
01060
for (y=0; y < (
long) image->
rows; y++)
01061 {
01062 (
void) jpeg_read_scanlines(&jpeg_info,scanline,1);
01063 p=jpeg_pixels;
01064 q=
SetImagePixels(image,0,y,image->
columns,1);
01065
if (q == (
PixelPacket *) NULL)
01066
break;
01067 indexes=
GetIndexes(image);
01068
if (jpeg_info.data_precision > 8)
01069 {
01070
if (jpeg_info.output_components == 1)
01071
for (x=0; x < (
long) image->
columns; x++)
01072 {
01073 index=
ConstrainColormapIndex(image,(
unsigned long)
01074 (16*GETJSAMPLE(*p)));
01075 indexes[x]=(
IndexPacket) index;
01076 *q++=image->
colormap[index];
01077 p++;
01078 }
01079
else
01080
for (x=0; x < (
long) image->
columns; x++)
01081 {
01082 q->
red=
ScaleShortToQuantum(16*GETJSAMPLE(*p++));
01083 q->
green=
ScaleShortToQuantum(16*GETJSAMPLE(*p++));
01084 q->
blue=
ScaleShortToQuantum(16*GETJSAMPLE(*p++));
01085
if (image->
colorspace ==
CMYKColorspace)
01086 indexes[x]=
ScaleShortToQuantum(16*GETJSAMPLE(*p++));
01087 q++;
01088 }
01089 }
01090
else
01091
if (jpeg_info.output_components == 1)
01092
for (x=0; x < (
long) image->
columns; x++)
01093 {
01094 index=
ConstrainColormapIndex(image,(
unsigned long) GETJSAMPLE(*p));
01095 indexes[x]=(
IndexPacket) index;
01096 *q++=image->
colormap[index];
01097 p++;
01098 }
01099
else
01100
for (x=0; x < (
long) image->
columns; x++)
01101 {
01102 q->
red=
ScaleCharToQuantum(GETJSAMPLE(*p++));
01103 q->
green=
ScaleCharToQuantum(GETJSAMPLE(*p++));
01104 q->
blue=
ScaleCharToQuantum(GETJSAMPLE(*p++));
01105
if (image->
colorspace ==
CMYKColorspace)
01106 indexes[x]=
ScaleCharToQuantum(GETJSAMPLE(*p++));
01107 q++;
01108 }
01109
if (
SyncImagePixels(image) ==
MagickFalse)
01110
break;
01111
if ((image->
progress_monitor != (
MagickProgressMonitor) NULL) &&
01112 (
QuantumTick(y,image->
rows) !=
MagickFalse))
01113 {
01114 status=image->
progress_monitor(LoadImageTag,y,image->
rows,
01115 image->
client_data);
01116
if (status ==
MagickFalse)
01117
break;
01118 }
01119 }
01120
if (jpeg_info.quantize_colors !=
MagickFalse)
01121
for (i=0; i < jpeg_info.actual_number_of_colors; i++)
01122 {
01123 image->
colormap[i].
red=
ScaleCharToQuantum(jpeg_info.colormap[0][i]);
01124 image->
colormap[i].
green=image->
colormap[i].
red;
01125 image->
colormap[i].
blue=image->
colormap[i].
red;
01126
if (jpeg_info.out_color_space != JCS_GRAYSCALE)
01127 {
01128 image->
colormap[i].
green=
ScaleCharToQuantum(jpeg_info.colormap[1][i]);
01129 image->
colormap[i].
blue=
ScaleCharToQuantum(jpeg_info.colormap[2][i]);
01130 }
01131 }
01132
if (image->
colorspace ==
CMYKColorspace)
01133 {
01134
01135
01136
01137
for (y=0; y < (
long) image->
rows; y++)
01138 {
01139 q=
GetImagePixels(image,0,y,image->
columns,1);
01140
if (q == (
PixelPacket *) NULL)
01141
break;
01142 indexes=
GetIndexes(image);
01143
for (x=0; x < (
long) image->
columns; x++)
01144 {
01145 q->
red=(
Quantum) (
MaxRGB-q->
red);
01146 q->
green=(
Quantum) (
MaxRGB-q->
green);
01147 q->
blue=(
Quantum) (
MaxRGB-q->
blue);
01148 indexes[x]=(
IndexPacket) (
MaxRGB-indexes[x]);
01149 q++;
01150 }
01151
if (
SyncImagePixels(image) ==
MagickFalse)
01152
break;
01153 }
01154 }
01155
01156
01157
01158 (
void) jpeg_finish_decompress(&jpeg_info);
01159 jpeg_destroy_decompress(&jpeg_info);
01160 jpeg_pixels=(
unsigned char *)
RelinquishMagickMemory(jpeg_pixels);
01161
CloseBlob(image);
01162
InheritException(exception,&image->
exception);
01163
return(
GetFirstImageInList(image));
01164 }
01165
#endif
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190 ModuleExport void RegisterJPEGImage(
void)
01191 {
01192
MagickInfo
01193 *entry;
01194
01195 entry=
SetMagickInfo(
"JPEG");
01196 entry->
thread_support=
MagickFalse;
01197
#if defined(HasJPEG)
01198
entry->
decoder=(
DecoderHandler *) ReadJPEGImage;
01199 entry->
encoder=(
EncoderHandler *) WriteJPEGImage;
01200
#endif
01201
entry->
magick=(
MagickHandler *)
IsJPEG;
01202 entry->
adjoin=
MagickFalse;
01203 entry->
description=
01204
AcquireString(
"Joint Photographic Experts Group JFIF format");
01205
#if defined(JPEG_LIB_VERSION)
01206
{
01207
char
01208 version[
MaxTextExtent];
01209
01210 (
void)
FormatMagickString(version,
MaxTextExtent,
"%d",JPEG_LIB_VERSION);
01211 entry->
version=
AcquireString(version);
01212 }
01213
#endif
01214
entry->
module=
AcquireString(
"JPEG");
01215 (
void)
RegisterMagickInfo(entry);
01216 entry=
SetMagickInfo(
"JPG");
01217 entry->
thread_support=
MagickFalse;
01218
#if defined(HasJPEG)
01219
entry->
decoder=(
DecoderHandler *) ReadJPEGImage;
01220 entry->
encoder=(
EncoderHandler *) WriteJPEGImage;
01221
#endif
01222
entry->
adjoin=
MagickFalse;
01223 entry->
description=
01224
AcquireString(
"Joint Photographic Experts Group JFIF format");
01225 entry->
module=
AcquireString(
"JPEG");
01226 (
void)
RegisterMagickInfo(entry);
01227 entry=
SetMagickInfo(
"PJPEG");
01228 entry->
thread_support=
MagickFalse;
01229
#if defined(HasJPEG)
01230
entry->
decoder=(
DecoderHandler *) ReadJPEGImage;
01231 entry->
encoder=(
EncoderHandler *) WriteJPEGImage;
01232
#endif
01233
entry->
adjoin=
MagickFalse;
01234 entry->
description=
01235
AcquireString(
"Progessive Joint Photographic Experts Group JFIF");
01236 entry->
module=
AcquireString(
"JPEG");
01237 (
void)
RegisterMagickInfo(entry);
01238 }
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259 ModuleExport void UnregisterJPEGImage(
void)
01260 {
01261 (
void)
UnregisterMagickInfo(
"JPEG");
01262 (
void)
UnregisterMagickInfo(
"JPG");
01263 }
01264
01265
#if defined(HasJPEG)
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
static boolean EmptyOutputBuffer(j_compress_ptr cinfo)
01295 {
01296 DestinationManager
01297 *destination;
01298
01299 destination=(DestinationManager *) cinfo->dest;
01300 destination->manager.free_in_buffer=(size_t)
WriteBlob(destination->image,
01301 MaxBufferExtent,destination->buffer);
01302
if (destination->manager.free_in_buffer !=
MaxBufferExtent)
01303 ERREXIT(cinfo,JERR_FILE_WRITE);
01304 destination->manager.next_output_byte=destination->buffer;
01305
return(TRUE);
01306 }
01307
01308
static void InitializeDestination(j_compress_ptr cinfo)
01309 {
01310 DestinationManager
01311 *destination;
01312
01313 destination=(DestinationManager *) cinfo->dest;
01314 destination->buffer=(JOCTET *) (*cinfo->mem->alloc_small)
01315 ((j_common_ptr) cinfo,JPOOL_IMAGE,
MaxBufferExtent*
sizeof(JOCTET));
01316 destination->manager.next_output_byte=destination->buffer;
01317 destination->manager.free_in_buffer=
MaxBufferExtent;
01318 }
01319
01320
static MagickBooleanType JPEGWarningHandler(j_common_ptr jpeg_info,
int level)
01321 {
01322
char
01323 message[JMSG_LENGTH_MAX];
01324
01325
Image
01326 *image;
01327
01328 (jpeg_info->err->format_message)(jpeg_info,message);
01329 image=(
Image *) jpeg_info->
client_data;
01330
if (level < 0)
01331 {
01332
if ((jpeg_info->err->num_warnings == 0) ||
01333 (jpeg_info->err->trace_level >= 3))
01334
ThrowBinaryException(CorruptImageWarning,(
char *) message,
01335 image->
filename);
01336 jpeg_info->err->num_warnings++;
01337 }
01338
else
01339
if (jpeg_info->err->trace_level >= level)
01340
ThrowBinaryException(CoderError,(
char *) message,image->
filename);
01341
return(
MagickTrue);
01342 }
01343
01344
static void TerminateDestination(j_compress_ptr cinfo)
01345 {
01346 DestinationManager
01347 *destination;
01348
01349 destination=(DestinationManager *) cinfo->dest;
01350
if ((
MaxBufferExtent-(
int) destination->manager.free_in_buffer) > 0)
01351 {
01352
ssize_t
01353 count;
01354
01355 count=
WriteBlob(destination->image,MaxBufferExtent-
01356 destination->manager.free_in_buffer,destination->buffer);
01357
if (count != (
ssize_t)
01358 (
MaxBufferExtent-destination->manager.free_in_buffer))
01359 ERREXIT(cinfo,JERR_FILE_WRITE);
01360 }
01361
if (
SyncBlob(destination->image) !=
MagickFalse)
01362 ERREXIT(cinfo,JERR_FILE_WRITE);
01363 }
01364
01365
static void WriteProfile(j_compress_ptr jpeg_info,
Image *image)
01366 {
01367
const char
01368 *
name;
01369
01370
const StringInfo
01371 *profile;
01372
01373
register long
01374 i;
01375
01376 size_t
01377 length;
01378
01379
StringInfo
01380 *custom_profile;
01381
01382
unsigned long
01383 tag_length;
01384
01385
01386
01387
01388 custom_profile=
AcquireStringInfo(65535L);
01389
ResetImageProfileIterator(image);
01390
for (
name=
GetNextImageProfile(image);
name != (
const char *) NULL; )
01391 {
01392 profile=
GetImageProfile(image,name);
01393
if ((
LocaleCompare(name,
"EXIF") == 0) || (
LocaleCompare(name,
"XMP") == 0))
01394
for (i=0; i < (
long) profile->
length; i+=65533L)
01395 {
01396 length=
Min(profile->
length-i,65533L);
01397 jpeg_write_marker(jpeg_info,XML_MARKER,profile->
datum+i,
01398 (
unsigned int) length);
01399 }
01400
if (
LocaleCompare(name,
"ICC") == 0)
01401 {
01402 tag_length=14;
01403 (
void)
CopyMagickMemory(custom_profile->
datum,ICC_PROFILE,tag_length);
01404
for (i=0; i < (
long) profile->
length; i+=65519L)
01405 {
01406 length=
Min(profile->
length-i,65519L);
01407 custom_profile->
datum[12]=(
unsigned char) ((i/65519L)+1);
01408 custom_profile->
datum[13]=(
unsigned char) (profile->
length/65519L+1);
01409 (
void)
CopyMagickMemory(custom_profile->
datum+tag_length,
01410 profile->
datum+i,length);
01411 jpeg_write_marker(jpeg_info,ICC_MARKER,custom_profile->
datum,
01412 (
unsigned int) (length+tag_length));
01413 }
01414 }
01415
if (
LocaleCompare(name,
"IPTC") == 0)
01416 {
01417
unsigned long
01418 roundup;
01419
01420 tag_length=14;
01421 (
void)
CopyMagickMemory(custom_profile->
datum,
"Photoshop 3.0 ",
01422 tag_length);
01423 custom_profile->
datum[13]=0x00;
01424
for (i=0; i < (
long) profile->
length; i+=65500L)
01425 {
01426 length=
Min(profile->
length-i,65500L);
01427 roundup=(
unsigned long) (length & 0x01);
01428 (
void)
CopyMagickMemory(custom_profile->
datum+tag_length,
01429 profile->
datum+i,length);
01430
if (roundup != 0)
01431 custom_profile->
datum[length+tag_length]=
'\0';
01432 jpeg_write_marker(jpeg_info,IPTC_MARKER,custom_profile->
datum,
01433 (
unsigned int) (length+tag_length+roundup));
01434 }
01435 }
01436 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
01437
"%s profile: %lu bytes",name,(
unsigned long) profile->
length);
01438
name=
GetNextImageProfile(image);
01439 }
01440 custom_profile=
DestroyStringInfo(custom_profile);
01441 }
01442
01443
static void JPEGDestinationManager(j_compress_ptr cinfo,
Image * image)
01444 {
01445 DestinationManager
01446 *destination;
01447
01448 cinfo->dest=(
struct jpeg_destination_mgr *) (*cinfo->mem->alloc_small)
01449 ((j_common_ptr) cinfo,JPOOL_IMAGE,
sizeof(DestinationManager));
01450 destination=(DestinationManager *) cinfo->dest;
01451 destination->manager.init_destination=InitializeDestination;
01452 destination->manager.empty_output_buffer=EmptyOutputBuffer;
01453 destination->manager.term_destination=TerminateDestination;
01454 destination->image=image;
01455 }
01456
01457
static char **SamplingFactorToList(
const char *text)
01458 {
01459
char
01460 **textlist;
01461
01462
register char
01463 *q;
01464
01465
register const char
01466 *p;
01467
01468
register long
01469 i;
01470
01471
unsigned long
01472 lines;
01473
01474
if (text == (
char *) NULL)
01475
return((
char **) NULL);
01476
01477
01478
01479 lines=1;
01480
for (p=text; *p !=
'\0'; p++)
01481
if (*p ==
',')
01482 lines++;
01483 textlist=(
char **)
01484
AcquireMagickMemory(((size_t) lines+MaxTextExtent)*
sizeof(*textlist));
01485
if (textlist == (
char **) NULL)
01486
ThrowMagickFatalException(ResourceLimitFatalError,
"UnableToConvertText",
01487 text);
01488 p=text;
01489
for (i=0; i < (
long) lines; i++)
01490 {
01491
for (q=(
char *) p; *q !=
'\0'; q++)
01492
if (*q ==
',')
01493
break;
01494 textlist[i]=(
char *)
AcquireMagickMemory((size_t) (q-p)+MaxTextExtent);
01495
if (textlist[i] == (
char *) NULL)
01496
ThrowMagickFatalException(ResourceLimitFatalError,
"UnableToConvertText",
01497 text);
01498 (
void)
CopyMagickString(textlist[i],p,(size_t) (q-p+1));
01499
if (*q ==
'\r')
01500 q++;
01501 p=q+1;
01502 }
01503 textlist[i]=(
char *) NULL;
01504
return(textlist);
01505 }
01506
01507
static MagickBooleanType WriteJPEGImage(
const ImageInfo *image_info,
01508
Image *image)
01509 {
01510
char
01511 *sampling_factors;
01512
01513
const ImageAttribute
01514 *attribute;
01515
01516 JSAMPLE
01517 *jpeg_pixels;
01518
01519 JSAMPROW
01520 scanline[1];
01521
01522
long
01523 y;
01524
01525
MagickBooleanType
01526 status;
01527
01528
MagickSizeType
01529 number_pixels;
01530
01531
register const PixelPacket
01532 *p;
01533
01534
register IndexPacket
01535 *indexes;
01536
01537
register JSAMPLE
01538 *q;
01539
01540
register long
01541 i,
01542 x;
01543
01544
struct jpeg_compress_struct
01545 jpeg_info;
01546
01547
struct jpeg_error_mgr
01548 jpeg_error;
01549
01550
01551
01552
01553
assert(image_info != (
const ImageInfo *) NULL);
01554
assert(image_info->
signature == MagickSignature);
01555
assert(image != (
Image *) NULL);
01556
assert(image->
signature == MagickSignature);
01557
if (image->
debug !=
MagickFalse)
01558 (
void)
LogMagickEvent(TraceEvent,
GetMagickModule(),image->
filename);
01559 status=
OpenBlob(image_info,image,WriteBinaryBlobMode,&image->
exception);
01560
if (status ==
MagickFalse)
01561
return(status);
01562
01563
01564
01565 jpeg_info.client_data=(
void *) image;
01566 jpeg_info.err=jpeg_std_error(&jpeg_error);
01567 jpeg_info.err->emit_message=(void (*)(j_common_ptr,
int)) JPEGWarningHandler;
01568 jpeg_create_compress(&jpeg_info);
01569 JPEGDestinationManager(&jpeg_info,image);
01570 jpeg_info.image_width=(
unsigned int) image->
columns;
01571 jpeg_info.image_height=(
unsigned int) image->
rows;
01572 jpeg_info.input_components=3;
01573 jpeg_info.data_precision=(
int)
Min(image->
depth,BITS_IN_JSAMPLE);
01574 jpeg_info.in_color_space=JCS_RGB;
01575
switch (image_info->
colorspace)
01576 {
01577
case CMYKColorspace:
01578 {
01579 jpeg_info.input_components=4;
01580 jpeg_info.in_color_space=JCS_CMYK;
01581 (
void)
SetImageColorspace(image,CMYKColorspace);
01582
break;
01583 }
01584
case YCbCrColorspace:
01585 {
01586 jpeg_info.in_color_space=JCS_YCbCr;
01587 (
void)
SetImageColorspace(image,YCbCrColorspace);
01588
break;
01589 }
01590
case GRAYColorspace:
01591 {
01592 jpeg_info.in_color_space=JCS_GRAYSCALE;
01593
SetImageColorspace(image,GRAYColorspace);
01594
break;
01595 }
01596
default:
01597 {
01598
if (image->
colorspace ==
CMYKColorspace)
01599 {
01600 jpeg_info.input_components=4;
01601 jpeg_info.in_color_space=JCS_CMYK;
01602
break;
01603 }
01604
if (image->
colorspace ==
YCbCrColorspace)
01605 {
01606 jpeg_info.in_color_space=JCS_YCbCr;
01607
break;
01608 }
01609 (
void)
SetImageColorspace(image,RGBColorspace);
01610
break;
01611 }
01612 }
01613
if ((image_info->
type !=
TrueColorType) &&
01614 (
IsGrayImage(image,&image->
exception) !=
MagickFalse))
01615 {
01616 jpeg_info.input_components=1;
01617 jpeg_info.in_color_space=JCS_GRAYSCALE;
01618 }
01619 jpeg_set_defaults(&jpeg_info);
01620 jpeg_info.density_unit=(UINT8) 1;
01621
if (image->
debug !=
MagickFalse)
01622 (
void)
LogMagickEvent(CoderEvent,
GetMagickModule(),
01623
"Image resolution: %ld,%ld",(
long) (image->
x_resolution+0.5),
01624 (
long) (image->
y_resolution+0.5));
01625 if ((image->
x_resolution != 0.0) && (image->
y_resolution != 0.0))
01626 {
01627
01628
01629
01630 jpeg_info.write_JFIF_header=MagickTrue;
01631 jpeg_info.X_density=(UINT16) image->
x_resolution;
01632 jpeg_info.Y_density=(UINT16) image->
y_resolution;
01633 if (image->
units == PixelsPerInchResolution)
01634 jpeg_info.density_unit=(UINT8) 1;
01635 if (image->
units == PixelsPerCentimeterResolution)
01636 jpeg_info.density_unit=(UINT8) 2;
01637 }
01638 number_pixels=(
MagickSizeType) image->
columns*image->
rows;
01639
if (number_pixels == (
MagickSizeType) ((size_t) number_pixels))
01640 {
01641
01642
01643
01644 status=
AcquireMagickResource(AreaResource,number_pixels);
01645
if (status !=
MagickFalse)
01646 jpeg_info.optimize_coding=
MagickTrue;
01647
RelinquishMagickResource(AreaResource,number_pixels);
01648 }
01649
#if (JPEG_LIB_VERSION >= 61) && defined(C_PROGRESSIVE_SUPPORTED)
01650
if