Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Unified Diff: src/codec/SkCodec_libbmp.cpp

Issue 1055743003: Swizzler changes Index8 and 565 (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fix windows errors Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/codec/SkCodec_libbmp.h ('k') | src/codec/SkCodec_libgif.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/codec/SkCodec_libbmp.cpp
diff --git a/src/codec/SkCodec_libbmp.cpp b/src/codec/SkCodec_libbmp.cpp
index 2b20faebad050c9d67a3769edc147f247c5e6ac3..b553deae6f8c0b14f669d19ee76aa4f8536f19d4 100644
--- a/src/codec/SkCodec_libbmp.cpp
+++ b/src/codec/SkCodec_libbmp.cpp
@@ -9,6 +9,7 @@
#include "SkCodecPriv.h"
#include "SkColorPriv.h"
#include "SkStream.h"
+#include "SkUtils.h"
/*
*
@@ -23,12 +24,33 @@ static bool conversion_possible(const SkImageInfo& dst,
return false;
}
- // Check for supported color and alpha types
+ // Check for supported alpha types
+ if (src.alphaType() != dst.alphaType()) {
+ if (kOpaque_SkAlphaType == src.alphaType()) {
+ // If the source is opaque, we must decode to opaque
+ return false;
+ }
+
+ // The source is not opaque
+ switch (dst.alphaType()) {
+ case kPremul_SkAlphaType:
+ case kUnpremul_SkAlphaType:
+ // The source is not opaque, so either of these is okay
+ break;
+ default:
+ // We cannot decode a non-opaque image to opaque (or unknown)
+ return false;
+ }
+ }
+
+ // Check for supported color types
switch (dst.colorType()) {
+ // Allow output to kN32 from any type of input
case kN32_SkColorType:
- return src.alphaType() == dst.alphaType() ||
- (kPremul_SkAlphaType == dst.alphaType() &&
- kUnpremul_SkAlphaType == src.alphaType());
+ return true;
+ // Allow output to kIndex_8 from compatible inputs
+ case kIndex_8_SkColorType:
+ return kIndex_8_SkColorType == src.colorType();
default:
return false;
}
@@ -420,12 +442,17 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool isIco, SkCodec** codecOut) {
}
iBuffer.free();
- // Additionally, 32 bit bmp-in-icos use the alpha channel
- if (isIco && 32 == bitsPerPixel) {
+ // Additionally, 32 bit bmp-in-icos use the alpha channel.
+ // And, RLE inputs may skip pixels, leaving them as transparent. This
+ // is uncommon, but we cannot be certain that an RLE bmp will be opaque.
+ if ((isIco && 32 == bitsPerPixel) || (kRLE_BitmapInputFormat == inputFormat)) {
alphaType = kUnpremul_SkAlphaType;
}
- // Check for valid bits per pixel input
+ // Check for valid bits per pixel.
+ // At the same time, use this information to choose a suggested color type
+ // and to set default masks.
+ SkColorType colorType = kN32_SkColorType;
switch (bitsPerPixel) {
// In addition to more standard pixel compression formats, bmp supports
// the use of bit masks to determine pixel components. The standard
@@ -440,10 +467,18 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool isIco, SkCodec** codecOut) {
inputFormat = kBitMask_BitmapInputFormat;
}
break;
+ // We want to decode to kIndex_8 for input formats that are already
+ // designed in index format.
case 1:
case 2:
case 4:
case 8:
+ // However, we cannot in RLE format since we may need to leave some
+ // pixels as transparent. Similarly, we also cannot for ICO images
+ // since we may need to apply a transparent mask.
+ if (kRLE_BitmapInputFormat != inputFormat && !isIco) {
+ colorType = kIndex_8_SkColorType;
+ }
case 24:
case 32:
break;
@@ -476,11 +511,10 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool isIco, SkCodec** codecOut) {
if (codecOut) {
// Return the codec
- // We will use ImageInfo to store width, height, and alpha type. We
- // will set color type to kN32_SkColorType because that should be the
- // default output.
+ // We will use ImageInfo to store width, height, suggested color type, and
+ // suggested alpha type.
const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
- kN32_SkColorType, alphaType);
+ colorType, alphaType);
*codecOut = SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel,
inputFormat, masks.detach(),
numColors, bytesPerColor,
@@ -541,8 +575,9 @@ SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream,
*/
SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo,
void* dst, size_t dstRowBytes,
- const Options&,
- SkPMColor*, int*) {
+ const Options& opts,
+ SkPMColor* inputColorPtr,
+ int* inputColorCount) {
// Check for proper input and output formats
SkCodec::RewindState rewindState = this->rewindIfNeeded();
if (rewindState == kCouldNotRewind_RewindState) {
@@ -562,17 +597,26 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo,
}
// Create the color table if necessary and prepare the stream for decode
- if (!createColorTable(dstInfo.alphaType())) {
+ // Note that if it is non-NULL, inputColorCount will be modified
+ if (!createColorTable(dstInfo.alphaType(), inputColorCount)) {
SkCodecPrintf("Error: could not create color table.\n");
return kInvalidInput;
}
+ // Copy the color table to the client if necessary
+ if (kIndex_8_SkColorType == dstInfo.colorType()) {
+ SkASSERT(NULL != inputColorPtr);
+ SkASSERT(NULL != inputColorCount);
+ SkASSERT(NULL != fColorTable.get());
+ sk_memcpy32(inputColorPtr, fColorTable->readColors(), *inputColorCount);
+ }
+
// Perform the decode
switch (fInputFormat) {
case kBitMask_BitmapInputFormat:
return decodeMask(dstInfo, dst, dstRowBytes);
case kRLE_BitmapInputFormat:
- return decodeRLE(dstInfo, dst, dstRowBytes);
+ return decodeRLE(dstInfo, dst, dstRowBytes, opts);
case kStandard_BitmapInputFormat:
return decode(dstInfo, dst, dstRowBytes);
default:
@@ -586,7 +630,7 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo,
* Process the color table for the bmp input
*
*/
- bool SkBmpCodec::createColorTable(SkAlphaType alphaType) {
+ bool SkBmpCodec::createColorTable(SkAlphaType alphaType, int* numColors) {
// Allocate memory for color table
uint32_t colorBytes = 0;
uint32_t maxColors = 0;
@@ -599,6 +643,15 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo,
fNumColors = maxColors;
}
+ // Inform the caller of the number of colors
+ if (NULL != numColors) {
+ SkASSERT(256 == *numColors);
+ // We set the number of colors to maxColors in order to ensure
+ // safe memory accesses. Otherwise, an invalid pixel could
+ // access memory outside of our color table array.
+ *numColors = maxColors;
+ }
+
// Read the color table from the stream
colorBytes = fNumColors * fBytesPerColor;
SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes));
@@ -632,9 +685,13 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo,
uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor);
uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1);
uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2);
- uint8_t alpha = kOpaque_SkAlphaType == alphaType ? 0xFF :
- (fMasks->getAlphaMask() >> 24) &
- get_byte(cBuffer.get(), i*fBytesPerColor + 3);
+ uint8_t alpha;
+ if (kOpaque_SkAlphaType == alphaType || kRLE_BitmapInputFormat == fInputFormat) {
+ alpha = 0xFF;
+ } else {
+ alpha = (fMasks->getAlphaMask() >> 24) &
+ get_byte(cBuffer.get(), i*fBytesPerColor + 3);
+ }
colorTable[i] = packARGB(alpha, red, green, blue);
}
@@ -740,7 +797,7 @@ SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo,
* Set an RLE pixel using the color table
*
*/
-void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes,
+void SkBmpCodec::setRLEPixel(void* dst, size_t dstRowBytes,
const SkImageInfo& dstInfo, uint32_t x, uint32_t y,
uint8_t index) {
// Set the row
@@ -755,17 +812,11 @@ void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes,
// Set the pixel based on destination color type
switch (dstInfo.colorType()) {
case kN32_SkColorType: {
- SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst,
+ SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst,
row * (int) dstRowBytes);
dstRow[x] = fColorTable->operator[](index);
break;
}
- case kRGB_565_SkColorType: {
- uint16_t* dstRow = SkTAddOffset<uint16_t>(dst,
- row * (int) dstRowBytes);
- dstRow[x] = SkPixel32ToPixel16(fColorTable->operator[](index));
- break;
- }
default:
// This case should not be reached. We should catch an invalid
// color type when we check that the conversion is possible.
@@ -779,7 +830,7 @@ void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes,
* Set an RLE pixel from R, G, B values
*
*/
-void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes,
+void SkBmpCodec::setRLE24Pixel(void* dst, size_t dstRowBytes,
const SkImageInfo& dstInfo, uint32_t x,
uint32_t y, uint8_t red, uint8_t green,
uint8_t blue) {
@@ -795,17 +846,11 @@ void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes,
// Set the pixel based on destination color type
switch (dstInfo.colorType()) {
case kN32_SkColorType: {
- SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst,
+ SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst,
row * (int) dstRowBytes);
dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue);
break;
}
- case kRGB_565_SkColorType: {
- uint16_t* dstRow = SkTAddOffset<uint16_t>(dst,
- row * (int) dstRowBytes);
- dstRow[x] = SkPack888ToRGB16(red, green, blue);
- break;
- }
default:
// This case should not be reached. We should catch an invalid
// color type when we check that the conversion is possible.
@@ -821,7 +866,8 @@ void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes,
*
*/
SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo,
- void* dst, size_t dstRowBytes) {
+ void* dst, size_t dstRowBytes,
+ const Options& opts) {
// Set RLE flags
static const uint8_t RLE_ESCAPE = 0;
static const uint8_t RLE_EOL = 0;
@@ -846,10 +892,15 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo,
// Destination parameters
int x = 0;
int y = 0;
- // If the code skips pixels, remaining pixels are transparent or black
- // TODO: Skip this if memory was already zeroed.
- memset(dst, 0, dstRowBytes * height);
- SkPMColor* dstPtr = (SkPMColor*) dst;
+
+ // Set the background as transparent. Then, if the RLE code skips pixels,
+ // the skipped pixels will be transparent.
+ // Because of the need for transparent pixels, kN32 is the only color
+ // type that makes sense for the destination format.
+ SkASSERT(kN32_SkColorType == dstInfo.colorType());
+ if (kNo_ZeroInitialized == opts.fZeroInitialized) {
+ SkSwizzler::Fill(dst, dstInfo, dstRowBytes, 0, SK_ColorTRANSPARENT, NULL);
+ }
while (true) {
// Every entry takes at least two bytes
@@ -920,11 +971,11 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo,
case 4: {
SkASSERT(currByte < totalBytes);
uint8_t val = buffer.get()[currByte++];
- setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++,
+ setRLEPixel(dst, dstRowBytes, dstInfo, x++,
y, val >> 4);
numPixels--;
if (numPixels != 0) {
- setRLEPixel(dstPtr, dstRowBytes, dstInfo,
+ setRLEPixel(dst, dstRowBytes, dstInfo,
x++, y, val & 0xF);
numPixels--;
}
@@ -932,7 +983,7 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo,
}
case 8:
SkASSERT(currByte < totalBytes);
- setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++,
+ setRLEPixel(dst, dstRowBytes, dstInfo, x++,
y, buffer.get()[currByte++]);
numPixels--;
break;
@@ -941,7 +992,7 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo,
uint8_t blue = buffer.get()[currByte++];
uint8_t green = buffer.get()[currByte++];
uint8_t red = buffer.get()[currByte++];
- setRLE24Pixel(dstPtr, dstRowBytes, dstInfo,
+ setRLE24Pixel(dst, dstRowBytes, dstInfo,
x++, y, red, green, blue);
numPixels--;
}
@@ -977,7 +1028,7 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo,
uint8_t green = buffer.get()[currByte++];
uint8_t red = buffer.get()[currByte++];
while (x < endX) {
- setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, x++, y, red,
+ setRLE24Pixel(dst, dstRowBytes, dstInfo, x++, y, red,
green, blue);
}
} else {
@@ -994,7 +1045,7 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo,
// Set the indicated number of pixels
for (int which = 0; x < endX; x++) {
- setRLEPixel(dstPtr, dstRowBytes, dstInfo, x, y,
+ setRLEPixel(dst, dstRowBytes, dstInfo, x, y,
indices[which]);
which = !which;
}
@@ -1084,7 +1135,8 @@ SkCodec::Result SkBmpCodec::decode(const SkImageInfo& dstInfo,
// Now we adjust the output image with some additional behavior that
// SkSwizzler does not support. Firstly, all bmp images that contain
// alpha are masked by the alpha mask. Secondly, many fully transparent
- // bmp images are intended to be opaque. Here, we make those corrections.
+ // bmp images are intended to be opaque. Here, we make those corrections
+ // in the kN32 case.
/*
SkPMColor* dstRow = (SkPMColor*) dst;
if (SkSwizzler::kBGRA == config) {
« no previous file with comments | « src/codec/SkCodec_libbmp.h ('k') | src/codec/SkCodec_libgif.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698