SkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeSampleSize) const {
    SkISize preSampledSize = this->codec()->getInfo().dimensions();
    int sampleSize = *sampleSizePtr;
    SkASSERT(sampleSize > 1);

    if (nativeSampleSize) {
        *nativeSampleSize = 1;
    }

    // Only JPEG supports native downsampling.
    if (this->codec()->getEncodedFormat() == SkEncodedImageFormat::kJPEG) {
        // See if libjpeg supports this scale directly
        switch (sampleSize) {
            case 2:
            case 4:
            case 8:
                // This class does not need to do any sampling.
                *sampleSizePtr = 1;
                return this->codec()->getScaledDimensions(get_scale_from_sample_size(sampleSize));
            default:
                break;
        }

        // Check if sampleSize is a multiple of something libjpeg can support.
        int remainder;
        const int sampleSizes[] = { 8, 4, 2 };
        for (int supportedSampleSize : sampleSizes) {
            int actualSampleSize;
            SkTDivMod(sampleSize, supportedSampleSize, &actualSampleSize, &remainder);
            if (0 == remainder) {
                float scale = get_scale_from_sample_size(supportedSampleSize);

                // this->codec() will scale to this size.
                preSampledSize = this->codec()->getScaledDimensions(scale);

                // And then this class will sample it.
                *sampleSizePtr = actualSampleSize;
                if (nativeSampleSize) {
                    *nativeSampleSize = supportedSampleSize;
                }
                break;
            }
        }
    }

    return preSampledSize;
}
示例#2
0
// Test interlaced PNG in stripes, similar to DM's kStripe_Mode
DEF_TEST(Codec_stripes, r) {
    const char * path = "plane_interlaced.png";
    SkAutoTDelete<SkStream> stream(resource(path));
    if (!stream) {
        SkDebugf("Missing resource '%s'\n", path);
    }

    SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.detach()));
    REPORTER_ASSERT(r, codec);

    if (!codec) {
        return;
    }

    switch (codec->getScanlineOrder()) {
        case SkCodec::kBottomUp_SkScanlineOrder:
        case SkCodec::kOutOfOrder_SkScanlineOrder:
            ERRORF(r, "This scanline order will not match the original.");
            return;
        default:
            break;
    }

    // Baseline for what the image should look like, using N32.
    const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);

    SkBitmap bm;
    bm.allocPixels(info);
    SkAutoLockPixels autoLockPixels(bm);
    SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes());
    REPORTER_ASSERT(r, result == SkCodec::kSuccess);

    SkMD5::Digest digest;
    md5(bm, &digest);

    // Now decode in stripes
    const int height = info.height();
    const int numStripes = 4;
    int stripeHeight;
    int remainingLines;
    SkTDivMod(height, numStripes, &stripeHeight, &remainingLines);

    bm.eraseColor(SK_ColorYELLOW);

    result = codec->startScanlineDecode(info);
    REPORTER_ASSERT(r, result == SkCodec::kSuccess);

    // Odd stripes
    for (int i = 1; i < numStripes; i += 2) {
        // Skip the even stripes
        bool skipResult = codec->skipScanlines(stripeHeight);
        REPORTER_ASSERT(r, skipResult);

        int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeight,
                                     bm.rowBytes());
        REPORTER_ASSERT(r, linesDecoded == stripeHeight);
    }

    // Even stripes
    result = codec->startScanlineDecode(info);
    REPORTER_ASSERT(r, result == SkCodec::kSuccess);

    for (int i = 0; i < numStripes; i += 2) {
        int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeight,
                                     bm.rowBytes());
        REPORTER_ASSERT(r, linesDecoded == stripeHeight);

        // Skip the odd stripes
        if (i + 1 < numStripes) {
            bool skipResult = codec->skipScanlines(stripeHeight);
            REPORTER_ASSERT(r, skipResult);
        }
    }

    // Remainder at the end
    if (remainingLines > 0) {
        result = codec->startScanlineDecode(info);
        REPORTER_ASSERT(r, result == SkCodec::kSuccess);

        bool skipResult = codec->skipScanlines(height - remainingLines);
        REPORTER_ASSERT(r, skipResult);

        int linesDecoded = codec->getScanlines(bm.getAddr(0, height - remainingLines),
                                     remainingLines, bm.rowBytes());
        REPORTER_ASSERT(r, linesDecoded == remainingLines);
    }

    compare_to_good_digest(r, digest, bm);
}