% July 1992 %
% %
% %
-% Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization %
+% Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
#include "magick/log.h"
#include "magick/magick.h"
#include "magick/memory_.h"
+#include "magick/module.h"
#include "magick/monitor.h"
#include "magick/monitor-private.h"
#include "magick/option.h"
#include "magick/splay-tree.h"
#include "magick/static.h"
#include "magick/string_.h"
-#include "magick/module.h"
+#include "magick/string-private.h"
#include "magick/utility.h"
#include <setjmp.h>
#if defined(MAGICKCORE_JPEG_DELEGATE)
source->start_of_blob=TRUE;
}
+static MagickBooleanType IsITUFaxImage(const Image *image)
+{
+ const StringInfo
+ *profile;
+
+ const unsigned char
+ *datum;
+
+ profile=GetImageProfile(image,"8bim");
+ if (profile == (const StringInfo *) NULL)
+ return(MagickFalse);
+ if (GetStringInfoLength(profile) < 5)
+ return(MagickFalse);
+ datum=GetStringInfoDatum(profile);
+ if ((datum[0] == 0x47) && (datum[1] == 0x33) && (datum[2] == 0x46) &&
+ (datum[3] == 0x41) && (datum[4] == 0x58))
+ return(MagickTrue);
+ return(MagickFalse);
+}
+
static void JPEGErrorHandler(j_common_ptr jpeg_info)
{
ErrorManager
{
if ((qvalue < hash[i]) && (sum < sums[i]))
continue;
- if ((qvalue <= hash[i]) && (sum <= sums[i]))
+ if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
image->quality=(unsigned long) i+1;
if (image->debug != MagickFalse)
- {
- if (image->quality != UndefinedCompressionQuality)
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- "Quality: %ld",image->quality);
- else
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- "Quality: %ld (approximate)",i+1);
- }
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Quality: %ld (%s)",i+1,(qvalue <= hash[i]) &&
+ (sum <= sums[i]) ? "exact" : "approximate");
break;
}
}
{
if ((qvalue < hash[i]) && (sum < sums[i]))
continue;
- image->quality=(unsigned long) i+1;
+ if (((qvalue <= hash[i]) && (sum <= sums[i])) || (i >= 50))
+ image->quality=(unsigned long) i+1;
if (image->debug != MagickFalse)
- {
- if ((qvalue > hash[i]) || (sum > sums[i]))
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- "Quality: %ld (approximate)",i+1);
- else
- (void) LogMagickEvent(CoderEvent,GetMagickModule(),
- "Quality: %ld",i+1);
- }
+ (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+ "Quality: %ld (%s)",i+1,(qvalue <= hash[i]) &&
+ (sum <= sums[i]) ? "exact" : "approximate");
break;
}
}
jpeg_info->comp_info[2].v_samp_factor,
jpeg_info->comp_info[3].h_samp_factor,
jpeg_info->comp_info[3].v_samp_factor);
- break;
+ break;
}
case JCS_GRAYSCALE:
{
ErrorManager
error_manager;
- IndexPacket
- jindex;
-
Image
*image;
+ IndexPacket
+ index;
+
long
y;
if (setjmp(error_manager.error_recovery) != 0)
{
jpeg_destroy_decompress(&jpeg_info);
- InheritException(exception,&image->exception);
(void) CloseBlob(image);
number_pixels=(MagickSizeType) image->columns*image->rows;
if (number_pixels != 0)
return(GetFirstImageInList(image));
+ InheritException(exception,&image->exception);
return(DestroyImage(image));
}
jpeg_info.client_data=(void *) &error_manager;
(image_info->colorspace == Rec601YCbCrColorspace) ||
(image_info->colorspace == Rec709YCbCrColorspace))
jpeg_info.out_color_space=JCS_YCbCr;
+ if (IsITUFaxImage(image) != MagickFalse)
+ {
+ image->colorspace=LabColorspace;
+ jpeg_info.out_color_space=JCS_YCbCr;
+ }
+ else
+ if (jpeg_info.out_color_space == JCS_CMYK)
+ image->colorspace=CMYKColorspace;
/*
Set image resolution.
*/
GeometryInfo
geometry_info;
- int
+ MagickStatusType
flags;
/*
jpeg_info.quantize_colors=MagickTrue;
jpeg_info.desired_number_of_colors=(int) image_info->colors;
}
+ option=GetImageOption(image_info,"jpeg:block-smoothing");
+ if (option != (const char *) NULL)
+ {
+ jpeg_info.do_block_smoothing=MagickFalse;
+ if (IsMagickTrue(option) != MagickFalse)
+ jpeg_info.do_block_smoothing=MagickTrue;
+ }
+ option=GetImageOption(image_info,"jpeg:dct-method");
+ if (option != (const char *) NULL)
+ switch (*option)
+ {
+ case 'D':
+ case 'd':
+ {
+ if (LocaleCompare(option,"default") == 0)
+ jpeg_info.dct_method=JDCT_DEFAULT;
+ break;
+ }
+ case 'F':
+ case 'f':
+ {
+ if (LocaleCompare(option,"fastest") == 0)
+ jpeg_info.dct_method=JDCT_FASTEST;
+ if (LocaleCompare(option,"float") == 0)
+ jpeg_info.dct_method=JDCT_FLOAT;
+ break;
+ }
+ case 'I':
+ case 'i':
+ {
+ if (LocaleCompare(option,"ifast") == 0)
+ jpeg_info.dct_method=JDCT_IFAST;
+ if (LocaleCompare(option,"islow") == 0)
+ jpeg_info.dct_method=JDCT_ISLOW;
+ break;
+ }
+ }
+ option=GetImageOption(image_info,"jpeg:fancy-upsampling");
+ if (option != (const char *) NULL)
+ {
+ jpeg_info.do_fancy_upsampling=MagickFalse;
+ if (IsMagickTrue(option) != MagickFalse)
+ jpeg_info.do_fancy_upsampling=MagickTrue;
+ }
(void) jpeg_start_decompress(&jpeg_info);
image->columns=jpeg_info.output_width;
image->rows=jpeg_info.output_height;
if (jpeg_pixels != (unsigned char *) NULL)
jpeg_pixels=(unsigned char *) RelinquishMagickMemory(jpeg_pixels);
jpeg_destroy_decompress(&jpeg_info);
- InheritException(exception,&image->exception);
(void) CloseBlob(image);
number_pixels=(MagickSizeType) image->columns*image->rows;
if (number_pixels != 0)
for (y=0; y < (long) image->rows; y++)
{
register IndexPacket
- *__restrict indexes;
+ *restrict indexes;
register long
x;
register PixelPacket
- *__restrict q;
+ *restrict q;
if (jpeg_read_scanlines(&jpeg_info,scanline,1) != 1)
{
pixel=(unsigned long) GETJSAMPLE(*p);
else
pixel=(unsigned long) ((GETJSAMPLE(*p) ^ 0x80) << 4);
- jindex=ConstrainColormapIndex(image,pixel);
- indexes[x]=jindex;
- *q++=image->colormap[(int) jindex];
+ index=ConstrainColormapIndex(image,pixel);
+ indexes[x]=index;
+ *q++=image->colormap[(int) index];
p++;
}
else
(GETJSAMPLE(*p++) << 4));
q->blue=ScaleShortToQuantum((unsigned char)
(GETJSAMPLE(*p++) << 4));
- q->opacity=OpaqueOpacity;
+ SetOpacityPixelComponent(q,OpaqueOpacity);
q++;
}
else
(unsigned char) (GETJSAMPLE(*p++) << 4));
q->blue=(Quantum) QuantumRange-ScaleShortToQuantum((unsigned char)
(GETJSAMPLE(*p++) << 4));
- q->opacity=OpaqueOpacity;
+ SetOpacityPixelComponent(q,OpaqueOpacity);
indexes[x]=(IndexPacket) QuantumRange-ScaleShortToQuantum(
(unsigned char) (GETJSAMPLE(*p++) << 4));
q++;
if (jpeg_info.output_components == 1)
for (x=0; x < (long) image->columns; x++)
{
- jindex=ConstrainColormapIndex(image,(unsigned long) GETJSAMPLE(*p));
- indexes[x]=(IndexPacket) jindex;
- *q++=image->colormap[(int) jindex];
+ index=ConstrainColormapIndex(image,(unsigned long) GETJSAMPLE(*p));
+ indexes[x]=(IndexPacket) index;
+ *q++=image->colormap[(int) index];
p++;
}
else
q->red=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
q->green=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
q->blue=ScaleCharToQuantum((unsigned char) GETJSAMPLE(*p++));
- q->opacity=OpaqueOpacity;
+ SetOpacityPixelComponent(q,OpaqueOpacity);
q++;
}
else
GETJSAMPLE(*p++));
q->blue=(Quantum) QuantumRange-ScaleCharToQuantum((unsigned char)
GETJSAMPLE(*p++));
- q->opacity=OpaqueOpacity;
+ SetOpacityPixelComponent(q,OpaqueOpacity);
indexes[x]=(IndexPacket) QuantumRange-ScaleCharToQuantum(
(unsigned char) GETJSAMPLE(*p++));
q++;
break;
}
default:
+ {
+ if (image->colorspace != RGBColorspace)
+ (void) TransformImageColorspace(image,RGBColorspace);
break;
+ }
}
if ((image_info->type != TrueColorType) &&
(IsGrayImage(image,&image->exception) != MagickFalse))
(void) LogMagickEvent(CoderEvent,GetMagickModule(),
"Interlace: nonprogressive");
#endif
+ option=GetImageOption(image_info,"jpeg:extent");
+ if (option != (const char *) NULL)
+ {
+ Image
+ *jpeg_image;
+
+ ImageInfo
+ *jpeg_info;
+
+ jpeg_info=CloneImageInfo(image_info);
+ jpeg_image=CloneImage(image,0,0,MagickTrue,&image->exception);
+ if (jpeg_image != (Image *) NULL)
+ {
+ MagickSizeType
+ extent;
+
+ size_t
+ maximum,
+ minimum;
+
+ /*
+ Search for compression quality that does not exceed image extent.
+ */
+ jpeg_info->quality=0;
+ extent=(MagickSizeType) SiPrefixToDouble(option,100.0);
+ (void) DeleteImageOption(jpeg_info,"jpeg:extent");
+ (void) AcquireUniqueFilename(jpeg_image->filename);
+ maximum=101;
+ for (minimum=0; minimum != maximum; )
+ {
+ jpeg_image->quality=minimum+(maximum-minimum)/2;
+ status=WriteJPEGImage(jpeg_info,jpeg_image);
+ if (GetBlobSize(jpeg_image) <= extent)
+ minimum=jpeg_image->quality+1;
+ else
+ maximum=jpeg_image->quality-1;
+ }
+ (void) RelinquishUniqueFileResource(jpeg_image->filename);
+ image->quality=minimum-1;
+ jpeg_image=DestroyImage(jpeg_image);
+ }
+ jpeg_info=DestroyImageInfo(jpeg_info);
+ }
if ((image_info->compression != LosslessJPEGCompression) &&
(image->quality <= 100))
{
q=jpeg_pixels;
for (x=0; x < (long) image->columns; x++)
{
- *q++=(JSAMPLE) (ScaleQuantumToShort(p->red) >> 4);
- *q++=(JSAMPLE) (ScaleQuantumToShort(p->green) >> 4);
- *q++=(JSAMPLE) (ScaleQuantumToShort(p->blue) >> 4);
+ *q++=(JSAMPLE) (ScaleQuantumToShort(GetRedPixelComponent(p)) >> 4);
+ *q++=(JSAMPLE) (ScaleQuantumToShort(GetGreenPixelComponent(p)) >> 4);
+ *q++=(JSAMPLE) (ScaleQuantumToShort(GetBluePixelComponent(p)) >> 4);
p++;
}
(void) jpeg_write_scanlines(&jpeg_info,scanline,1);
/*
Convert DirectClass packets to contiguous CMYK scanlines.
*/
- *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->red) >> 4));
- *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->green) >> 4));
- *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(p->blue) >> 4));
+ *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(GetRedPixelComponent(p)) >> 4));
+ *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(GetGreenPixelComponent(p)) >> 4));
+ *q++=(JSAMPLE) (4095-(ScaleQuantumToShort(GetBluePixelComponent(p)) >> 4));
*q++=(JSAMPLE) (4095-(ScaleQuantumToShort(indexes[x]) >> 4));
p++;
}
q=jpeg_pixels;
for (x=0; x < (long) image->columns; x++)
{
- *q++=(JSAMPLE) ScaleQuantumToChar(p->red);
- *q++=(JSAMPLE) ScaleQuantumToChar(p->green);
- *q++=(JSAMPLE) ScaleQuantumToChar(p->blue);
+ *q++=(JSAMPLE) ScaleQuantumToChar(GetRedPixelComponent(p));
+ *q++=(JSAMPLE) ScaleQuantumToChar(GetGreenPixelComponent(p));
+ *q++=(JSAMPLE) ScaleQuantumToChar(GetBluePixelComponent(p));
p++;
}
(void) jpeg_write_scanlines(&jpeg_info,scanline,1);
Convert DirectClass packets to contiguous CMYK scanlines.
*/
*q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
- p->red)));
+ GetRedPixelComponent(p))));
*q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
- p->green)));
+ GetGreenPixelComponent(p))));
*q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
- p->blue)));
+ GetBluePixelComponent(p))));
*q++=(JSAMPLE) (ScaleQuantumToChar((Quantum) (QuantumRange-
indexes[x])));
p++;