| Index: src/codec/SkBmpCodec.cpp
|
| diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp
|
| index e327f790187fc434aad4317b78e1f9650c40d294..ad6f0ddc4d5312b6e28e19ccb8b0655325c63bf9 100644
|
| --- a/src/codec/SkBmpCodec.cpp
|
| +++ b/src/codec/SkBmpCodec.cpp
|
| @@ -286,6 +286,18 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) {
|
| switch (compression) {
|
| case kNone_BmpCompressionMethod:
|
| inputFormat = kStandard_BmpInputFormat;
|
| +
|
| + // In addition to more standard pixel compression formats, bmp supports
|
| + // the use of bit masks to determine pixel components. The standard
|
| + // format for representing 16-bit colors is 555 (XRRRRRGGGGGBBBBB),
|
| + // which does not map well to any Skia color formats. For this reason,
|
| + // we will always enable mask mode with 16 bits per pixel.
|
| + if (16 == bitsPerPixel) {
|
| + inputMasks.red = 0x7C00;
|
| + inputMasks.green = 0x03E0;
|
| + inputMasks.blue = 0x001F;
|
| + inputFormat = kBitMask_BmpInputFormat;
|
| + }
|
| break;
|
| case k8BitRLE_BmpCompressionMethod:
|
| if (bitsPerPixel != 8) {
|
| @@ -331,6 +343,27 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) {
|
| inputMasks.red = get_int(iBuffer.get(), 36);
|
| inputMasks.green = get_int(iBuffer.get(), 40);
|
| inputMasks.blue = get_int(iBuffer.get(), 44);
|
| +
|
| + if (kInfoV2_BmpHeaderType == headerType ||
|
| + (kInfoV3_BmpHeaderType == headerType && !inIco)) {
|
| + break;
|
| + }
|
| +
|
| + // V3+ bmp files introduce an alpha mask and allow the creator of the image
|
| + // to use the alpha channels. However, many of these images leave the
|
| + // alpha channel blank and expect to be rendered as opaque. This is the
|
| + // case for almost all V3 images, so we ignore the alpha mask. For V4+
|
| + // images in kMask mode, we will use the alpha mask. Additionally, V3
|
| + // bmp-in-ico expect us to use the alpha mask.
|
| + //
|
| + // skbug.com/4116: We should perhaps also apply the alpha mask in kStandard
|
| + // mode. We just haven't seen any images that expect this
|
| + // behavior.
|
| + //
|
| + // Header types are matched based on size. If the header is
|
| + // V3+, we are guaranteed to be able to read at least this size.
|
| + SkASSERT(infoBytesRemaining > 52);
|
| + inputMasks.alpha = get_int(iBuffer.get(), 48);
|
| break;
|
| case kOS2VX_BmpHeaderType:
|
| // TODO: Decide if we intend to support this.
|
| @@ -366,101 +399,8 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) {
|
| SkCodecPrintf("Error: invalid format for bitmap decoding.\n");
|
| return false;
|
| }
|
| -
|
| - // Most versions of bmps should be rendered as opaque. Either they do
|
| - // not have an alpha channel, or they expect the alpha channel to be
|
| - // ignored. V3+ bmp files introduce an alpha mask and allow the creator
|
| - // of the image to use the alpha channels. However, many of these images
|
| - // leave the alpha channel blank and expect to be rendered as opaque. This
|
| - // is the case for almost all V3 images, so we render these as opaque. For
|
| - // V4+ images in kMask mode, we will use the alpha mask.
|
| - //
|
| - // skbug.com/4116: We should perhaps also apply the alpha mask in kStandard
|
| - // mode. We just haven't seen any images that expect this
|
| - // behavior.
|
| - //
|
| - // Additionally, V3 bmp-in-ico may use the alpha mask.
|
| - SkAlphaType alphaType = kOpaque_SkAlphaType;
|
| - if ((kInfoV3_BmpHeaderType == headerType && inIco) ||
|
| - kInfoV4_BmpHeaderType == headerType ||
|
| - kInfoV5_BmpHeaderType == headerType) {
|
| - // Header types are matched based on size. If the header is
|
| - // V3+, we are guaranteed to be able to read at least this size.
|
| - SkASSERT(infoBytesRemaining > 52);
|
| - inputMasks.alpha = get_int(iBuffer.get(), 48);
|
| - if (inputMasks.alpha != 0) {
|
| - alphaType = kUnpremul_SkAlphaType;
|
| - }
|
| - }
|
| iBuffer.reset();
|
|
|
| - // Additionally, 32 bit bmp-in-icos use the alpha channel.
|
| - // FIXME (msarett): Don't all 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 ((inIco && 32 == bitsPerPixel) || (kRLE_BmpInputFormat == inputFormat)) {
|
| - alphaType = kUnpremul_SkAlphaType;
|
| - }
|
| -
|
| - // 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
|
| - // format for representing 16-bit colors is 555 (XRRRRRGGGGGBBBBB),
|
| - // which does not map well to any Skia color formats. For this reason,
|
| - // we will always enable mask mode with 16 bits per pixel.
|
| - case 16:
|
| - if (kBitMask_BmpInputFormat != inputFormat) {
|
| - inputMasks.red = 0x7C00;
|
| - inputMasks.green = 0x03E0;
|
| - inputMasks.blue = 0x001F;
|
| - inputFormat = kBitMask_BmpInputFormat;
|
| - }
|
| - 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_BmpInputFormat != inputFormat && !inIco) {
|
| - colorType = kIndex_8_SkColorType;
|
| - }
|
| -
|
| - // Mask bmps must have 16, 24, or 32 bits per pixel.
|
| - if (kBitMask_BmpInputFormat == inputFormat) {
|
| - SkCodecPrintf("Error: invalid input value of bits per pixel for mask bmp.\n");
|
| - return false;
|
| - }
|
| - case 24:
|
| - case 32:
|
| - break;
|
| - default:
|
| - SkCodecPrintf("Error: invalid input value for bits per pixel.\n");
|
| - return false;
|
| - }
|
| -
|
| - // Check that input bit masks are valid and create the masks object
|
| - SkAutoTDelete<SkMasks>
|
| - masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel));
|
| - if (nullptr == masks) {
|
| - SkCodecPrintf("Error: invalid input masks.\n");
|
| - return false;
|
| - }
|
| -
|
| - // Check for a valid number of total bytes when in RLE mode
|
| - if (totalBytes <= offset && kRLE_BmpInputFormat == inputFormat) {
|
| - SkCodecPrintf("Error: RLE requires valid input size.\n");
|
| - return false;
|
| - }
|
| - const size_t RLEBytes = totalBytes - offset;
|
| -
|
| // Calculate the number of bytes read so far
|
| const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes;
|
| if (!inIco && offset < bytesRead) {
|
| @@ -471,63 +411,133 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) {
|
| return false;
|
| }
|
|
|
| - // Skip to the start of the pixel array.
|
| - // We can do this here because there is no color table to read
|
| - // in bit mask mode.
|
| - if (!inIco && kBitMask_BmpInputFormat == inputFormat) {
|
| - if (stream->skip(offset - bytesRead) != offset - bytesRead) {
|
| - SkCodecPrintf("Error: unable to skip to image data.\n");
|
| - return false;
|
| - }
|
| - }
|
|
|
| - if (codecOut) {
|
| - // BMPs-in-ICOs contain an alpha mask after the image which means we
|
| - // cannot guarantee that an image is opaque, even if the bmp thinks
|
| - // it is.
|
| - bool isOpaque = kOpaque_SkAlphaType == alphaType;
|
| - if (inIco) {
|
| - alphaType = kUnpremul_SkAlphaType;
|
| - }
|
|
|
| - // Set the image info
|
| - const SkImageInfo& imageInfo = SkImageInfo::Make(width, height,
|
| - colorType, alphaType);
|
| + switch (inputFormat) {
|
| + case kStandard_BmpInputFormat: {
|
| + // BMPs-in-ICOs often contain an alpha mask after the image, which
|
| + // means we cannot guarantee that an image is opaque, even if the
|
| + // embedded bmp is opaque.
|
| + // We use |isOpaque| to indicate if the BMP itself is opaque, but
|
| + // still need to recommend kUnpremul when it is contained in an ICO.
|
| + SkColorType colorType = kN32_SkColorType;
|
| + SkAlphaType alphaType = inIco ? kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
|
| + bool isOpaque = true;
|
| + switch (bitsPerPixel) {
|
| + // Palette formats
|
| + case 1:
|
| + case 2:
|
| + case 4:
|
| + case 8:
|
| + // We cannot recommend a palette color type for ICOs because they
|
| + // may contain a transparency mask.
|
| + if (!inIco) {
|
| + colorType = kIndex_8_SkColorType;
|
| + }
|
| + break;
|
| + case 24:
|
| + case 32:
|
| + // 32-bit BMP-in-ICOs actually use the alpha channel in place of a
|
| + // transparency mask.
|
| + if (inIco) {
|
| + isOpaque = false;
|
| + }
|
| + break;
|
| + default:
|
| + SkCodecPrintf("Error: invalid input value for bits per pixel.\n");
|
| + return false;
|
| + }
|
|
|
| - // Return the codec
|
| - switch (inputFormat) {
|
| - case kStandard_BmpInputFormat:
|
| + if (codecOut) {
|
| // We require streams to have a memory base for Bmp-in-Ico decodes.
|
| SkASSERT(!inIco || nullptr != stream->getMemoryBase());
|
| +
|
| + // Set the image info and create a codec.
|
| + const SkImageInfo imageInfo = SkImageInfo::Make(width, height, colorType,
|
| + alphaType);
|
| *codecOut = new SkBmpStandardCodec(imageInfo, stream, bitsPerPixel, numColors,
|
| bytesPerColor, offset - bytesRead, rowOrder, isOpaque, inIco);
|
| - return true;
|
| - case kBitMask_BmpInputFormat:
|
| - // Bmp-in-Ico must be standard mode
|
| - if (inIco) {
|
| - SkCodecPrintf("Error: Icos may not use bit mask format.\n");
|
| +
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + case kBitMask_BmpInputFormat: {
|
| + // Bmp-in-Ico must be standard mode
|
| + if (inIco) {
|
| + SkCodecPrintf("Error: Icos may not use bit mask format.\n");
|
| + return false;
|
| + }
|
| +
|
| + switch (bitsPerPixel) {
|
| + case 16:
|
| + case 24:
|
| + case 32:
|
| + break;
|
| + default:
|
| + SkCodecPrintf("Error: invalid input value for bits per pixel.\n");
|
| + return false;
|
| + }
|
| +
|
| + // Skip to the start of the pixel array.
|
| + // We can do this here because there is no color table to read
|
| + // in bit mask mode.
|
| + if (stream->skip(offset - bytesRead) != offset - bytesRead) {
|
| + SkCodecPrintf("Error: unable to skip to image data.\n");
|
| + return false;
|
| + }
|
| +
|
| + if (codecOut) {
|
| + // Check that input bit masks are valid and create the masks object
|
| + SkAutoTDelete<SkMasks> masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel));
|
| + if (nullptr == masks) {
|
| + SkCodecPrintf("Error: invalid input masks.\n");
|
| return false;
|
| }
|
|
|
| + // Set the image info
|
| + SkAlphaType alphaType = masks->getAlphaMask() ? kUnpremul_SkAlphaType :
|
| + kOpaque_SkAlphaType;
|
| + const SkImageInfo imageInfo = SkImageInfo::Make(width, height, kN32_SkColorType,
|
| + alphaType);
|
| *codecOut = new SkBmpMaskCodec(imageInfo, stream, bitsPerPixel, masks.release(),
|
| rowOrder);
|
| - return true;
|
| - case kRLE_BmpInputFormat:
|
| - // Bmp-in-Ico must be standard mode
|
| - // When inIco is true, this line cannot be reached, since we
|
| - // require that RLE Bmps have a valid number of totalBytes, and
|
| - // Icos skip the header that contains totalBytes.
|
| - SkASSERT(!inIco);
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + case kRLE_BmpInputFormat: {
|
| + // We should not reach this point without a valid value of bitsPerPixel.
|
| + SkASSERT(4 == bitsPerPixel || 8 == bitsPerPixel || 24 == bitsPerPixel);
|
| +
|
| + // Check for a valid number of total bytes when in RLE mode
|
| + if (totalBytes <= offset) {
|
| + SkCodecPrintf("Error: RLE requires valid input size.\n");
|
| + return false;
|
| + }
|
| + const size_t RLEBytes = totalBytes - offset;
|
| +
|
| + // Bmp-in-Ico must be standard mode
|
| + // When inIco is true, this line cannot be reached, since we
|
| + // require that RLE Bmps have a valid number of totalBytes, and
|
| + // Icos skip the header that contains totalBytes.
|
| + SkASSERT(!inIco);
|
| +
|
| + if (codecOut) {
|
| + // RLE inputs may skip pixels, leaving them as transparent. This
|
| + // is uncommon, but we cannot be certain that an RLE bmp will be
|
| + // opaque.
|
| + const SkImageInfo imageInfo = SkImageInfo::Make(width, height, kN32_SkColorType,
|
| + kUnpremul_SkAlphaType);
|
| *codecOut = new SkBmpRLECodec(imageInfo, stream, bitsPerPixel, numColors,
|
| bytesPerColor, offset - bytesRead, rowOrder, RLEBytes);
|
| - return true;
|
| - default:
|
| - SkASSERT(false);
|
| - return false;
|
| + }
|
| + return true;
|
| }
|
| + default:
|
| + SkASSERT(false);
|
| + return false;
|
| }
|
| -
|
| - return true;
|
| }
|
|
|
| /*
|
|
|