Commit 0a81c953 authored by Mike Reed's avatar Mike Reed
Browse files

add optional preftable to image codecs, for more control over the resulting bitmap config

parent 95c58e02
......@@ -254,10 +254,14 @@ public:
Note, if you change this after startup, you'll need to flush the glyph
cache because it'll have the wrong type of masks cached.
*/
kNONE_LCDOrder means that the subpixel elements are not spatially
separated in any usable fashion.
*/
enum LCDOrder {
kRGB_LCDOrder = 0, //!< this is the default
kBGR_LCDOrder = 1,
kNONE_LCDOrder = 2,
};
static void SetSubpixelOrder(LCDOrder order);
......
......@@ -89,6 +89,33 @@ public:
Chooser* getChooser() const { return fChooser; }
Chooser* setChooser(Chooser*);
/** This optional table describes the caller's preferred config based on
information about the src data. For this table, the src attributes are
described in terms of depth (index (8), 16, 32/24) and if there is
per-pixel alpha. These inputs combine to create an index into the
pref[] table, which contains the caller's preferred config for that
input, or kNo_Config if there is no preference.
To specify no preferrence, call setPrefConfigTable(NULL), which is
the default.
Note, it is still at the discretion of the codec as to what output
config is actually returned, as it may not be able to support the
caller's preference.
Here is how the index into the table is computed from the src:
depth [8, 16, 32/24] -> 0, 2, 4
alpha [no, yes] -> 0, 1
The two index values are OR'd together.
src: 8-index, no-alpha -> 0
src: 8-index, yes-alpha -> 1
src: 16bit, no-alpha -> 2 // e.g. 565
src: 16bit, yes-alpha -> 3 // e.g. 1555
src: 32/24, no-alpha -> 4
src: 32/24, yes-alpha -> 5
*/
void setPrefConfigTable(const SkBitmap::Config pref[6]);
SkBitmap::Allocator* getAllocator() const { return fAllocator; }
SkBitmap::Allocator* setAllocator(SkBitmap::Allocator*);
......@@ -145,6 +172,9 @@ public:
note: document use of Allocator, Peeker and Chooser
*/
bool decode(SkStream*, SkBitmap* bitmap, SkBitmap::Config pref, Mode);
bool decode(SkStream* stream, SkBitmap* bitmap, Mode mode) {
return this->decode(stream, bitmap, SkBitmap::kNo_Config, mode);
}
/** Given a stream, this will try to find an appropriate decoder object.
If none is found, the method returns NULL.
......@@ -232,8 +262,7 @@ public:
protected:
// must be overridden in subclasses. This guy is called by decode(...)
virtual bool onDecode(SkStream*, SkBitmap* bitmap, SkBitmap::Config pref,
Mode) = 0;
virtual bool onDecode(SkStream*, SkBitmap* bitmap, Mode) = 0;
/** Can be queried from within onDecode, to see if the user (possibly in
a different thread) has requested the decode to cancel. If this returns
......@@ -260,12 +289,30 @@ protected:
*/
bool allocPixelRef(SkBitmap*, SkColorTable*) const;
enum SrcDepth {
kIndex_SrcDepth,
k16Bit_SrcDepth,
k32Bit_SrcDepth
};
/** The subclass, inside onDecode(), calls this to determine the config of
the returned bitmap. SrcDepth and hasAlpha reflect the raw data of the
src image. This routine returns the caller's preference given
srcDepth and hasAlpha, or kNo_Config if there is no preference.
Note: this also takes into account GetDeviceConfig(), so the subclass
need not call that.
*/
SkBitmap::Config getPrefConfig(SrcDepth, bool hasAlpha) const;
private:
Peeker* fPeeker;
Chooser* fChooser;
SkBitmap::Allocator* fAllocator;
int fSampleSize;
SkBitmap::Config fDefaultPref; // use if fUsePrefTable is false
SkBitmap::Config fPrefTable[6]; // use if fUsePrefTable is true
bool fDitherImage;
bool fUsePrefTable;
mutable bool fShouldCancelDecode;
// illegal
......
......@@ -37,7 +37,9 @@ void SkImageDecoder::SetDeviceConfig(SkBitmap::Config config)
SkImageDecoder::SkImageDecoder()
: fPeeker(NULL), fChooser(NULL), fAllocator(NULL), fSampleSize(1),
fDitherImage(true) {
fDefaultPref(SkBitmap::kNo_Config), fDitherImage(true),
fUsePrefTable(false) {
SkDebugf("--------- sizeof(fPrefTable) = %d\n", sizeof(fPrefTable));
}
SkImageDecoder::~SkImageDecoder() {
......@@ -91,6 +93,46 @@ bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
///////////////////////////////////////////////////////////////////////////////
void SkImageDecoder::setPrefConfigTable(const SkBitmap::Config pref[6]) {
if (NULL == pref) {
fUsePrefTable = false;
} else {
fUsePrefTable = true;
memcpy(fPrefTable, pref, sizeof(fPrefTable));
}
}
SkBitmap::Config SkImageDecoder::getPrefConfig(SrcDepth srcDepth,
bool srcHasAlpha) const {
SkBitmap::Config config;
if (fUsePrefTable) {
int index = 0;
switch (srcDepth) {
case kIndex_SrcDepth:
index = 0;
break;
case k16Bit_SrcDepth:
index = 2;
break;
case k32Bit_SrcDepth:
index = 4;
break;
}
if (srcHasAlpha) {
index += 1;
}
config = fPrefTable[index];
} else {
config = fDefaultPref;
}
if (SkBitmap::kNo_Config == config) {
config = SkImageDecoder::GetDeviceConfig();
}
return config;
}
bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config pref, Mode mode) {
// pass a temporary bitmap, so that if we return false, we are assured of
......@@ -99,8 +141,10 @@ bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
// we reset this to false before calling onDecode
fShouldCancelDecode = false;
// assign this, for use by getPrefConfig(), in case fUsePrefTable is false
fDefaultPref = pref;
if (!this->onDecode(stream, &tmp, pref, mode)) {
if (!this->onDecode(stream, &tmp, mode)) {
return false;
}
bm->swap(tmp);
......
......@@ -31,8 +31,7 @@ public:
}
protected:
virtual bool onDecode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config pref, Mode mode);
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
};
static SkImageDecoder* Factory(SkStream* stream) {
......@@ -81,8 +80,7 @@ private:
bool fJustBounds;
};
bool SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config prefConfig, Mode mode) {
bool SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
size_t length = stream->getLength();
SkAutoMalloc storage(length);
......@@ -110,12 +108,12 @@ bool SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
int width = callback.width();
int height = callback.height();
SkBitmap::Config config = SkBitmap::kARGB_8888_Config;
SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
// only accept prefConfig if it makes sense for us
if (SkBitmap::kARGB_4444_Config == prefConfig ||
SkBitmap::kRGB_565_Config == config) {
config = prefConfig;
if (SkBitmap::kARGB_4444_Config != config &&
SkBitmap::kRGB_565_Config != config) {
config = SkBitmap::kARGB_8888_Config;
}
SkScaledBitmapSampler sampler(width, height, getSampleSize());
......
......@@ -31,8 +31,7 @@ public:
}
protected:
virtual bool onDecode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config pref, Mode mode);
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
};
static const uint8_t gStartingIterlaceYValue[] = {
......@@ -154,8 +153,7 @@ static bool error_return(GifFileType* gif, const SkBitmap& bm,
return false;
}
bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
SkBitmap::Config prefConfig, Mode mode) {
bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) {
GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc);
if (NULL == gif) {
return error_return(gif, *bm, "DGifOpen");
......
......@@ -29,8 +29,7 @@ public:
}
protected:
virtual bool onDecode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config pref, Mode);
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
};
/////////////////////////////////////////////////////////////////////////////////////////
......@@ -79,8 +78,7 @@ static int calculateRowBytesFor8888(int w, int bitCount)
return 0;
}
bool SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config pref, Mode mode)
bool SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode)
{
size_t length = stream->read(NULL, 0);
SkAutoMalloc autoMal(length);
......
......@@ -55,8 +55,7 @@ public:
}
protected:
virtual bool onDecode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config pref, Mode);
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
};
//////////////////////////////////////////////////////////////////////////
......@@ -157,8 +156,7 @@ static bool return_false(const jpeg_decompress_struct& cinfo,
return false; // must always return false
}
bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config prefConfig, Mode mode) {
bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
#ifdef TIME_DECODE
AutoTimeMillis atm("JPEG Decode");
#endif
......@@ -215,11 +213,7 @@ bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
/* default format is RGB */
cinfo.out_color_space = JCS_RGB;
SkBitmap::Config config = prefConfig;
// if no user preference, see what the device recommends
if (config == SkBitmap::kNo_Config)
config = SkImageDecoder::GetDeviceConfig();
SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
// only these make sense for jpegs
if (config != SkBitmap::kARGB_8888_Config &&
config != SkBitmap::kARGB_4444_Config &&
......
......@@ -37,8 +37,7 @@ public:
}
protected:
virtual bool onDecode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config pref, Mode);
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
};
#ifndef png_jmpbuf
......@@ -110,9 +109,9 @@ static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
return reallyHasAlpha;
}
static bool canUpscalePaletteToConfig(SkBitmap::Config prefConfig,
static bool canUpscalePaletteToConfig(SkBitmap::Config dstConfig,
bool srcHasAlpha) {
switch (prefConfig) {
switch (dstConfig) {
case SkBitmap::kARGB_8888_Config:
case SkBitmap::kARGB_4444_Config:
return true;
......@@ -137,7 +136,7 @@ static bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) {
}
bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
SkBitmap::Config prefConfig, Mode mode) {
Mode mode) {
// SkAutoTrace apr("SkPNGImageDecoder::onDecode");
/* Create and initialize the png_struct with the desired error handler
......@@ -233,11 +232,11 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
}
if (color_type == PNG_COLOR_TYPE_PALETTE) {
config = SkBitmap::kIndex8_Config;
// now see if we can upscale to their requested config
bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);
if (canUpscalePaletteToConfig(prefConfig, paletteHasAlpha)) {
config = prefConfig;
config = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha);
// now see if we can upscale to their requested config
if (!canUpscalePaletteToConfig(config, paletteHasAlpha)) {
config = SkBitmap::kIndex8_Config;
}
} else {
png_color_16p transpColor = NULL;
......@@ -278,14 +277,16 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
PNG_COLOR_TYPE_RGB_ALPHA == color_type ||
PNG_COLOR_TYPE_GRAY_ALPHA == color_type) {
hasAlpha = true;
config = SkBitmap::kARGB_8888_Config;
} else { // we get to choose the config
config = prefConfig;
if (config == SkBitmap::kNo_Config) {
config = SkImageDecoder::GetDeviceConfig();
}
config = this->getPrefConfig(k32Bit_SrcDepth, hasAlpha);
// now match the request against our capabilities
if (hasAlpha) {
if (config != SkBitmap::kARGB_4444_Config) {
config = SkBitmap::kARGB_8888_Config;
}
} else {
if (config != SkBitmap::kRGB_565_Config &&
config != SkBitmap::kARGB_4444_Config) {
config != SkBitmap::kARGB_4444_Config) {
config = SkBitmap::kARGB_8888_Config;
}
}
......@@ -311,9 +312,6 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
const int sampleSize = this->getSampleSize();
SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
// we must always return the same config, independent of mode, so if we were
// going to respect prefConfig, it must have happened by now
decodedBitmap->setConfig(config, sampler.scaledWidth(),
sampler.scaledHeight(), 0);
if (SkImageDecoder::kDecodeBounds_Mode == mode) {
......
......@@ -29,8 +29,7 @@ public:
}
protected:
virtual bool onDecode(SkStream* stream, SkBitmap* bm,
SkBitmap::Config pref, Mode);
virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
};
static bool read_byte(SkStream* stream, uint8_t* data)
......@@ -107,7 +106,7 @@ static void expand_bits_to_bytes(uint8_t dst[], const uint8_t src[], int bits)
#define SkAlign8(x) (((x) + 7) & ~7)
bool SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
SkBitmap::Config prefConfig, Mode mode)
Mode mode)
{
wbmp_head head;
......
......@@ -43,7 +43,7 @@ static boolean sk_fill_input_buffer(j_decompress_ptr cinfo) {
static void sk_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
if (num_bytes > src->bytes_in_buffer) {
if (num_bytes > (long)src->bytes_in_buffer) {
long bytesToSkip = num_bytes - src->bytes_in_buffer;
while (bytesToSkip > 0) {
long bytes = (long)src->fStream->skip(bytesToSkip);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment