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; }
// 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); }