/* * Performs the decoding */ SkCodec::Result SkBmpMaskCodec::decode(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts) { // Set constant values const int width = dstInfo.width(); const int height = dstInfo.height(); const size_t rowBytes = SkAlign4(compute_row_bytes(width, this->bitsPerPixel())); // Iterate over rows of the image uint8_t* srcRow = fSrcBuffer.get(); for (int y = 0; y < height; y++) { // Read a row of the input if (this->stream()->read(srcRow, rowBytes) != rowBytes) { SkCodecPrintf("Warning: incomplete input stream.\n"); // Fill the destination image on failure SkPMColor fillColor = dstInfo.alphaType() == kOpaque_SkAlphaType ? SK_ColorBLACK : SK_ColorTRANSPARENT; if (kNo_ZeroInitialized == opts.fZeroInitialized || 0 != fillColor) { void* dstStart = this->getDstStartRow(dst, dstRowBytes, y); SkSwizzler::Fill(dstStart, dstInfo, dstRowBytes, dstInfo.height() - y, fillColor, nullptr); } return kIncompleteInput; } // Decode the row in destination format int row = SkBmpCodec::kBottomUp_RowOrder == this->rowOrder() ? height - 1 - y : y; void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); fMaskSwizzler->swizzle(dstRow, srcRow); } // Finished decoding the entire image return kSuccess; }
SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder) : INHERITED(info, stream) , fBitsPerPixel(bitsPerPixel) , fRowOrder(rowOrder) , fSrcRowBytes(SkAlign4(compute_row_bytes(info.width(), fBitsPerPixel))) {}
bool SkBmpMaskCodec::initializeSwizzler(const SkImageInfo& dstInfo) { // Allocate space for a row buffer const size_t rowBytes = SkAlign4(compute_row_bytes(dstInfo.width(), this->bitsPerPixel())); fSrcBuffer.reset(new uint8_t[rowBytes]); // Create the swizzler fMaskSwizzler.reset(SkMaskSwizzler::CreateMaskSwizzler( dstInfo, fMasks, this->bitsPerPixel())); if (nullptr == fMaskSwizzler.get()) { return false; } return true; }
/* * Performs the bitmap decoding for RLE input format * RLE decoding is performed all at once, rather than a one row at a time */ SkCodec::Result SkBmpRLECodec::decode(const SkImageInfo& dstInfo, 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; static const uint8_t RLE_EOF = 1; static const uint8_t RLE_DELTA = 2; // Set constant values const int width = dstInfo.width(); const int height = dstInfo.height(); // Destination parameters int x = 0; int y = 0; // 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, height, SK_ColorTRANSPARENT, NULL); } while (true) { // If we have reached a row that is beyond the requested height, we have // succeeded. if (y >= height) { // It would be better to check for the EOF marker before returning // success, but we may be performing a scanline decode, which // may require us to stop before decoding the full height. return kSuccess; } // Every entry takes at least two bytes if ((int) fRLEBytes - fCurrRLEByte < 2) { SkCodecPrintf("Warning: might be incomplete RLE input.\n"); if (this->checkForMoreData() < 2) { return kIncompleteInput; } } // Read the next two bytes. These bytes have different meanings // depending on their values. In the first interpretation, the first // byte is an escape flag and the second byte indicates what special // task to perform. const uint8_t flag = fStreamBuffer.get()[fCurrRLEByte++]; const uint8_t task = fStreamBuffer.get()[fCurrRLEByte++]; // Perform decoding if (RLE_ESCAPE == flag) { switch (task) { case RLE_EOL: x = 0; y++; break; case RLE_EOF: return kSuccess; case RLE_DELTA: { // Two bytes are needed to specify delta if ((int) fRLEBytes - fCurrRLEByte < 2) { SkCodecPrintf("Warning: might be incomplete RLE input.\n"); if (this->checkForMoreData() < 2) { return kIncompleteInput; } } // Modify x and y const uint8_t dx = fStreamBuffer.get()[fCurrRLEByte++]; const uint8_t dy = fStreamBuffer.get()[fCurrRLEByte++]; x += dx; y += dy; if (x > width || y > height) { SkCodecPrintf("Warning: invalid RLE input.\n"); return kInvalidInput; } break; } default: { // If task does not match any of the above signals, it // indicates that we have a sequence of non-RLE pixels. // Furthermore, the value of task is equal to the number // of pixels to interpret. uint8_t numPixels = task; const size_t rowBytes = compute_row_bytes(numPixels, this->bitsPerPixel()); // Abort if setting numPixels moves us off the edge of the // image. if (x + numPixels > width) { SkCodecPrintf("Warning: invalid RLE input.\n"); return kInvalidInput; } // Also abort if there are not enough bytes // remaining in the stream to set numPixels. if ((int) fRLEBytes - fCurrRLEByte < SkAlign2(rowBytes)) { SkCodecPrintf("Warning: might be incomplete RLE input.\n"); if (this->checkForMoreData() < SkAlign2(rowBytes)) { return kIncompleteInput; } } // Set numPixels number of pixels while (numPixels > 0) { switch(this->bitsPerPixel()) { case 4: { SkASSERT(fCurrRLEByte < fRLEBytes); uint8_t val = fStreamBuffer.get()[fCurrRLEByte++]; setPixel(dst, dstRowBytes, dstInfo, x++, y, val >> 4); numPixels--; if (numPixels != 0) { setPixel(dst, dstRowBytes, dstInfo, x++, y, val & 0xF); numPixels--; } break; } case 8: SkASSERT(fCurrRLEByte < fRLEBytes); setPixel(dst, dstRowBytes, dstInfo, x++, y, fStreamBuffer.get()[fCurrRLEByte++]); numPixels--; break; case 24: { SkASSERT(fCurrRLEByte + 2 < fRLEBytes); uint8_t blue = fStreamBuffer.get()[fCurrRLEByte++]; uint8_t green = fStreamBuffer.get()[fCurrRLEByte++]; uint8_t red = fStreamBuffer.get()[fCurrRLEByte++]; setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, blue); numPixels--; } default: SkASSERT(false); return kInvalidInput; } } // Skip a byte if necessary to maintain alignment if (!SkIsAlign2(rowBytes)) { fCurrRLEByte++; } break; } } } else { // If the first byte read is not a flag, it indicates the number of // pixels to set in RLE mode. const uint8_t numPixels = flag; const int endX = SkTMin<int>(x + numPixels, width); if (24 == this->bitsPerPixel()) { // In RLE24, the second byte read is part of the pixel color. // There are two more required bytes to finish encoding the // color. if ((int) fRLEBytes - fCurrRLEByte < 2) { SkCodecPrintf("Warning: might be incomplete RLE input.\n"); if (this->checkForMoreData() < 2) { return kIncompleteInput; } } // Fill the pixels up to endX with the specified color uint8_t blue = task; uint8_t green = fStreamBuffer.get()[fCurrRLEByte++]; uint8_t red = fStreamBuffer.get()[fCurrRLEByte++]; while (x < endX) { setRGBPixel(dst, dstRowBytes, dstInfo, x++, y, red, green, blue); } } else { // In RLE8 or RLE4, the second byte read gives the index in the // color table to look up the pixel color. // RLE8 has one color index that gets repeated // RLE4 has two color indexes in the upper and lower 4 bits of // the bytes, which are alternated uint8_t indices[2] = { task, task }; if (4 == this->bitsPerPixel()) { indices[0] >>= 4; indices[1] &= 0xf; } // Set the indicated number of pixels for (int which = 0; x < endX; x++) { setPixel(dst, dstRowBytes, dstInfo, x, y, indices[which]); which = !which; } } }