123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650 |
- /*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "include/core/SkStream.h"
- #include "include/private/SkColorData.h"
- #include "src/codec/SkBmpCodec.h"
- #include "src/codec/SkBmpMaskCodec.h"
- #include "src/codec/SkBmpRLECodec.h"
- #include "src/codec/SkBmpStandardCodec.h"
- #include "src/codec/SkCodecPriv.h"
- /*
- * Defines the version and type of the second bitmap header
- */
- enum BmpHeaderType {
- kInfoV1_BmpHeaderType,
- kInfoV2_BmpHeaderType,
- kInfoV3_BmpHeaderType,
- kInfoV4_BmpHeaderType,
- kInfoV5_BmpHeaderType,
- kOS2V1_BmpHeaderType,
- kOS2VX_BmpHeaderType,
- kUnknown_BmpHeaderType
- };
- /*
- * Possible bitmap compression types
- */
- enum BmpCompressionMethod {
- kNone_BmpCompressionMethod = 0,
- k8BitRLE_BmpCompressionMethod = 1,
- k4BitRLE_BmpCompressionMethod = 2,
- kBitMasks_BmpCompressionMethod = 3,
- kJpeg_BmpCompressionMethod = 4,
- kPng_BmpCompressionMethod = 5,
- kAlphaBitMasks_BmpCompressionMethod = 6,
- kCMYK_BmpCompressionMethod = 11,
- kCMYK8BitRLE_BmpCompressionMethod = 12,
- kCMYK4BitRLE_BmpCompressionMethod = 13
- };
- /*
- * Used to define the input format of the bmp
- */
- enum BmpInputFormat {
- kStandard_BmpInputFormat,
- kRLE_BmpInputFormat,
- kBitMask_BmpInputFormat,
- kUnknown_BmpInputFormat
- };
- /*
- * Checks the start of the stream to see if the image is a bitmap
- */
- bool SkBmpCodec::IsBmp(const void* buffer, size_t bytesRead) {
- // TODO: Support "IC", "PT", "CI", "CP", "BA"
- const char bmpSig[] = { 'B', 'M' };
- return bytesRead >= sizeof(bmpSig) && !memcmp(buffer, bmpSig, sizeof(bmpSig));
- }
- /*
- * Assumes IsBmp was called and returned true
- * Creates a bmp decoder
- * Reads enough of the stream to determine the image format
- */
- std::unique_ptr<SkCodec> SkBmpCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
- Result* result) {
- return SkBmpCodec::MakeFromStream(std::move(stream), result, false);
- }
- /*
- * Creates a bmp decoder for a bmp embedded in ico
- * Reads enough of the stream to determine the image format
- */
- std::unique_ptr<SkCodec> SkBmpCodec::MakeFromIco(std::unique_ptr<SkStream> stream, Result* result) {
- return SkBmpCodec::MakeFromStream(std::move(stream), result, true);
- }
- // Header size constants
- static constexpr uint32_t kBmpHeaderBytes = 14;
- static constexpr uint32_t kBmpHeaderBytesPlusFour = kBmpHeaderBytes + 4;
- static constexpr uint32_t kBmpOS2V1Bytes = 12;
- static constexpr uint32_t kBmpOS2V2Bytes = 64;
- static constexpr uint32_t kBmpInfoBaseBytes = 16;
- static constexpr uint32_t kBmpInfoV1Bytes = 40;
- static constexpr uint32_t kBmpInfoV2Bytes = 52;
- static constexpr uint32_t kBmpInfoV3Bytes = 56;
- static constexpr uint32_t kBmpInfoV4Bytes = 108;
- static constexpr uint32_t kBmpInfoV5Bytes = 124;
- static constexpr uint32_t kBmpMaskBytes = 12;
- static BmpHeaderType get_header_type(size_t infoBytes) {
- if (infoBytes >= kBmpInfoBaseBytes) {
- // Check the version of the header
- switch (infoBytes) {
- case kBmpInfoV1Bytes:
- return kInfoV1_BmpHeaderType;
- case kBmpInfoV2Bytes:
- return kInfoV2_BmpHeaderType;
- case kBmpInfoV3Bytes:
- return kInfoV3_BmpHeaderType;
- case kBmpInfoV4Bytes:
- return kInfoV4_BmpHeaderType;
- case kBmpInfoV5Bytes:
- return kInfoV5_BmpHeaderType;
- case 16:
- case 20:
- case 24:
- case 28:
- case 32:
- case 36:
- case 42:
- case 46:
- case 48:
- case 60:
- case kBmpOS2V2Bytes:
- return kOS2VX_BmpHeaderType;
- default:
- SkCodecPrintf("Error: unknown bmp header format.\n");
- return kUnknown_BmpHeaderType;
- }
- } if (infoBytes >= kBmpOS2V1Bytes) {
- // The OS2V1 is treated separately because it has a unique format
- return kOS2V1_BmpHeaderType;
- } else {
- // There are no valid bmp headers
- SkCodecPrintf("Error: second bitmap header size is invalid.\n");
- return kUnknown_BmpHeaderType;
- }
- }
- SkCodec::Result SkBmpCodec::ReadHeader(SkStream* stream, bool inIco,
- std::unique_ptr<SkCodec>* codecOut) {
- // The total bytes in the bmp file
- // We only need to use this value for RLE decoding, so we will only
- // check that it is valid in the RLE case.
- uint32_t totalBytes;
- // The offset from the start of the file where the pixel data begins
- uint32_t offset;
- // The size of the second (info) header in bytes
- uint32_t infoBytes;
- // Bmps embedded in Icos skip the first Bmp header
- if (!inIco) {
- // Read the first header and the size of the second header
- uint8_t hBuffer[kBmpHeaderBytesPlusFour];
- if (stream->read(hBuffer, kBmpHeaderBytesPlusFour) !=
- kBmpHeaderBytesPlusFour) {
- SkCodecPrintf("Error: unable to read first bitmap header.\n");
- return kIncompleteInput;
- }
- totalBytes = get_int(hBuffer, 2);
- offset = get_int(hBuffer, 10);
- if (offset < kBmpHeaderBytes + kBmpOS2V1Bytes) {
- SkCodecPrintf("Error: invalid starting location for pixel data\n");
- return kInvalidInput;
- }
- // The size of the second (info) header in bytes
- // The size is the first field of the second header, so we have already
- // read the first four infoBytes.
- infoBytes = get_int(hBuffer, 14);
- if (infoBytes < kBmpOS2V1Bytes) {
- SkCodecPrintf("Error: invalid second header size.\n");
- return kInvalidInput;
- }
- } else {
- // This value is only used by RLE compression. Bmp in Ico files do not
- // use RLE. If the compression field is incorrectly signaled as RLE,
- // we will catch this and signal an error below.
- totalBytes = 0;
- // Bmps in Ico cannot specify an offset. We will always assume that
- // pixel data begins immediately after the color table. This value
- // will be corrected below.
- offset = 0;
- // Read the size of the second header
- uint8_t hBuffer[4];
- if (stream->read(hBuffer, 4) != 4) {
- SkCodecPrintf("Error: unable to read size of second bitmap header.\n");
- return kIncompleteInput;
- }
- infoBytes = get_int(hBuffer, 0);
- if (infoBytes < kBmpOS2V1Bytes) {
- SkCodecPrintf("Error: invalid second header size.\n");
- return kInvalidInput;
- }
- }
- // Determine image information depending on second header format
- const BmpHeaderType headerType = get_header_type(infoBytes);
- if (kUnknown_BmpHeaderType == headerType) {
- return kInvalidInput;
- }
- // We already read the first four bytes of the info header to get the size
- const uint32_t infoBytesRemaining = infoBytes - 4;
- // Read the second header
- std::unique_ptr<uint8_t[]> iBuffer(new uint8_t[infoBytesRemaining]);
- if (stream->read(iBuffer.get(), infoBytesRemaining) != infoBytesRemaining) {
- SkCodecPrintf("Error: unable to read second bitmap header.\n");
- return kIncompleteInput;
- }
- // The number of bits used per pixel in the pixel data
- uint16_t bitsPerPixel;
- // The compression method for the pixel data
- uint32_t compression = kNone_BmpCompressionMethod;
- // Number of colors in the color table, defaults to 0 or max (see below)
- uint32_t numColors = 0;
- // Bytes per color in the color table, early versions use 3, most use 4
- uint32_t bytesPerColor;
- // The image width and height
- int width, height;
- switch (headerType) {
- case kInfoV1_BmpHeaderType:
- case kInfoV2_BmpHeaderType:
- case kInfoV3_BmpHeaderType:
- case kInfoV4_BmpHeaderType:
- case kInfoV5_BmpHeaderType:
- case kOS2VX_BmpHeaderType:
- // We check the size of the header before entering the if statement.
- // We should not reach this point unless the size is large enough for
- // these required fields.
- SkASSERT(infoBytesRemaining >= 12);
- width = get_int(iBuffer.get(), 0);
- height = get_int(iBuffer.get(), 4);
- bitsPerPixel = get_short(iBuffer.get(), 10);
- // Some versions do not have these fields, so we check before
- // overwriting the default value.
- if (infoBytesRemaining >= 16) {
- compression = get_int(iBuffer.get(), 12);
- if (infoBytesRemaining >= 32) {
- numColors = get_int(iBuffer.get(), 28);
- }
- }
- // All of the headers that reach this point, store color table entries
- // using 4 bytes per pixel.
- bytesPerColor = 4;
- break;
- case kOS2V1_BmpHeaderType:
- // The OS2V1 is treated separately because it has a unique format
- width = (int) get_short(iBuffer.get(), 0);
- height = (int) get_short(iBuffer.get(), 2);
- bitsPerPixel = get_short(iBuffer.get(), 6);
- bytesPerColor = 3;
- break;
- case kUnknown_BmpHeaderType:
- // We'll exit above in this case.
- SkASSERT(false);
- return kInvalidInput;
- }
- // Check for valid dimensions from header
- SkCodec::SkScanlineOrder rowOrder = SkCodec::kBottomUp_SkScanlineOrder;
- if (height < 0) {
- // We can't negate INT32_MIN.
- if (height == INT32_MIN) {
- return kInvalidInput;
- }
- height = -height;
- rowOrder = SkCodec::kTopDown_SkScanlineOrder;
- }
- // The height field for bmp in ico is double the actual height because they
- // contain an XOR mask followed by an AND mask
- if (inIco) {
- height /= 2;
- }
- // Arbitrary maximum. Matches Chromium.
- constexpr int kMaxDim = 1 << 16;
- if (width <= 0 || height <= 0 || width >= kMaxDim || height >= kMaxDim) {
- SkCodecPrintf("Error: invalid bitmap dimensions.\n");
- return kInvalidInput;
- }
- // Create mask struct
- SkMasks::InputMasks inputMasks;
- memset(&inputMasks, 0, sizeof(SkMasks::InputMasks));
- // Determine the input compression format and set bit masks if necessary
- uint32_t maskBytes = 0;
- BmpInputFormat inputFormat = kUnknown_BmpInputFormat;
- 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) {
- SkCodecPrintf("Warning: correcting invalid bitmap format.\n");
- bitsPerPixel = 8;
- }
- inputFormat = kRLE_BmpInputFormat;
- break;
- case k4BitRLE_BmpCompressionMethod:
- if (bitsPerPixel != 4) {
- SkCodecPrintf("Warning: correcting invalid bitmap format.\n");
- bitsPerPixel = 4;
- }
- inputFormat = kRLE_BmpInputFormat;
- break;
- case kAlphaBitMasks_BmpCompressionMethod:
- case kBitMasks_BmpCompressionMethod:
- // Load the masks
- inputFormat = kBitMask_BmpInputFormat;
- switch (headerType) {
- case kInfoV1_BmpHeaderType: {
- // The V1 header stores the bit masks after the header
- uint8_t buffer[kBmpMaskBytes];
- if (stream->read(buffer, kBmpMaskBytes) != kBmpMaskBytes) {
- SkCodecPrintf("Error: unable to read bit inputMasks.\n");
- return kIncompleteInput;
- }
- maskBytes = kBmpMaskBytes;
- inputMasks.red = get_int(buffer, 0);
- inputMasks.green = get_int(buffer, 4);
- inputMasks.blue = get_int(buffer, 8);
- break;
- }
- case kInfoV2_BmpHeaderType:
- case kInfoV3_BmpHeaderType:
- case kInfoV4_BmpHeaderType:
- case kInfoV5_BmpHeaderType:
- // Header types are matched based on size. If the header
- // is V2+, we are guaranteed to be able to read at least
- // this size.
- SkASSERT(infoBytesRemaining >= 48);
- 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.
- // It is unsupported in the previous version and
- // in chromium. I have not come across a test case
- // that uses this format.
- SkCodecPrintf("Error: huffman format unsupported.\n");
- return kUnimplemented;
- default:
- SkCodecPrintf("Error: invalid bmp bit masks header.\n");
- return kInvalidInput;
- }
- break;
- case kJpeg_BmpCompressionMethod:
- if (24 == bitsPerPixel) {
- inputFormat = kRLE_BmpInputFormat;
- break;
- }
- // Fall through
- case kPng_BmpCompressionMethod:
- // TODO: Decide if we intend to support this.
- // It is unsupported in the previous version and
- // in chromium. I think it is used mostly for printers.
- SkCodecPrintf("Error: compression format not supported.\n");
- return kUnimplemented;
- case kCMYK_BmpCompressionMethod:
- case kCMYK8BitRLE_BmpCompressionMethod:
- case kCMYK4BitRLE_BmpCompressionMethod:
- // TODO: Same as above.
- SkCodecPrintf("Error: CMYK not supported for bitmap decoding.\n");
- return kUnimplemented;
- default:
- SkCodecPrintf("Error: invalid format for bitmap decoding.\n");
- return kInvalidInput;
- }
- iBuffer.reset();
- // Calculate the number of bytes read so far
- const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes;
- if (!inIco && offset < bytesRead) {
- // TODO (msarett): Do we really want to fail if the offset in the header is invalid?
- // Seems like we can just assume that the offset is zero and try to decode?
- // Maybe we don't want to try to decode corrupt images?
- SkCodecPrintf("Error: pixel data offset less than header size.\n");
- return kInvalidInput;
- }
- switch (inputFormat) {
- case kStandard_BmpInputFormat: {
- // BMPs are generally opaque, however BMPs-in-ICOs may contain
- // a transparency mask after the image. Therefore, we mark the
- // alpha as kBinary if the BMP is contained in an ICO.
- // We use |isOpaque| to indicate if the BMP itself is opaque.
- SkEncodedInfo::Alpha alpha = inIco ? SkEncodedInfo::kBinary_Alpha :
- SkEncodedInfo::kOpaque_Alpha;
- bool isOpaque = true;
- SkEncodedInfo::Color color;
- uint8_t bitsPerComponent;
- switch (bitsPerPixel) {
- // Palette formats
- case 1:
- case 2:
- case 4:
- case 8:
- // In the case of ICO, kBGRA is actually the closest match,
- // since we will need to apply a transparency mask.
- if (inIco) {
- color = SkEncodedInfo::kBGRA_Color;
- bitsPerComponent = 8;
- } else {
- color = SkEncodedInfo::kPalette_Color;
- bitsPerComponent = (uint8_t) bitsPerPixel;
- }
- break;
- case 24:
- // In the case of ICO, kBGRA is actually the closest match,
- // since we will need to apply a transparency mask.
- color = inIco ? SkEncodedInfo::kBGRA_Color : SkEncodedInfo::kBGR_Color;
- bitsPerComponent = 8;
- break;
- case 32:
- // 32-bit BMP-in-ICOs actually use the alpha channel in place of a
- // transparency mask.
- if (inIco) {
- isOpaque = false;
- alpha = SkEncodedInfo::kUnpremul_Alpha;
- color = SkEncodedInfo::kBGRA_Color;
- } else {
- color = SkEncodedInfo::kBGRX_Color;
- }
- bitsPerComponent = 8;
- break;
- default:
- SkCodecPrintf("Error: invalid input value for bits per pixel.\n");
- return kInvalidInput;
- }
- 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.
- auto info = SkEncodedInfo::Make(width, height, color, alpha, bitsPerComponent);
- codecOut->reset(new SkBmpStandardCodec(std::move(info),
- std::unique_ptr<SkStream>(stream),
- bitsPerPixel, numColors, bytesPerColor,
- offset - bytesRead, rowOrder, isOpaque,
- inIco));
- return static_cast<SkBmpStandardCodec*>(codecOut->get())->didCreateSrcBuffer()
- ? kSuccess : kInvalidInput;
- }
- return kSuccess;
- }
- case kBitMask_BmpInputFormat: {
- // Bmp-in-Ico must be standard mode
- if (inIco) {
- SkCodecPrintf("Error: Icos may not use bit mask format.\n");
- return kInvalidInput;
- }
- switch (bitsPerPixel) {
- case 16:
- case 24:
- case 32:
- break;
- default:
- SkCodecPrintf("Error: invalid input value for bits per pixel.\n");
- return kInvalidInput;
- }
- // 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 kIncompleteInput;
- }
- if (codecOut) {
- // Check that input bit masks are valid and create the masks object
- SkASSERT(bitsPerPixel % 8 == 0);
- std::unique_ptr<SkMasks> masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel/8));
- if (nullptr == masks) {
- SkCodecPrintf("Error: invalid input masks.\n");
- return kInvalidInput;
- }
- // Masked bmps are not a great fit for SkEncodedInfo, since they have
- // arbitrary component orderings and bits per component. Here we choose
- // somewhat reasonable values - it's ok that we don't match exactly
- // because SkBmpMaskCodec has its own mask swizzler anyway.
- SkEncodedInfo::Color color;
- SkEncodedInfo::Alpha alpha;
- if (masks->getAlphaMask()) {
- color = SkEncodedInfo::kBGRA_Color;
- alpha = SkEncodedInfo::kUnpremul_Alpha;
- } else {
- color = SkEncodedInfo::kBGR_Color;
- alpha = SkEncodedInfo::kOpaque_Alpha;
- }
- auto info = SkEncodedInfo::Make(width, height, color, alpha, 8);
- codecOut->reset(new SkBmpMaskCodec(std::move(info),
- std::unique_ptr<SkStream>(stream), bitsPerPixel,
- masks.release(), rowOrder));
- return static_cast<SkBmpMaskCodec*>(codecOut->get())->didCreateSrcBuffer()
- ? kSuccess : kInvalidInput;
- }
- return kSuccess;
- }
- 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 kInvalidInput;
- }
- // 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 or that we will be able to represent it with a palette.
- // For that reason, we always indicate that we are kBGRA.
- auto info = SkEncodedInfo::Make(width, height, SkEncodedInfo::kBGRA_Color,
- SkEncodedInfo::kBinary_Alpha, 8);
- codecOut->reset(new SkBmpRLECodec(std::move(info),
- std::unique_ptr<SkStream>(stream), bitsPerPixel,
- numColors, bytesPerColor, offset - bytesRead,
- rowOrder));
- }
- return kSuccess;
- }
- default:
- SkASSERT(false);
- return kInvalidInput;
- }
- }
- /*
- * Creates a bmp decoder
- * Reads enough of the stream to determine the image format
- */
- std::unique_ptr<SkCodec> SkBmpCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
- Result* result, bool inIco) {
- std::unique_ptr<SkCodec> codec;
- *result = ReadHeader(stream.get(), inIco, &codec);
- if (codec) {
- // codec has taken ownership of stream, so we do not need to delete it.
- stream.release();
- }
- return kSuccess == *result ? std::move(codec) : nullptr;
- }
- SkBmpCodec::SkBmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
- uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
- : INHERITED(std::move(info), kXformSrcColorFormat, std::move(stream))
- , fBitsPerPixel(bitsPerPixel)
- , fRowOrder(rowOrder)
- , fSrcRowBytes(SkAlign4(compute_row_bytes(this->dimensions().width(), fBitsPerPixel)))
- , fXformBuffer(nullptr)
- {}
- bool SkBmpCodec::onRewind() {
- return SkBmpCodec::ReadHeader(this->stream(), this->inIco(), nullptr) == kSuccess;
- }
- int32_t SkBmpCodec::getDstRow(int32_t y, int32_t height) const {
- if (SkCodec::kTopDown_SkScanlineOrder == fRowOrder) {
- return y;
- }
- SkASSERT(SkCodec::kBottomUp_SkScanlineOrder == fRowOrder);
- return height - y - 1;
- }
- SkCodec::Result SkBmpCodec::prepareToDecode(const SkImageInfo& dstInfo,
- const SkCodec::Options& options) {
- return this->onPrepareToDecode(dstInfo, options);
- }
- SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
- const SkCodec::Options& options) {
- return prepareToDecode(dstInfo, options);
- }
- int SkBmpCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
- // Create a new image info representing the portion of the image to decode
- SkImageInfo rowInfo = this->dstInfo().makeWH(this->dstInfo().width(), count);
- // Decode the requested rows
- return this->decodeRows(rowInfo, dst, rowBytes, this->options());
- }
- bool SkBmpCodec::skipRows(int count) {
- const size_t bytesToSkip = count * fSrcRowBytes;
- return this->stream()->skip(bytesToSkip) == bytesToSkip;
- }
- bool SkBmpCodec::onSkipScanlines(int count) {
- return this->skipRows(count);
- }
|