Exemple #1
0
/*
 * Initiates the bitmap decode
 */
SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo,
                                            void* dst, size_t dstRowBytes,
                                            const Options& opts,
                                            SkPMColor* inputColorPtr,
                                            int* inputColorCount) {
    if (!this->rewindIfNeeded()) {
        return kCouldNotRewind;
    }
    if (opts.fSubset) {
        // Subsets are not supported.
        return kUnimplemented;
    }
    if (dstInfo.dimensions() != this->getInfo().dimensions()) {
        SkCodecPrintf("Error: scaling not supported.\n");
        return kInvalidScale;
    }

    if (!conversion_possible(dstInfo, this->getInfo())) {
        SkCodecPrintf("Error: cannot convert input type to output type.\n");
        return kInvalidConversion;
    }

    // Initialize a the mask swizzler
    if (!this->initializeSwizzler(dstInfo)) {
        SkCodecPrintf("Error: cannot initialize swizzler.\n");
        return kInvalidConversion;
    }

    return this->decode(dstInfo, dst, dstRowBytes, opts);
}
Exemple #2
0
SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
        const Options& options, SkPMColor ctable[], int* ctableCount) {
    // Set the jump location for libjpeg errors
    if (setjmp(fDecoderMgr->getJmpBuf())) {
        SkCodecPrintf("setjmp: Error from libjpeg\n");
        return kInvalidInput;
    }

    // Check if we can decode to the requested destination and set the output color space
    if (!this->setOutputColorSpace(dstInfo)) {
        return kInvalidConversion;
    }

    // Remove objects used for sampling.
    fSwizzler.reset(nullptr);
    fSrcRow = nullptr;
    fStorage.free();

    // Now, given valid output dimensions, we can start the decompress
    if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
        SkCodecPrintf("start decompress failed\n");
        return kInvalidInput;
    }

    // We will need a swizzler if we are performing a subset decode or
    // converting from CMYK.
    if (options.fSubset || JCS_CMYK == fDecoderMgr->dinfo()->out_color_space) {
        this->initializeSwizzler(dstInfo, options);
    }

    return kSuccess;
}
Exemple #3
0
/*
 * Initiates the Ico decode
 */
SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo,
                                        void* dst, size_t dstRowBytes,
                                        const Options& opts, SkPMColor* ct,
                                        int* ptr) {
    if (opts.fSubset) {
        // Subsets are not supported.
        return kUnimplemented;
    }
    // We return invalid scale if there is no candidate image with matching
    // dimensions.
    Result result = kInvalidScale;
    for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) {
        // If the dimensions match, try to decode
        if (dstInfo.dimensions() ==
                fEmbeddedCodecs->operator[](i)->getInfo().dimensions()) {

            // Perform the decode
            result = fEmbeddedCodecs->operator[](i)->getPixels(dstInfo,
                    dst, dstRowBytes, &opts, ct, ptr);

            // On a fatal error, keep trying to find an image to decode
            if (kInvalidConversion == result || kInvalidInput == result ||
                    kInvalidScale == result) {
                SkCodecPrintf("Warning: Attempt to decode candidate ico failed.\n");
                continue;
            }

            // On success or partial success, return the result
            return result;
        }
    }

    SkCodecPrintf("Error: No matching candidate image in ico.\n");
    return result;
}
Exemple #4
0
/*
 * Initiates the bitmap decode
 */
SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo,
                                            void* dst, size_t dstRowBytes,
                                            const Options& opts,
                                            SkPMColor* inputColorPtr,
                                            int* inputColorCount,
                                            int* rowsDecoded) {
    if (opts.fSubset) {
        // Subsets are not supported.
        return kUnimplemented;
    }
    if (dstInfo.dimensions() != this->getInfo().dimensions()) {
        SkCodecPrintf("Error: scaling not supported.\n");
        return kInvalidScale;
    }

    if (!conversion_possible(dstInfo, this->getInfo())) {
        SkCodecPrintf("Error: cannot convert input type to output type.\n");
        return kInvalidConversion;
    }

    Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount);
    if (kSuccess != result) {
        return result;
    }

    int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts);
    if (rows != dstInfo.height()) {
        *rowsDecoded = rows;
        return kIncompleteInput;
    }
    return kSuccess;
}
SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo,
        const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) {
    // FIXME: Support subsets for scanline decodes.
    if (options.fSubset) {
        // Subsets are not supported.
        return kUnimplemented;
    }

    // Reset fSampleX. If it needs to be a value other than 1, it will get modified by
    // the sampler.
    fSampleX = 1;
    fLinesToSkip = 0;

    // Create the color table if necessary and prepare the stream for decode
    // Note that if it is non-NULL, inputColorCount will be modified
    if (!this->createColorTable(dstInfo.colorType(), inputColorCount)) {
        SkCodecPrintf("Error: could not create color table.\n");
        return SkCodec::kInvalidInput;
    }

    // Copy the color table to the client if necessary
    copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount);

    // Initialize a buffer for encoded RLE data
    fRLEBytes = fOrigRLEBytes;
    if (!this->initializeStreamBuffer()) {
        SkCodecPrintf("Error: cannot initialize stream buffer.\n");
        return SkCodec::kInvalidInput;
    }

    return SkCodec::kSuccess;
}
Exemple #6
0
SkCodec* SkCodec::NewFromStream(SkStream* stream,
                                SkPngChunkReader* chunkReader) {
    if (!stream) {
        return nullptr;
    }

    SkAutoTDelete<SkStream> streamDeleter(stream);

    // 14 is enough to read all of the supported types.
    const size_t bytesToRead = 14;
    SkASSERT(bytesToRead <= MinBufferedBytesNeeded());

    char buffer[bytesToRead];
    size_t bytesRead = stream->peek(buffer, bytesToRead);

    // It is also possible to have a complete image less than bytesToRead bytes
    // (e.g. a 1 x 1 wbmp), meaning peek() would return less than bytesToRead.
    // Assume that if bytesRead < bytesToRead, but > 0, the stream is shorter
    // than bytesToRead, so pass that directly to the decoder.
    // It also is possible the stream uses too small a buffer for peeking, but
    // we trust the caller to use a large enough buffer.

    if (0 == bytesRead) {
        SkCodecPrintf("Could not peek!\n");
        // It is possible the stream does not support peeking, but does support
        // rewinding.
        // Attempt to read() and pass the actual amount read to the decoder.
        bytesRead = stream->read(buffer, bytesToRead);
        if (!stream->rewind()) {
            SkCodecPrintf("Could not rewind!\n");
            return nullptr;
        }
    }

    SkAutoTDelete<SkCodec> codec(nullptr);
    // PNG is special, since we want to be able to supply an SkPngChunkReader.
    // But this code follows the same pattern as the loop.
    if (SkPngCodec::IsPng(buffer, bytesRead)) {
        codec.reset(SkPngCodec::NewFromStream(streamDeleter.detach(), chunkReader));
    } else {
        for (DecoderProc proc : gDecoderProcs) {
            if (proc.IsFormat(buffer, bytesRead)) {
                codec.reset(proc.NewFromStream(streamDeleter.detach()));
                break;
            }
        }
    }

    // Set the max size at 128 megapixels (512 MB for kN32).
    // This is about 4x smaller than a test image that takes a few minutes for
    // dm to decode and draw.
    const int32_t maxSize = 1 << 27;
    if (codec && codec->getInfo().width() * codec->getInfo().height() > maxSize) {
        SkCodecPrintf("Error: Image size too large, cannot decode.\n");
        return nullptr;
    } else {
        return codec.detach();
    }
}
SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create(
        SkStreamRewindable* stream, Strategy strategy) {
    SkAutoTDelete<SkStreamRewindable> streamDeleter(stream);
    switch (strategy) {
        case kCanvas_Strategy: {
            SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(streamDeleter.detach()));
            if (nullptr == codec) {
                SkCodecPrintf("Error: Failed to create decoder.\n");
                return nullptr;
            }

            SkEncodedFormat format = codec->getEncodedFormat();
            switch (format) {
                case SkEncodedFormat::kJPEG_SkEncodedFormat:
                case SkEncodedFormat::kPNG_SkEncodedFormat:
                    break;
                default:
                    // FIXME: Support webp using a special case.  Webp does not support
                    //        scanline decoding.
                    return nullptr;
            }

            // If the image is a jpeg or a png, the scanline ordering should always be
            // kTopDown or kNone.  It is relevant to check because this implementation
            // only supports these two scanline orderings.
            SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder() ||
                    SkCodec::kNone_SkScanlineOrder == codec->getScanlineOrder());

            return new SkBitmapRegionCanvas(codec.detach());
        }
        case kAndroidCodec_Strategy: {
            SkAutoTDelete<SkAndroidCodec> codec =
                    SkAndroidCodec::NewFromStream(streamDeleter.detach());
            if (nullptr == codec) {
                SkCodecPrintf("Error: Failed to create codec.\n");
                return NULL;
            }

            SkEncodedFormat format = codec->getEncodedFormat();
            switch (format) {
                case SkEncodedFormat::kJPEG_SkEncodedFormat:
                case SkEncodedFormat::kPNG_SkEncodedFormat:
                case SkEncodedFormat::kWEBP_SkEncodedFormat:
                    break;
                default:
                    return nullptr;
            }

            return new SkBitmapRegionCodec(codec.detach());
        }
        default:
            SkASSERT(false);
            return nullptr;
    }
}
bool SkBmpRLECodec::initializeStreamBuffer() {
    // Setup a buffer to contain the full input stream
    size_t totalBytes = this->stream()->read(fStreamBuffer.get(), fRLEBytes);
    if (totalBytes < fRLEBytes) {
        fRLEBytes = totalBytes;
        SkCodecPrintf("Warning: incomplete RLE file.\n");
    }
    if (fRLEBytes == 0) {
        SkCodecPrintf("Error: could not read RLE image data.\n");
        return false;
    }
    return true;
}
/*
 * Performs the decoding
 */
int SkBmpMaskCodec::decodeRows(const SkImageInfo& dstInfo,
                                           void* dst, size_t dstRowBytes,
                                           const Options& opts) {
    // Iterate over rows of the image
    uint8_t* srcRow = fSrcBuffer.get();
    const int height = dstInfo.height();
    for (int y = 0; y < height; y++) {
        // Read a row of the input
        if (this->stream()->read(srcRow, this->srcRowBytes()) != this->srcRowBytes()) {
            SkCodecPrintf("Warning: incomplete input stream.\n");
            return y;
        }

        // Decode the row in destination format
        uint32_t row = this->getDstRow(y, height);
        void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes);

        if (this->colorXform()) {
            SkImageInfo xformInfo = dstInfo.makeWH(fMaskSwizzler->swizzleWidth(), dstInfo.height());
            fMaskSwizzler->swizzle(this->xformBuffer(), srcRow);
            this->applyColorXform(xformInfo, dstRow, this->xformBuffer());
        } else {
            fMaskSwizzler->swizzle(dstRow, srcRow);
        }
    }

    // Finished decoding the entire image
    return height;
}
Exemple #10
0
bool SkHeifCodec::conversionSupported(const SkImageInfo& dstInfo, bool srcIsOpaque,
                                      bool needsColorXform) {
    SkASSERT(srcIsOpaque);

    if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
        return false;
    }

    if (kOpaque_SkAlphaType != dstInfo.alphaType()) {
        SkCodecPrintf("Warning: an opaque image should be decoded as opaque "
                "- it is being decoded as non-opaque, which will draw slower\n");
    }

    switch (dstInfo.colorType()) {
        case kRGBA_8888_SkColorType:
            return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);

        case kBGRA_8888_SkColorType:
            return fHeifDecoder->setOutputColor(kHeifColorFormat_BGRA_8888);

        case kRGB_565_SkColorType:
            if (needsColorXform) {
                return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
            } else {
                return fHeifDecoder->setOutputColor(kHeifColorFormat_RGB565);
            }

        case kRGBA_F16_SkColorType:
            SkASSERT(needsColorXform);
            return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);

        default:
            return false;
    }
}
Exemple #11
0
SkCodec::Result SkIcoCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
        const SkCodec::Options& options, SkPMColor colorTable[], int* colorCount) {
    if (!ico_conversion_possible(dstInfo)) {
        return kInvalidConversion;
    }

    int index = 0;
    SkCodec::Result result = kInvalidScale;
    while (true) {
        index = this->chooseCodec(dstInfo.dimensions(), index);
        if (index < 0) {
            break;
        }

        SkCodec* embeddedCodec = fEmbeddedCodecs->operator[](index);
        SkImageInfo decodeInfo = fix_embedded_alpha(dstInfo, embeddedCodec->getInfo().alphaType());
        result = embeddedCodec->startScanlineDecode(decodeInfo, &options, colorTable, colorCount);
        if (kSuccess == result) {
            fCurrScanlineCodec = embeddedCodec;
            return result;
        }

        index++;
    }

    SkCodecPrintf("Error: No matching candidate image in ico.\n");
    return result;
}
SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
                                               const Options& options,
                                               SkPMColor ctable[],
                                               int* ctableCount) {
    // FIXME: Could we use the return value of setjmp to specify the type of
    // error?
    if (setjmp(png_jmpbuf(fPng_ptr))) {
        SkCodecPrintf("setjmp long jump!\n");
        return kInvalidInput;
    }
    png_read_update_info(fPng_ptr, fInfo_ptr);

    if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
        if (!this->createColorTable(requestedInfo.colorType(),
                kPremul_SkAlphaType == requestedInfo.alphaType(), ctableCount)) {
            return kInvalidInput;
        }
    }

    // Copy the color table to the client if they request kIndex8 mode
    copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);

    // Create the swizzler.  SkPngCodec retains ownership of the color table.
    const SkPMColor* colors = get_color_ptr(fColorTable.get());
    fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, requestedInfo,
            options));
    SkASSERT(fSwizzler);

    return kSuccess;
}
Exemple #13
0
/*
 *
 * Process an input mask to obtain the necessary information
 *
 */
const SkMasks::MaskInfo process_mask(uint32_t mask, uint32_t bpp) {
    // Determine properties of the mask
    uint32_t tempMask = mask;
    uint32_t shift = 0;
    uint32_t size = 0;
    if (tempMask != 0) {
        // Count trailing zeros on masks
        for (; (tempMask & 1) == 0; tempMask >>= 1) {
            shift++;
        }
        // Count the size of the mask
        for (; tempMask & 1; tempMask >>= 1) {
            size++;
        }
        // Verify that the mask is continuous
        if (tempMask) {
            SkCodecPrintf("Warning: Bit mask is not continuous.\n");
            // Finish processing the mask
            for (; tempMask; tempMask >>= 1) {
                size++;
            }
        }
        // Truncate masks greater than 8 bits
        if (size > 8) {
            shift += size - 8;
            size = 8;
            mask &= 0xFF << shift;
        }
    }

    // Save the calculated values
    const SkMasks::MaskInfo info = { mask, shift, size };
    return info;
}
Exemple #14
0
SkCodec* SkCodec::NewFromStream(SkStream* stream) {
    if (!stream) {
        return NULL;
    }

    SkAutoTDelete<SkStream> streamDeleter(stream);
    
    SkAutoTDelete<SkCodec> codec(NULL);
    for (uint32_t i = 0; i < SK_ARRAY_COUNT(gDecoderProcs); i++) {
        DecoderProc proc = gDecoderProcs[i];
        const bool correctFormat = proc.IsFormat(stream);
        if (!stream->rewind()) {
            return NULL;
        }
        if (correctFormat) {
            codec.reset(proc.NewFromStream(streamDeleter.detach()));
            break;
        }
    }

    // Set the max size at 128 megapixels (512 MB for kN32).
    // This is about 4x smaller than a test image that takes a few minutes for
    // dm to decode and draw.
    const int32_t maxSize = 1 << 27;
    if (codec && codec->getInfo().width() * codec->getInfo().height() > maxSize) {
        SkCodecPrintf("Error: Image size too large, cannot decode.\n");
        return NULL;
    } else {
        return codec.detach();
    }
}
Exemple #15
0
/*
 * Initiates the bitmap decode
 */
SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo,
                                           void* dst, size_t dstRowBytes,
                                           const Options& opts,
                                           SkPMColor* inputColorPtr,
                                           int* inputColorCount,
                                           int* rowsDecoded) {
    if (opts.fSubset) {
        // Subsets are not supported.
        return kUnimplemented;
    }
    if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) {
        SkCodecPrintf("Error: cannot convert input type to output type.\n");
        return kInvalidConversion;
    }

    Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount);
    if (kSuccess != result) {
        return result;
    }

    // Perform the decode
    int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts);
    if (rows != dstInfo.height()) {
        // We set rowsDecoded equal to the height because the background has already
        // been filled.  RLE encodings sometimes skip pixels, so we always start by
        // filling the background.
        *rowsDecoded = dstInfo.height();
        return kIncompleteInput;
    }

    return kSuccess;
}
Exemple #16
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;
}
Exemple #17
0
/*
 * Initiates the bitmap decode
 */
SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo,
                                            void* dst, size_t dstRowBytes,
                                            const Options& opts,
                                            int* rowsDecoded) {
    if (opts.fSubset) {
        // Subsets are not supported.
        return kUnimplemented;
    }
    if (dstInfo.dimensions() != this->dimensions()) {
        SkCodecPrintf("Error: scaling not supported.\n");
        return kInvalidScale;
    }

    Result result = this->prepareToDecode(dstInfo, opts);
    if (kSuccess != result) {
        return result;
    }

    int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts);
    if (rows != dstInfo.height()) {
        *rowsDecoded = rows;
        return kIncompleteInput;
    }
    return kSuccess;
}
Exemple #18
0
SkCodec* SkCodec::NewFromStream(SkStream* stream,
                                SkPngChunkReader* chunkReader) {
    if (!stream) {
        return nullptr;
    }

    SkAutoTDelete<SkStream> streamDeleter(stream);

    // 14 is enough to read all of the supported types.
    const size_t bytesToRead = 14;
    SkASSERT(bytesToRead <= MinBufferedBytesNeeded());

    char buffer[bytesToRead];
    size_t bytesRead = stream->peek(buffer, bytesToRead);

    // It is also possible to have a complete image less than bytesToRead bytes
    // (e.g. a 1 x 1 wbmp), meaning peek() would return less than bytesToRead.
    // Assume that if bytesRead < bytesToRead, but > 0, the stream is shorter
    // than bytesToRead, so pass that directly to the decoder.
    // It also is possible the stream uses too small a buffer for peeking, but
    // we trust the caller to use a large enough buffer.

    if (0 == bytesRead) {
        // TODO: After implementing peek in CreateJavaOutputStreamAdaptor.cpp, this
        // printf could be useful to notice failures.
        // SkCodecPrintf("Encoded image data failed to peek!\n");

        // It is possible the stream does not support peeking, but does support
        // rewinding.
        // Attempt to read() and pass the actual amount read to the decoder.
        bytesRead = stream->read(buffer, bytesToRead);
        if (!stream->rewind()) {
            SkCodecPrintf("Encoded image data could not peek or rewind to determine format!\n");
            return nullptr;
        }
    }

    // PNG is special, since we want to be able to supply an SkPngChunkReader.
    // But this code follows the same pattern as the loop.
#ifdef SK_CODEC_DECODES_PNG
    if (SkPngCodec::IsPng(buffer, bytesRead)) {
        return SkPngCodec::NewFromStream(streamDeleter.detach(), chunkReader);
    } else
#endif
    {
        for (DecoderProc proc : gDecoderProcs) {
            if (proc.IsFormat(buffer, bytesRead)) {
                return proc.NewFromStream(streamDeleter.detach());
            }
        }

#ifdef SK_CODEC_DECODES_RAW
        // Try to treat the input as RAW if all the other checks failed.
        return SkRawCodec::NewFromStream(streamDeleter.detach());
#endif
    }

    return nullptr;
}
Exemple #19
0
    void onFinish() override {
        if (setjmp(fCodec->fDecoderMgr->getJmpBuf())) {
            SkCodecPrintf("setjmp: Error in libjpeg finish_decompress\n");
            return;
        }

        jpeg_finish_decompress(fCodec->fDecoderMgr->dinfo());
    }
Exemple #20
0
    int readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, int count, int startRow)
    override {
        if (setjmp(png_jmpbuf(fPng_ptr))) {
            SkCodecPrintf("Failed to get scanlines.\n");
            // FIXME (msarett): Returning 0 is pessimistic.  If we can complete a single pass,
            // we may be able to report that all of the memory has been initialized.  Even if we
            // fail on the first pass, we can still report than some scanlines are initialized.
            return 0;
        }

        SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
        uint8_t* srcRow;
        for (int i = 0; i < fNumberPasses; i++) {
            // Discard rows that we planned to skip.
            for (int y = 0; y < startRow; y++){
                png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr);
            }
            // Read rows we care about into storage.
            srcRow = storage.get();
            for (int y = 0; y < count; y++) {
                png_read_row(fPng_ptr, srcRow, nullptr);
                srcRow += fSrcRowBytes;
            }
            // Discard rows that we don't need.
            for (int y = 0; y < this->getInfo().height() - startRow - count; y++) {
                png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr);
            }
        }

        // Swizzle and xform the rows we care about
        void* swizzlerDstRow = dst;
        size_t swizzlerDstRowBytes = rowBytes;

        bool colorXform = fColorXform &&
                apply_xform_on_decode(dstInfo.colorType(), this->getEncodedInfo().color());
        if (colorXform) {
            swizzlerDstRow = fColorXformSrcRow;
            swizzlerDstRowBytes = 0;
        }

        SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(),
                                                      this->getInfo().alphaType());
        srcRow = storage.get();
        for (int y = 0; y < count; y++) {
            fSwizzler->swizzle(swizzlerDstRow, srcRow);
            srcRow = SkTAddOffset<uint8_t>(srcRow, fSrcRowBytes);

            if (colorXform) {
                fColorXform->apply(dst, (const uint32_t*) swizzlerDstRow, fSwizzler->swizzleWidth(),
                                   dstInfo.colorType(), xformAlphaType);
                dst = SkTAddOffset<void>(dst, rowBytes);
            }

            swizzlerDstRow = SkTAddOffset<void>(swizzlerDstRow, swizzlerDstRowBytes);
        }

        return count;
    }
Exemple #21
0
SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
                                        size_t dstRowBytes, const Options& options,
                                        SkPMColor ctable[], int* ctableCount,
                                        int* rowsDecoded) {
    if (!conversion_possible(requestedInfo, this->getInfo())) {
        SkCodecPrintf("Error: cannot convert input type to output type.\n");
        return kInvalidConversion;
    }

    SkAutoTDelete<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(
            SkSwizzler::kRGB, nullptr, requestedInfo, options));
    SkASSERT(swizzler);

    const int width = requestedInfo.width();
    const int height = requestedInfo.height();
    SkAutoTDelete<dng_image> image(fDngImage->render(width, height));
    if (!image) {
        return kInvalidInput;
    }

    // Because the DNG SDK can not guarantee to render to requested size, we allow a small
    // difference. Only the overlapping region will be converted.
    const float maxDiffRatio = 1.03f;
    const dng_point& imageSize = image->Size();
    if (imageSize.h / width > maxDiffRatio || imageSize.h < width ||
        imageSize.v / height > maxDiffRatio || imageSize.v < height) {
        return SkCodec::kInvalidScale;
    }

    void* dstRow = dst;
    SkAutoTMalloc<uint8_t> srcRow(width * 3);

    dng_pixel_buffer buffer;
    buffer.fData = &srcRow[0];
    buffer.fPlane = 0;
    buffer.fPlanes = 3;
    buffer.fColStep = buffer.fPlanes;
    buffer.fPlaneStep = 1;
    buffer.fPixelType = ttByte;
    buffer.fPixelSize = sizeof(uint8_t);
    buffer.fRowStep = width * 3;

    for (int i = 0; i < height; ++i) {
        buffer.fArea = dng_rect(i, 0, i + 1, width);

        try {
            image->Get(buffer, dng_image::edge_zero);
        } catch (...) {
            *rowsDecoded = i;
            return kIncompleteInput; 
        }

        swizzler->swizzle(dstRow, &srcRow[0]);
        dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
    }
    return kSuccess;
}
Exemple #22
0
SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
        const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) {
    if (!conversion_possible(dstInfo, this->getInfo())) {
        SkCodecPrintf("Error: cannot convert input type to output type.\n");
        return kInvalidConversion;
    }

    return prepareToDecode(dstInfo, options, inputColorPtr, inputColorCount);
}
Exemple #23
0
 bool write(const void* buffer, size_t size) override {
     size_t newSize;
     if (!safe_add_to_size_t(this->bytesWritten(), size, &newSize) ||
         newSize > kMaxStreamSize)
     {
         SkCodecPrintf("Error: Stream size exceeds the limit.\n");
         return false;
     }
     return this->INHERITED::write(buffer, size);
 }
Exemple #24
0
    bool onSkipScanlines(int count) override {
        if (setjmp(png_jmpbuf(fPng_ptr))) {
            SkCodecPrintf("Failed to skip row.\n");
            return false;
        }

        for (int row = 0; row < count; row++) {
            png_read_row(fPng_ptr, fSwizzlerSrcRow, nullptr);
        }
        return true;
    }
SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create(
        SkStreamRewindable* stream, Strategy strategy) {
    SkAutoTDelete<SkStreamRewindable> streamDeleter(stream);
    switch (strategy) {
        case kCanvas_Strategy: {
            SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(streamDeleter.detach()));
            if (nullptr == codec) {
                SkCodecPrintf("Error: Failed to create decoder.\n");
                return nullptr;
            }

            if (SkEncodedFormat::kWEBP_SkEncodedFormat == codec->getEncodedFormat()) {
                // FIXME: Support webp using a special case.  Webp does not support
                //        scanline decoding.
                return nullptr;
            }

            switch (codec->getScanlineOrder()) {
                case SkCodec::kTopDown_SkScanlineOrder:
                case SkCodec::kNone_SkScanlineOrder:
                    break;
                default:
                    SkCodecPrintf("Error: Scanline ordering not supported.\n");
                    return nullptr;
            }
            return new SkBitmapRegionCanvas(codec.detach());
        }
        case kAndroidCodec_Strategy: {
            SkAutoTDelete<SkAndroidCodec> codec =
                    SkAndroidCodec::NewFromStream(streamDeleter.detach());
            if (NULL == codec) {
                SkCodecPrintf("Error: Failed to create codec.\n");
                return NULL;
            }
            return new SkBitmapRegionCodec(codec.detach());
        }
        default:
            SkASSERT(false);
            return nullptr;
    }
}
    bool onSkipScanlines(int count) override {
        // Assume that an error in libpng indicates an incomplete input.
        if (setjmp(png_jmpbuf(this->png_ptr()))) {
            SkCodecPrintf("setjmp long jump!\n");
            return false;
        }

        for (int row = 0; row < count; row++) {
            png_read_row(this->png_ptr(), fSrcRow, nullptr);
        }
        return true;
    }
Exemple #27
0
bool SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const Options& options,
                                  SkPMColor ctable[], int* ctableCount) {
    if (setjmp(png_jmpbuf(fPng_ptr))) {
        SkCodecPrintf("Failed on png_read_update_info.\n");
        return false;
    }
    png_read_update_info(fPng_ptr, fInfo_ptr);

    // It's important to reset fColorXform to nullptr.  We don't do this on rewinding
    // because the interlaced scanline decoder may need to rewind.
    fColorXform = nullptr;
    SkImageInfo swizzlerInfo = dstInfo;
    bool needsColorXform = needs_color_xform(dstInfo, this->getInfo());
    if (needsColorXform) {
        switch (dstInfo.colorType()) {
            case kRGBA_8888_SkColorType:
            case kBGRA_8888_SkColorType:
            case kRGBA_F16_SkColorType:
                swizzlerInfo = swizzlerInfo.makeColorType(kRGBA_8888_SkColorType);
                if (kPremul_SkAlphaType == dstInfo.alphaType()) {
                    swizzlerInfo = swizzlerInfo.makeAlphaType(kUnpremul_SkAlphaType);
                }
                break;
            case kIndex_8_SkColorType:
                break;
            default:
                return false;
        }

        fColorXform = SkColorSpaceXform::New(sk_ref_sp(this->getInfo().colorSpace()),
                                             sk_ref_sp(dstInfo.colorSpace()));

        if (!fColorXform && kRGBA_F16_SkColorType == dstInfo.colorType()) {
            return false;
        }
    }

    if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) {
        if (!this->createColorTable(dstInfo, ctableCount)) {
            return false;
        }
    }

    // Copy the color table to the client if they request kIndex8 mode
    copy_color_table(swizzlerInfo, fColorTable, ctable, ctableCount);

    // Create the swizzler.  SkPngCodec retains ownership of the color table.
    const SkPMColor* colors = get_color_ptr(fColorTable.get());
    fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, swizzlerInfo,
                                               options));
    SkASSERT(fSwizzler);
    return true;
}
/*
 * Initiates the bitmap decode
 */
SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo,
                                        void* dst, size_t dstRowBytes,
                                        const Options& opts,
                                        SkPMColor* inputColorPtr,
                                        int* inputColorCount) {
    if (!this->rewindIfNeeded()) {
        return kCouldNotRewind;
    }
    if (opts.fSubset) {
        // Subsets are not supported.
        return kUnimplemented;
    }
    if (dstInfo.dimensions() != this->getInfo().dimensions()) {
        SkCodecPrintf("Error: scaling not supported.\n");
        return kInvalidScale;
    }
    if (!conversion_possible(dstInfo, this->getInfo())) {
        SkCodecPrintf("Error: cannot convert input type to output type.\n");
        return kInvalidConversion;
    }

    // Create the color table if necessary and prepare the stream for decode
    // Note that if it is non-NULL, inputColorCount will be modified
    if (!this->createColorTable(inputColorCount)) {
        SkCodecPrintf("Error: could not create color table.\n");
        return kInvalidInput;
    }

    // Copy the color table to the client if necessary
    copy_color_table(dstInfo, fColorTable, inputColorPtr, inputColorCount);

    // Initialize a swizzler if necessary
    if (!this->initializeStreamBuffer()) {
        SkCodecPrintf("Error: cannot initialize swizzler.\n");
        return kInvalidConversion;
    }

    // Perform the decode
    return decode(dstInfo, dst, dstRowBytes, opts);
}
Exemple #29
0
void SkSampler::Fill(const SkImageInfo& info, void* dst, size_t rowBytes,
                     SkCodec::ZeroInitialized zeroInit) {
    SkASSERT(dst != nullptr);

    if (SkCodec::kYes_ZeroInitialized == zeroInit) {
        return;
    }

    const int width = info.width();
    const int numRows = info.height();

    // Use the proper memset routine to fill the remaining bytes
    switch (info.colorType()) {
        case kRGBA_8888_SkColorType:
        case kBGRA_8888_SkColorType: {
            uint32_t* dstRow = (uint32_t*) dst;
            for (int row = 0; row < numRows; row++) {
                sk_memset32(dstRow, 0, width);
                dstRow = SkTAddOffset<uint32_t>(dstRow, rowBytes);
            }
            break;
        }
        case kRGB_565_SkColorType: {
            uint16_t* dstRow = (uint16_t*) dst;
            for (int row = 0; row < numRows; row++) {
                sk_memset16(dstRow, 0, width);
                dstRow = SkTAddOffset<uint16_t>(dstRow, rowBytes);
            }
            break;
        }
        case kGray_8_SkColorType: {
            uint8_t* dstRow = (uint8_t*) dst;
            for (int row = 0; row < numRows; row++) {
                memset(dstRow, 0, width);
                dstRow = SkTAddOffset<uint8_t>(dstRow, rowBytes);
            }
            break;
        }
        case kRGBA_F16_SkColorType: {
            uint64_t* dstRow = (uint64_t*) dst;
            for (int row = 0; row < numRows; row++) {
                sk_memset64(dstRow, 0, width);
                dstRow = SkTAddOffset<uint64_t>(dstRow, rowBytes);
            }
            break;
        }
        default:
            SkCodecPrintf("Error: Unsupported dst color type for fill().  Doing nothing.\n");
            SkASSERT(false);
            break;
    }
}
Exemple #30
0
bool SkBmpRLECodec::initializeStreamBuffer() {
    // Setup a buffer to contain the full input stream
    // TODO (msarett): I'm not sure it is smart or optimal to trust fRLEBytes (read from header)
    //                 as the size of our buffer.  First of all, the decode fails if fRLEBytes is
    //                 corrupt (negative, zero, or small) when we might be able to decode
    //                 successfully with a fixed size buffer.  Additionally, we would save memory
    //                 using a fixed size buffer if the RLE encoding is large.  On the other hand,
    //                 we may also waste memory with a fixed size buffer.  And determining a
    //                 minimum size for our buffer would depend on the image width (so it's not
    //                 really "fixed" size), and we may end up allocating a buffer that is
    //                 generally larger than the average encoded size anyway.
    size_t totalBytes = this->stream()->read(fStreamBuffer.get(), fRLEBytes);
    if (totalBytes < fRLEBytes) {
        fRLEBytes = totalBytes;
        SkCodecPrintf("Warning: incomplete RLE file.\n");
    }
    if (fRLEBytes == 0) {
        SkCodecPrintf("Error: could not read RLE image data.\n");
        return false;
    }
    fCurrRLEByte = 0;
    return true;
}