Пример #1
0
/*
 * 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;
}
Пример #2
0
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)))
{}
Пример #3
0
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;
}
Пример #4
0
/*
 * 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;
                }
            }
        }