diff options
author | msarett <msarett@google.com> | 2015-03-18 11:11:19 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-03-18 11:11:19 -0700 |
commit | eed039b5ffbdff958053ac80b09451ad6caa1787 (patch) | |
tree | 231161cc1da391effd685a5b69aeb6259c7b8d1d /src | |
parent | c88e11508739f53514228f1ea487af3d7eef7f3e (diff) |
Adding swizzles for bmp:
We now support kN32 and kRGB_565 color types.
Additionally, we support premul, unpremul, and opaque alpha types.
Unpremul is currently untested as we cannot currently draw to unpremul.
BUG=skia:
Review URL: https://codereview.chromium.org/1013743003
Diffstat (limited to 'src')
-rw-r--r-- | src/codec/SkCodecPriv.h | 9 | ||||
-rw-r--r-- | src/codec/SkCodec_libbmp.cpp | 375 | ||||
-rw-r--r-- | src/codec/SkCodec_libbmp.h | 42 | ||||
-rw-r--r-- | src/codec/SkCodec_libpng.cpp | 12 | ||||
-rw-r--r-- | src/codec/SkMaskSwizzler.cpp | 264 | ||||
-rw-r--r-- | src/codec/SkMaskSwizzler.h | 14 | ||||
-rw-r--r-- | src/codec/SkSwizzler.cpp | 86 |
7 files changed, 577 insertions, 225 deletions
diff --git a/src/codec/SkCodecPriv.h b/src/codec/SkCodecPriv.h index a0e5c94900..7c57a9fe77 100644 --- a/src/codec/SkCodecPriv.h +++ b/src/codec/SkCodecPriv.h @@ -65,15 +65,6 @@ static inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) { /* * - * Checks if alpha types are premul and unpremul - * - */ -static inline bool premul_and_unpremul(SkAlphaType dst, SkAlphaType src) { - return kPremul_SkAlphaType == dst && kUnpremul_SkAlphaType == src; -} - -/* - * * Get a byte from a buffer * This method is unsafe, the caller is responsible for performing a check * diff --git a/src/codec/SkCodec_libbmp.cpp b/src/codec/SkCodec_libbmp.cpp index a96cd665b8..62cda95733 100644 --- a/src/codec/SkCodec_libbmp.cpp +++ b/src/codec/SkCodec_libbmp.cpp @@ -18,18 +18,23 @@ */ static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { - // All of the swizzles convert to kN32 - // TODO: Update this when more swizzles are supported - if (kN32_SkColorType != dst.colorType()) { + // Ensure that the profile type is unchanged + if (dst.profileType() != src.profileType()) { return false; } - // Support the swizzle if the requested alpha type is the same as our guess - // for the input alpha type - if (src.alphaType() == dst.alphaType()) { - return true; + + // Check for supported color and alpha types + switch (dst.colorType()) { + case kN32_SkColorType: + return src.alphaType() == dst.alphaType() || + (kPremul_SkAlphaType == dst.alphaType() && + kUnpremul_SkAlphaType == src.alphaType()); + case kRGB_565_SkColorType: + return src.alphaType() == dst.alphaType() && + kOpaque_SkAlphaType == dst.alphaType(); + default: + return false; } - // TODO: Support more swizzles, especially premul - return false; } /* @@ -247,7 +252,7 @@ SkCodec* SkBmpCodec::NewFromStream(SkStream* stream) { // Create mask struct SkMasks::InputMasks inputMasks; - memset(&inputMasks, 0, 4*sizeof(uint32_t)); + memset(&inputMasks, 0, sizeof(SkMasks::InputMasks)); // Determine the input compression format and set bit masks if necessary uint32_t maskBytes = 0; @@ -392,87 +397,30 @@ SkCodec* SkBmpCodec::NewFromStream(SkStream* stream) { return NULL; } - // Process the color table - uint32_t colorBytes = 0; - SkPMColor* colorTable = NULL; - if (bitsPerPixel < 16) { - // Verify the number of colors for the color table - const uint32_t maxColors = 1 << bitsPerPixel; - // Zero is a default for maxColors - // Also set numColors to maxColors when input is too large - if (numColors <= 0 || numColors > maxColors) { - numColors = maxColors; - } - colorTable = SkNEW_ARRAY(SkPMColor, maxColors); - - // Construct the color table - colorBytes = numColors * bytesPerColor; - SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes)); - if (stream->read(cBuffer.get(), colorBytes) != colorBytes) { - SkDebugf("Error: unable to read color table.\n"); - return NULL; - } - - // Fill in the color table (colors are stored unpremultiplied) - uint32_t i = 0; - for (; i < numColors; i++) { - uint8_t blue = get_byte(cBuffer.get(), i*bytesPerColor); - uint8_t green = get_byte(cBuffer.get(), i*bytesPerColor + 1); - uint8_t red = get_byte(cBuffer.get(), i*bytesPerColor + 2); - uint8_t alpha = 0xFF; - if (kOpaque_SkAlphaType != alphaType) { - alpha = (inputMasks.alpha >> 24) & - get_byte(cBuffer.get(), i*bytesPerColor + 3); - } - // Store the unpremultiplied color - colorTable[i] = SkPackARGB32NoCheck(alpha, red, green, blue); - } - - // To avoid segmentation faults on bad pixel data, fill the end of the - // color table with black. This is the same the behavior as the - // chromium decoder. - for (; i < maxColors; i++) { - colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); - } - } - - // Ensure that the stream now points to the start of the pixel array - uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes + colorBytes; - - // Check that we have not read past the pixel array offset - if(bytesRead > offset) { - // This may occur on OS 2.1 and other old versions where the color - // table defaults to max size, and the bmp tries to use a smaller color - // table. This is invalid, and our decision is to indicate an error, - // rather than try to guess the intended size of the color table and - // rewind the stream to display the image. - SkDebugf("Error: pixel data offset less than header size.\n"); - return NULL; - } - - // Skip to the start of the pixel array - if (stream->skip(offset - bytesRead) != offset - bytesRead) { - SkDebugf("Error: unable to skip to image data.\n"); + // Check for a valid number of total bytes when in RLE mode + if (totalBytes <= offset && kRLE_BitmapInputFormat == inputFormat) { + SkDebugf("Error: RLE requires valid input size.\n"); return NULL; } + const size_t RLEBytes = totalBytes - offset; - // Remaining bytes is only used for RLE - const int remainingBytes = totalBytes - offset; - if (remainingBytes <= 0 && kRLE_BitmapInputFormat == inputFormat) { - SkDebugf("Error: RLE requires valid input size.\n"); + // Calculate the number of bytes read so far + const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes; + if (offset < bytesRead) { + SkDebugf("Error: pixel data offset less than header size.\n"); return NULL; } // Return the codec // We will use ImageInfo to store width, height, and alpha type. We will - // choose kN32_SkColorType as the input color type because that is the - // expected choice for a destination color type. In reality, the input - // color type has many possible formats. + // set color type to kN32_SkColorType because that should be the default + // output. const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, kN32_SkColorType, alphaType); return SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel, - inputFormat, masks.detach(), colorTable, - rowOrder, remainingBytes)); + inputFormat, masks.detach(), numColors, + bytesPerColor, offset - bytesRead, + rowOrder, RLEBytes)); } /* @@ -483,16 +431,19 @@ SkCodec* SkBmpCodec::NewFromStream(SkStream* stream) { */ SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, uint16_t bitsPerPixel, BitmapInputFormat inputFormat, - SkMasks* masks, SkPMColor* colorTable, - RowOrder rowOrder, - const uint32_t remainingBytes) + SkMasks* masks, uint32_t numColors, + uint32_t bytesPerColor, uint32_t offset, + RowOrder rowOrder, size_t RLEBytes) : INHERITED(info, stream) , fBitsPerPixel(bitsPerPixel) , fInputFormat(inputFormat) , fMasks(masks) - , fColorTable(colorTable) + , fColorTable(NULL) + , fNumColors(numColors) + , fBytesPerColor(bytesPerColor) + , fOffset(offset) , fRowOrder(rowOrder) - , fRemainingBytes(remainingBytes) + , fRLEBytes(RLEBytes) {} /* @@ -504,6 +455,7 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options&, SkPMColor*, int*) { + // Check for proper input and output formats if (!this->rewindIfNeeded()) { return kCouldNotRewind; } @@ -516,6 +468,13 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, return kInvalidConversion; } + // Create the color table if necessary and prepare the stream for decode + if (!createColorTable(dstInfo.alphaType())) { + SkDebugf("Error: could not create color table.\n"); + return kInvalidInput; + } + + // Perform the decode switch (fInputFormat) { case kBitMask_BitmapInputFormat: return decodeMask(dstInfo, dst, dstRowBytes); @@ -531,6 +490,92 @@ SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, /* * + * Process the color table for the bmp input + * + */ + bool SkBmpCodec::createColorTable(SkAlphaType alphaType) { + // Allocate memory for color table + uint32_t colorBytes = 0; + uint32_t maxColors = 0; + SkPMColor colorTable[256]; + if (fBitsPerPixel <= 8) { + // Zero is a default for maxColors + // Also set fNumColors to maxColors when it is too large + maxColors = 1 << fBitsPerPixel; + if (fNumColors == 0 || fNumColors >= maxColors) { + fNumColors = maxColors; + } + + // Read the color table from the stream + colorBytes = fNumColors * fBytesPerColor; + SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes)); + if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) { + SkDebugf("Error: unable to read color table.\n"); + return false; + } + + // Choose the proper packing function + SkPMColor (*packARGB) (uint32_t, uint32_t, uint32_t, uint32_t); + switch (alphaType) { + case kOpaque_SkAlphaType: + case kUnpremul_SkAlphaType: + packARGB = &SkPackARGB32NoCheck; + break; + case kPremul_SkAlphaType: + packARGB = &SkPreMultiplyARGB; + break; + default: + // This should not be reached because conversion possible + // should fail if the alpha type is not one of the above + // values. + SkASSERT(false); + packARGB = NULL; + break; + } + + // Fill in the color table + uint32_t i = 0; + for (; i < fNumColors; i++) { + 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); + colorTable[i] = packARGB(alpha, red, green, blue); + } + + // To avoid segmentation faults on bad pixel data, fill the end of the + // color table with black. This is the same the behavior as the + // chromium decoder. + for (; i < maxColors; i++) { + colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); + } + } + + // Check that we have not read past the pixel array offset + if(fOffset < colorBytes) { + // This may occur on OS 2.1 and other old versions where the color + // table defaults to max size, and the bmp tries to use a smaller color + // table. This is invalid, and our decision is to indicate an error, + // rather than try to guess the intended size of the color table. + SkDebugf("Error: pixel data offset less than color table size.\n"); + return false; + } + + // After reading the color table, skip to the start of the pixel array + if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) { + SkDebugf("Error: unable to skip to image data.\n"); + return false; + } + + // Set the color table and return true on success + fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorTable, maxColors))); + return true; +} + +/* + * * Performs the bitmap decoding for bit masks input format * */ @@ -541,50 +586,50 @@ SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, const int height = dstInfo.height(); const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); - // Allocate space for a row buffer and a source for the swizzler - SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes)); - - // Get the destination start row and delta - SkPMColor* dstRow; - int delta; - if (kTopDown_RowOrder == fRowOrder) { - dstRow = (SkPMColor*) dst; - delta = (int) dstRowBytes; - } else { - dstRow = (SkPMColor*) SkTAddOffset<void>(dst, (height-1) * dstRowBytes); - delta = -((int) dstRowBytes); - } + // Allocate a buffer large enough to hold the full image + SkAutoTDeleteArray<uint8_t> + srcBuffer(SkNEW_ARRAY(uint8_t, height*rowBytes)); + uint8_t* srcRow = srcBuffer.get(); // Create the swizzler - SkMaskSwizzler* swizzler = SkMaskSwizzler::CreateMaskSwizzler( - dstInfo, fMasks, fBitsPerPixel); + SkAutoTDelete<SkMaskSwizzler> maskSwizzler( + SkMaskSwizzler::CreateMaskSwizzler(dstInfo, dst, dstRowBytes, + fMasks, fBitsPerPixel)); // Iterate over rows of the image bool transparent = true; for (int y = 0; y < height; y++) { // Read a row of the input - if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) { + if (stream()->read(srcRow, rowBytes) != rowBytes) { SkDebugf("Warning: incomplete input stream.\n"); return kIncompleteInput; } // Decode the row in destination format - SkSwizzler::ResultAlpha r = swizzler->next(dstRow, srcBuffer.get()); + int row = kBottomUp_RowOrder == fRowOrder ? height - 1 - y : y; + SkSwizzler::ResultAlpha r = maskSwizzler->next(srcRow, row); transparent &= SkSwizzler::IsTransparent(r); // Move to the next row - dstRow = SkTAddOffset<SkPMColor>(dstRow, delta); + srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes); } // Some fully transparent bmp images are intended to be opaque. Here, we // correct for this possibility. - dstRow = (SkPMColor*) dst; if (transparent) { + const SkImageInfo& opaqueInfo = + dstInfo.makeAlphaType(kOpaque_SkAlphaType); + SkAutoTDelete<SkMaskSwizzler> opaqueSwizzler( + SkMaskSwizzler::CreateMaskSwizzler(opaqueInfo, dst, dstRowBytes, + fMasks, fBitsPerPixel)); + srcRow = srcBuffer.get(); for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - dstRow[x] |= 0xFF000000; - } - dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); + // Decode the row in opaque format + int row = kBottomUp_RowOrder == fRowOrder ? height - 1 - y : y; + opaqueSwizzler->next(srcRow, row); + + // Move to the next row + srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes); } } @@ -597,13 +642,78 @@ SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, * Set an RLE pixel using the color table * */ -void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, int height, - uint32_t x, uint32_t y, uint8_t index) { +void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, + const SkImageInfo& dstInfo, uint32_t x, uint32_t y, + uint8_t index) { + // Set the row + int height = dstInfo.height(); + int row; if (kBottomUp_RowOrder == fRowOrder) { - y = height - y - 1; + row = height - y - 1; + } else { + row = y; + } + + // Set the pixel based on destination color type + switch (dstInfo.colorType()) { + case kN32_SkColorType: { + SkPMColor* dstRow = SkTAddOffset<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. + SkASSERT(false); + break; + } +} + +/* + * + * Set an RLE pixel from R, G, B values + * + */ +void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes, + const SkImageInfo& dstInfo, uint32_t x, + uint32_t y, uint8_t red, uint8_t green, + uint8_t blue) { + // Set the row + int height = dstInfo.height(); + int row; + if (kBottomUp_RowOrder == fRowOrder) { + row = height - y - 1; + } else { + row = y; + } + + // Set the pixel based on destination color type + switch (dstInfo.colorType()) { + case kN32_SkColorType: { + SkPMColor* dstRow = SkTAddOffset<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. + SkASSERT(false); + break; } - SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, y * dstRowBytes); - dstRow[x] = fColorTable.get()[index]; } /* @@ -626,9 +736,9 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, // Input buffer parameters uint32_t currByte = 0; - SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRemainingBytes)); - size_t totalBytes = stream()->read(buffer.get(), fRemainingBytes); - if ((uint32_t) totalBytes < fRemainingBytes) { + SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRLEBytes)); + size_t totalBytes = stream()->read(buffer.get(), fRLEBytes); + if (totalBytes < fRLEBytes) { SkDebugf("Warning: incomplete RLE file.\n"); } else if (totalBytes <= 0) { SkDebugf("Error: could not read RLE image data.\n"); @@ -707,18 +817,16 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, return kIncompleteInput; } // Set numPixels number of pixels - SkPMColor* dstRow = SkTAddOffset<SkPMColor>( - dstPtr, y * dstRowBytes); while (numPixels > 0) { switch(fBitsPerPixel) { case 4: { SkASSERT(currByte < totalBytes); uint8_t val = buffer.get()[currByte++]; - setRLEPixel(dstPtr, dstRowBytes, height, x++, y, - val >> 4); + setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, + y, val >> 4); numPixels--; if (numPixels != 0) { - setRLEPixel(dstPtr, dstRowBytes, height, + setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, y, val & 0xF); numPixels--; } @@ -726,8 +834,8 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, } case 8: SkASSERT(currByte < totalBytes); - setRLEPixel(dstPtr, dstRowBytes, height, x++, y, - buffer.get()[currByte++]); + setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, + y, buffer.get()[currByte++]); numPixels--; break; case 24: { @@ -735,9 +843,8 @@ 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++]; - SkPMColor color = SkPackARGB32NoCheck( - 0xFF, red, green, blue); - dstRow[x++] = color; + setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, + x++, y, red, green, blue); numPixels--; } default: @@ -771,11 +878,9 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, uint8_t blue = task; uint8_t green = buffer.get()[currByte++]; uint8_t red = buffer.get()[currByte++]; - SkPMColor color = SkPackARGB32NoCheck(0xFF, red, green, blue); - SkPMColor* dstRow = - SkTAddOffset<SkPMColor>(dstPtr, y * dstRowBytes); while (x < endX) { - dstRow[x++] = color; + setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, x++, y, red, + green, blue); } } else { // In RLE8 or RLE4, the second byte read gives the index in the @@ -791,7 +896,7 @@ SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, // Set the indicated number of pixels for (int which = 0; x < endX; x++) { - setRLEPixel(dstPtr, dstRowBytes, height, x, y, + setRLEPixel(dstPtr, dstRowBytes, dstInfo, x, y, indices[which]); which = !which; } @@ -811,7 +916,6 @@ SkCodec::Result SkBmpCodec::decode(const SkImageInfo& dstInfo, const int width = dstInfo.width(); const int height = dstInfo.height(); const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); - const uint32_t alphaMask = fMasks->getAlphaMask(); // Get swizzler configuration SkSwizzler::SrcConfig config; @@ -832,7 +936,7 @@ SkCodec::Result SkBmpCodec::decode(const SkImageInfo& dstInfo, config = SkSwizzler::kBGR; break; case 32: - if (0 == alphaMask) { + if (kOpaque_SkAlphaType == dstInfo.alphaType()) { config = SkSwizzler::kBGRX; } else { config = SkSwizzler::kBGRA; @@ -844,8 +948,9 @@ SkCodec::Result SkBmpCodec::decode(const SkImageInfo& dstInfo, } // Create swizzler - SkSwizzler* swizzler = SkSwizzler::CreateSwizzler(config, fColorTable.get(), - dstInfo, dst, dstRowBytes, SkImageGenerator::kNo_ZeroInitialized); + SkAutoTDelete<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(config, + fColorTable->readColors(), dstInfo, dst, dstRowBytes, + SkImageGenerator::kNo_ZeroInitialized)); // Allocate space for a row buffer and a source for the swizzler SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes)); diff --git a/src/codec/SkCodec_libbmp.h b/src/codec/SkCodec_libbmp.h index 21dab1a4d9..e6620d275d 100644 --- a/src/codec/SkCodec_libbmp.h +++ b/src/codec/SkCodec_libbmp.h @@ -6,6 +6,7 @@ */ #include "SkCodec.h" +#include "SkColorTable.h" #include "SkImageInfo.h" #include "SkMaskSwizzler.h" #include "SkStream.h" @@ -75,6 +76,13 @@ private: /* * + * Creates the color table + * + */ + bool createColorTable(SkAlphaType alphaType); + + /* + * * Performs the bitmap decoding for bit masks input format * */ @@ -86,8 +94,17 @@ private: * Set an RLE pixel using the color table * */ - void setRLEPixel(SkPMColor* dst, size_t dstRowBytes, int height, - uint32_t x, uint32_t y, uint8_t index); + void setRLEPixel(SkPMColor* dst, size_t dstRowBytes, + const SkImageInfo& dstInfo, uint32_t x, uint32_t y, + uint8_t index); + /* + * + * Set an RLE24 pixel from R, G, B values + * + */ + void setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes, + const SkImageInfo& dstInfo, uint32_t x, uint32_t y, + uint8_t red, uint8_t green, uint8_t blue); /* * @@ -115,11 +132,13 @@ private: * @param format the format of the bmp file * @param masks optional color masks for certain bmp formats, passes ownership to SkBmpCodec - * @param colorTable array representing the color table for index-based bmp - * formats, colors are unpremultiplied, passes ownership - * to SkBmpCodec + * @param numColors the number of colors in the color table + * @param bytesPerColor the number of bytes in the stream used to represent + each color in the color table + * @param offset the offset of the image pixel data from the end of the + * headers * @param rowOrder indicates whether rows are ordered top-down or bottom-up - * @param remainingBytes used only for RLE decodes, as we must decode all + * @param RLEBytes used only for RLE decodes, as we must decode all * of the data at once rather than row by row * it indicates the amount of data left in the stream * after decoding the headers @@ -127,16 +146,19 @@ private: */ SkBmpCodec(const SkImageInfo& srcInfo, SkStream* stream, uint16_t bitsPerPixel, BitmapInputFormat format, - SkMasks* masks, SkPMColor* colorTable, - RowOrder rowOrder, uint32_t remainingBytes); + SkMasks* masks, uint32_t numColors, uint32_t bytesPerColor, + uint32_t offset, RowOrder rowOrder, size_t RLEByes); // Fields const uint16_t fBitsPerPixel; const BitmapInputFormat fInputFormat; SkAutoTDelete<SkMasks> fMasks; // owned - const SkAutoTDeleteArray<SkPMColor> fColorTable; // owned, unpremul + SkAutoTDelete<SkColorTable> fColorTable; // owned + uint32_t fNumColors; + const uint32_t fBytesPerColor; + const uint32_t fOffset; const RowOrder fRowOrder; - const uint32_t fRemainingBytes; + const size_t fRLEBytes; typedef SkCodec INHERITED; }; diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp index bf0647dd24..57653e74df 100644 --- a/src/codec/SkCodec_libpng.cpp +++ b/src/codec/SkCodec_libpng.cpp @@ -347,19 +347,19 @@ SkPngCodec::~SkPngCodec() { // Getting the pixels /////////////////////////////////////////////////////////////////////////////// -static bool conversion_possible(const SkImageInfo& A, const SkImageInfo& B) { +static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) { // TODO: Support other conversions - if (A.colorType() != B.colorType()) { + if (dst.colorType() != src.colorType()) { return false; } - if (A.profileType() != B.profileType()) { + if (dst.profileType() != src.profileType()) { return false; } - if (A.alphaType() == B.alphaType()) { + if (dst.alphaType() == src.alphaType()) { return true; } - return premul_and_unpremul(A.alphaType(), B.alphaType()) - || premul_and_unpremul(B.alphaType(), A.alphaType()); + return kPremul_SkAlphaType == dst.alphaType() && + kUnpremul_SkAlphaType == src.alphaType(); } SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, diff --git a/src/codec/SkMaskSwizzler.cpp b/src/codec/SkMaskSwizzler.cpp index 8d9f6c66b3..944042d1ab 100644 --- a/src/codec/SkMaskSwizzler.cpp +++ b/src/codec/SkMaskSwizzler.cpp @@ -9,12 +9,7 @@ #include "SkColorPriv.h" #include "SkMaskSwizzler.h" -/* - * - * Row procedure for masked color components with 16 bits per pixel - * - */ -static SkSwizzler::ResultAlpha swizzle_mask16_to_n32( +static SkSwizzler::ResultAlpha swizzle_mask16_to_n32_opaque( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { // Use the masks to decode to the destination @@ -30,12 +25,7 @@ static SkSwizzler::ResultAlpha swizzle_mask16_to_n32( return SkSwizzler::kOpaque_ResultAlpha; } -/* - * - * Row procedure for masked color components with 16 bits per pixel with alpha - * - */ -static SkSwizzler::ResultAlpha swizzle_mask16_alpha_to_n32( +static SkSwizzler::ResultAlpha swizzle_mask16_to_n32_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { // Use the masks to decode to the destination @@ -54,12 +44,42 @@ static SkSwizzler::ResultAlpha swizzle_mask16_alpha_to_n32( return COMPUTE_RESULT_ALPHA; } -/* - * - * Row procedure for masked color components with 24 bits per pixel - * - */ -static SkSwizzler::ResultAlpha swizzle_mask24_to_n32( +static SkSwizzler::ResultAlpha swizzle_mask16_to_n32_premul( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { + + // Use the masks to decode to the destination + uint16_t* srcPtr = (uint16_t*) srcRow; + SkPMColor* dstPtr = (SkPMColor*) dstRow; + INIT_RESULT_ALPHA; + for (int i = 0; i < width; i++) { + uint16_t p = srcPtr[i]; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + uint8_t alpha = masks->getAlpha(p); + UPDATE_RESULT_ALPHA(alpha); + dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue); + } + return COMPUTE_RESULT_ALPHA; +} + +static SkSwizzler::ResultAlpha swizzle_mask16_to_565( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { + + // Use the masks to decode to the destination + uint16_t* srcPtr = (uint16_t*) srcRow; + uint16_t* dstPtr = (uint16_t*) dstRow; + for (int i = 0; i < width; i++) { + uint16_t p = srcPtr[i]; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + dstPtr[i] = SkPack888ToRGB16(red, green, blue); + } + return SkSwizzler::kOpaque_ResultAlpha; +} + +static SkSwizzler::ResultAlpha swizzle_mask24_to_n32_opaque( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { // Use the masks to decode to the destination @@ -74,12 +94,7 @@ static SkSwizzler::ResultAlpha swizzle_mask24_to_n32( return SkSwizzler::kOpaque_ResultAlpha; } -/* - * - * Row procedure for masked color components with 24 bits per pixel with alpha - * - */ -static SkSwizzler::ResultAlpha swizzle_mask24_alpha_to_n32( +static SkSwizzler::ResultAlpha swizzle_mask24_to_n32_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { // Use the masks to decode to the destination @@ -97,12 +112,40 @@ static SkSwizzler::ResultAlpha swizzle_mask24_alpha_to_n32( return COMPUTE_RESULT_ALPHA; } -/* - * - * Row procedure for masked color components with 32 bits per pixel - * - */ -static SkSwizzler::ResultAlpha swizzle_mask32_to_n32( +static SkSwizzler::ResultAlpha swizzle_mask24_to_n32_premul( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { + + // Use the masks to decode to the destination + SkPMColor* dstPtr = (SkPMColor*) dstRow; + INIT_RESULT_ALPHA; + for (int i = 0; i < 3*width; i += 3) { + uint32_t p = srcRow[i] | (srcRow[i + 1] << 8) | srcRow[i + 2] << 16; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + uint8_t alpha = masks->getAlpha(p); + UPDATE_RESULT_ALPHA(alpha); + dstPtr[i/3] = SkPreMultiplyARGB(alpha, red, green, blue); + } + return COMPUTE_RESULT_ALPHA; +} + +static SkSwizzler::ResultAlpha swizzle_mask24_to_565( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { + + // Use the masks to decode to the destination + uint16_t* dstPtr = (uint16_t*) dstRow; + for (int i = 0; i < 3*width; i += 3) { + uint32_t p = srcRow[i] | (srcRow[i + 1] << 8) | srcRow[i + 2] << 16; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + dstPtr[i/3] = SkPack888ToRGB16(red, green, blue); + } + return SkSwizzler::kOpaque_ResultAlpha; +} + +static SkSwizzler::ResultAlpha swizzle_mask32_to_n32_opaque( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { // Use the masks to decode to the destination @@ -118,12 +161,7 @@ static SkSwizzler::ResultAlpha swizzle_mask32_to_n32( return SkSwizzler::kOpaque_ResultAlpha; } -/* - * - * Row procedure for masked color components with 32 bits per pixel - * - */ -static SkSwizzler::ResultAlpha swizzle_mask32_alpha_to_n32( +static SkSwizzler::ResultAlpha swizzle_mask32_to_n32_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { // Use the masks to decode to the destination @@ -142,44 +180,148 @@ static SkSwizzler::ResultAlpha swizzle_mask32_alpha_to_n32( return COMPUTE_RESULT_ALPHA; } +static SkSwizzler::ResultAlpha swizzle_mask32_to_n32_premul( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { + + // Use the masks to decode to the destination + uint32_t* srcPtr = (uint32_t*) srcRow; + SkPMColor* dstPtr = (SkPMColor*) dstRow; + INIT_RESULT_ALPHA; + for (int i = 0; i < width; i++) { + uint32_t p = srcPtr[i]; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + uint8_t alpha = masks->getAlpha(p); + UPDATE_RESULT_ALPHA(alpha); + dstPtr[i] = SkPreMultiplyARGB(alpha, red, green, blue); + } + return COMPUTE_RESULT_ALPHA; +} + +static SkSwizzler::ResultAlpha swizzle_mask32_to_565( + void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { + + // Use the masks to decode to the destination + uint32_t* srcPtr = (uint32_t*) srcRow; + uint16_t* dstPtr = (uint16_t*) dstRow; + for (int i = 0; i < width; i++) { + uint32_t p = srcPtr[i]; + uint8_t red = masks->getRed(p); + uint8_t green = masks->getGreen(p); + uint8_t blue = masks->getBlue(p); + dstPtr[i] = SkPack888ToRGB16(red, green, blue); + } + return SkSwizzler::kOpaque_ResultAlpha; +} + /* * * Create a new mask swizzler * */ SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler( - const SkImageInfo& imageInfo, SkMasks* masks, uint32_t bitsPerPixel) { + const SkImageInfo& info, void* dst, size_t dstRowBytes, SkMasks* masks, + uint32_t bitsPerPixel) { // Choose the appropriate row procedure RowProc proc = NULL; - uint32_t alphaMask = masks->getAlphaMask(); switch (bitsPerPixel) { case 16: - if (0 == alphaMask) { - proc = &swizzle_mask16_to_n32; - } else { - proc = &swizzle_mask16_alpha_to_n32; + switch (info.colorType()) { + case kN32_SkColorType: + switch (info.alphaType()) { + case kUnpremul_SkAlphaType: + proc = &swizzle_mask16_to_n32_unpremul; + break; + case kPremul_SkAlphaType: + proc = &swizzle_mask16_to_n32_premul; + break; + case kOpaque_SkAlphaType: + proc = &swizzle_mask16_to_n32_opaque; + break; + default: + break; + } + break; + case kRGB_565_SkColorType: + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + proc = &swizzle_mask16_to_565; + break; + default: + break; + } + break; + default: + break; } break; case 24: - if (0 == alphaMask) { - proc = &swizzle_mask24_to_n32; - } else { - proc = &swizzle_mask24_alpha_to_n32; + switch (info.colorType()) { + case kN32_SkColorType: + switch (info.alphaType()) { + case kUnpremul_SkAlphaType: + proc = &swizzle_mask24_to_n32_unpremul; + break; + case kPremul_SkAlphaType: + proc = &swizzle_mask24_to_n32_premul; + break; + case kOpaque_SkAlphaType: + proc = &swizzle_mask24_to_n32_opaque; + break; + default: + break; + } + break; + case kRGB_565_SkColorType: + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + proc = &swizzle_mask24_to_565; + break; + default: + break; + } + break; + default: + break; } break; case 32: - if (0 == alphaMask) { - proc = &swizzle_mask32_to_n32; - } else { - proc = &swizzle_mask32_alpha_to_n32; + switch (info.colorType()) { + case kN32_SkColorType: + switch (info.alphaType()) { + case kUnpremul_SkAlphaType: + proc = &swizzle_mask32_to_n32_unpremul; + break; + case kPremul_SkAlphaType: + proc = &swizzle_mask32_to_n32_premul; + break; + case kOpaque_SkAlphaType: + proc = &swizzle_mask32_to_n32_opaque; + break; + default: + break; + } + break; + case kRGB_565_SkColorType: + switch (info.alphaType()) { + case kOpaque_SkAlphaType: + proc = &swizzle_mask32_to_565; + break; + default: + break; + } + break; + default: + break; } break; default: SkASSERT(false); return NULL; } - return SkNEW_ARGS(SkMaskSwizzler, (imageInfo, masks, proc)); + return SkNEW_ARGS(SkMaskSwizzler, (info, dst, dstRowBytes, masks, proc)); } /* @@ -187,19 +329,25 @@ SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler( * Constructor for mask swizzler * */ -SkMaskSwizzler::SkMaskSwizzler(const SkImageInfo& imageInfo, - SkMasks* masks, RowProc proc) - : fImageInfo(imageInfo) +SkMaskSwizzler::SkMaskSwizzler(const SkImageInfo& dstInfo, void* dst, + size_t dstRowBytes, SkMasks* masks, RowProc proc) + : fDstInfo(dstInfo) + , fDst(dst) + , fDstRowBytes(dstRowBytes) , fMasks(masks) , fRowProc(proc) {} /* * - * Swizzle the next row + * Swizzle the specified row * */ -SkSwizzler::ResultAlpha SkMaskSwizzler::next(void* dst, - const uint8_t* src) { - return fRowProc(dst, src, fImageInfo.width(), fMasks); +SkSwizzler::ResultAlpha SkMaskSwizzler::next(const uint8_t* SK_RESTRICT src, + int y) { + // Choose the row + void* row = SkTAddOffset<void>(fDst, y*fDstRowBytes); + + // Decode the row + return fRowProc(row, src, fDstInfo.width(), fMasks); } diff --git a/src/codec/SkMaskSwizzler.h b/src/codec/SkMaskSwizzler.h index 9351f0228b..69103023c6 100644 --- a/src/codec/SkMaskSwizzler.h +++ b/src/codec/SkMaskSwizzler.h @@ -25,15 +25,16 @@ public: * */ static SkMaskSwizzler* CreateMaskSwizzler(const SkImageInfo& imageInfo, + void* dst, size_t dstRowBytes, SkMasks* masks, uint32_t bitsPerPixel); /* * - * Swizzle the next row + * Swizzle the row with the specified y value * */ - SkSwizzler::ResultAlpha next(void* dst, const uint8_t* src); + SkSwizzler::ResultAlpha next(const uint8_t* SK_RESTRICT src, int y); private: @@ -51,10 +52,13 @@ private: * Constructor for mask swizzler * */ - SkMaskSwizzler(const SkImageInfo& info, SkMasks* masks, RowProc proc); + SkMaskSwizzler(const SkImageInfo& info, void* dst, size_t dstRowBytes, + SkMasks* masks, RowProc proc); // Fields - const SkImageInfo& fImageInfo; - SkMasks* fMasks; // unowned + const SkImageInfo& fDstInfo; + void* fDst; + size_t fDstRowBytes; + SkMasks* fMasks; // unowned const RowProc fRowProc; }; diff --git a/src/codec/SkSwizzler.cpp b/src/codec/SkSwizzler.cpp index 1aa3793f15..351b3be1d2 100644 --- a/src/codec/SkSwizzler.cpp +++ b/src/codec/SkSwizzler.cpp @@ -44,6 +44,28 @@ static SkSwizzler::ResultAlpha swizzle_small_index_to_n32( return COMPUTE_RESULT_ALPHA; } +static SkSwizzler::ResultAlpha swizzle_small_index_to_565( + void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, + int bitsPerPixel, int y, const SkPMColor ctable[]) { + + uint16_t* SK_RESTRICT dst = (uint16_t*) dstRow; + const uint32_t pixelsPerByte = 8 / bitsPerPixel; + const size_t rowBytes = compute_row_bytes_ppb(width, pixelsPerByte); + const uint8_t mask = (1 << bitsPerPixel) - 1; + int x = 0; + for (uint32_t byte = 0; byte < rowBytes; byte++) { + uint8_t pixelData = src[byte]; + for (uint32_t p = 0; p < pixelsPerByte && x < width; p++) { + uint8_t index = (pixelData >> (8 - bitsPerPixel)) & mask; + uint16_t c = SkPixel32ToPixel16(ctable[index]); + dst[x] = c; + pixelData <<= bitsPerPixel; + x++; + } + } + return SkSwizzler::kOpaque_ResultAlpha; +} + // kIndex static SkSwizzler::ResultAlpha swizzle_index_to_n32( @@ -78,6 +100,19 @@ static SkSwizzler::ResultAlpha swizzle_index_to_n32_skipZ( return COMPUTE_RESULT_ALPHA; } +static SkSwizzler::ResultAlpha swizzle_index_to_565( + void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, + int bytesPerPixel, int y, const SkPMColor ctable[]) { + + uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; + for (int x = 0; x < width; x++) { + uint16_t c = SkPixel32ToPixel16(ctable[*src]); + dst[x] = c; + src++; + } + return SkSwizzler::kOpaque_ResultAlpha; +} + #undef A32_MASK_IN_PLACE static SkSwizzler::ResultAlpha swizzle_bgrx_to_n32( @@ -92,9 +127,21 @@ static SkSwizzler::ResultAlpha swizzle_bgrx_to_n32( return SkSwizzler::kOpaque_ResultAlpha; } +static SkSwizzler::ResultAlpha swizzle_bgrx_to_565( + void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, + int bytesPerPixel, int y, const SkPMColor ctable[]) { + + uint16_t* SK_RESTRICT dst = (uint16_t*)dstRow; + for (int x = 0; x < width; x++) { + dst[x] = SkPack888ToRGB16(src[2], src[1], src[0]); + src += bytesPerPixel; + } + return SkSwizzler::kOpaque_ResultAlpha; +} + // kBGRA -static SkSwizzler::ResultAlpha swizzle_bgra_to_n32( +static SkSwizzler::ResultAlpha swizzle_bgra_to_n32_unpremul( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, int bytesPerPixel, int y, const SkPMColor ctable[]) { @@ -109,6 +156,21 @@ static SkSwizzler::ResultAlpha swizzle_bgra_to_n32( return COMPUTE_RESULT_ALPHA; } +static SkSwizzler::ResultAlpha swizzle_bgra_to_n32_premul( + void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, + int bytesPerPixel, int y, const SkPMColor ctable[]) { + + SkPMColor* SK_RESTRICT dst = (SkPMColor*)dstRow; + INIT_RESULT_ALPHA; + for (int x = 0; x < width; x++) { + uint8_t alpha = src[3]; + UPDATE_RESULT_ALPHA(alpha); + dst[x] = SkPreMultiplyARGB(alpha, src[2], src[1], src[0]); + src += bytesPerPixel; + } + return COMPUTE_RESULT_ALPHA; +} + // n32 static SkSwizzler::ResultAlpha swizzle_rgbx_to_n32( void* SK_RESTRICT dstRow, const uint8_t* SK_RESTRICT src, int width, @@ -220,6 +282,9 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, case kN32_SkColorType: proc = &swizzle_small_index_to_n32; break; + case kRGB_565_SkColorType: + proc = &swizzle_small_index_to_565; + break; default: break; } @@ -230,10 +295,15 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, // We assume the color premultiplied ctable (or not) as desired. if (SkImageGenerator::kYes_ZeroInitialized == zeroInit) { proc = &swizzle_index_to_n32_skipZ; + break; } else { proc = &swizzle_index_to_n32; + break; } break; + case kRGB_565_SkColorType: + proc = &swizzle_index_to_565; + break; default: break; } @@ -244,6 +314,9 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, case kN32_SkColorType: proc = &swizzle_bgrx_to_n32; break; + case kRGB_565_SkColorType: + proc = &swizzle_bgrx_to_565; + break; default: break; } @@ -251,7 +324,16 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc, case kBGRA: switch (info.colorType()) { case kN32_SkColorType: - proc = &swizzle_bgra_to_n32; + switch (info.alphaType()) { + case kUnpremul_SkAlphaType: + proc = &swizzle_bgra_to_n32_unpremul; + break; + case kPremul_SkAlphaType: + proc = &swizzle_bgra_to_n32_premul; + break; + default: + break; + } break; default: break; |