From 557fbbe05ba48bcc20be684d11fe0edfc24c87ba Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Tue, 23 May 2017 09:37:21 -0400 Subject: Add animation support to SkWebpCodec TBR=reed@google.com (No change to the public API, but changed a header file) SkWebpCodec: - Implement onGetFrameCount, onGetFrameInfo, and onGetRepetitionCount - Respect the alpha reported by libwebp. Although the spec states that it is only a hint, the libwebp encoder uses it properly. Respecting allows us to draw opaque images faster and decode them to 565. This also matches other SkCodecs (and Chromium). - onGetPixels: - Decode the frame requested, recursively decoding required frame if necessary - When blending with a prior frame, use SkRasterPipeline SkCodec: - Move check for negative index to getFrameInfo - Reset the colorXform if one is not needed SkCodecAnimation: - Add new blend enum, for WebP's (and APNG's) non-blending option SkFrameHolder: - New base classes for frames and the owner of the frames, allowing code sharing between SkWebpCodec and SkGifCodec (particularly for determining whether a frame has alpha and what frame it depends on) - When moving items from SkGIFFrameContext, use Skia conventions (i.e. int instead of unsigned) - Rename "delay time" to "duration", to match e.g. SkFrameInfo:: fDuration SkGifImageReader: - Move pieces to SkFrameHolder, and adapt to changes made in the process - Make setAlphaAndRequiredFrame (now on the base class SkFrameHolder) more general to support webp, and add support for frames that do not blend - Change SkGIFFrameContext from a struct to a class, to match how we use the distinction elsewhere (i.e. struct is a small object with public fields) - Rework hasTransparentPixel (now hasTransparency, since it returns true in some cases where there is not a transparent pixel) to better fit with the modified setAlphaAndRequiredFrame. Also be more consistent when there is no transparent pixel but no color map. - Simplify an if condition that was previously simplified in 2d61e717 but accidentally got reverted in a4db9be6 CodecAnimTest: - Test new animated webp files - Rearrange the test to more cleanly print alpha type mismatches for the first frame resources: - webp-animated.webp - animated webp from Chromium - blendBG.webp - new webp file using bits of webp-animated-semitransparent4.webp from Chromium - tests required frame and alpha when using the non-blending mode - frames have the following properties: - Frame 0: no alpha, fills screen - Frame 1: alpha, fills screen - Frame 2: no alpha, fills screen - Frame 3: alpha, fills screen, blendBG - Frame 4: no alpha, fills screen, blendBG - Frame 5: alpha, blendBG - Frame 6: covers 4, has alpha, blendBG - also used to test decoding to 565 if the new frame data has alpha but blends onto an opaque frame DM.cpp: - Test animated images to non-native 8888 and unpremul DMSrcSink.cpp: - Do not test non-native 8888 decodes to f16 dst - Test unpremul decodes to f16 - Copy a frame of an animated image prior to drawing, since in unpremul mode, the DM code will premultiply first. Bug: skia: 3315 Change-Id: I4e55ae2ee5bc095b37a743bdcfac644be603b980 Reviewed-on: https://skia-review.googlesource.com/16707 Commit-Queue: Mike Reed Reviewed-by: Mike Reed Reviewed-by: Leon Scroggins Reviewed-by: Matt Sarett --- tests/CodecAnimTest.cpp | 52 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) (limited to 'tests/CodecAnimTest.cpp') diff --git a/tests/CodecAnimTest.cpp b/tests/CodecAnimTest.cpp index 24b9c13ae9..087f5d89cd 100644 --- a/tests/CodecAnimTest.cpp +++ b/tests/CodecAnimTest.cpp @@ -34,11 +34,37 @@ static void write_bm(const char* name, const SkBitmap& bm) { DEF_TEST(Codec_trunc, r) { sk_sp data(GetResourceAsData("box.gif")); + if (!data) { + return; + } data = SkData::MakeSubset(data.get(), 0, 23); std::unique_ptr codec(SkCodec::NewFromData(data)); codec->getFrameInfo(); } +// 565 does not support alpha, but there is no reason for it not to support an +// animated image with a frame that has alpha but then blends onto an opaque +// frame making the result opaque. Test that we can decode such a frame. +DEF_TEST(Codec_565, r) { + sk_sp data(GetResourceAsData("blendBG.webp")); + if (!data) { + return; + } + std::unique_ptr codec(SkCodec::NewFromData(std::move(data))); + auto info = codec->getInfo().makeColorType(kRGB_565_SkColorType); + SkBitmap bm; + bm.allocPixels(info); + + SkCodec::Options options; + options.fFrameIndex = 1; + options.fHasPriorFrame = false; + + const auto result = codec->getPixels(info, bm.getPixels(), bm.rowBytes(), + &options, nullptr, nullptr); + REPORTER_ASSERT(r, result == SkCodec::kSuccess); +} + + DEF_TEST(Codec_frames, r) { #define kOpaque kOpaque_SkAlphaType #define kUnpremul kUnpremul_SkAlphaType @@ -97,6 +123,12 @@ DEF_TEST(Codec_frames, r) { { "mandrill.wbmp", 1, {}, {}, {}, 0 }, { "randPixels.bmp", 1, {}, {}, {}, 0 }, { "yellow_rose.webp", 1, {}, {}, {}, 0 }, + { "webp-animated.webp", 3, { 0, 1 }, { kOpaque, kOpaque, kOpaque }, + { 1000, 500, 1000 }, SkCodec::kRepetitionCountInfinite }, + { "blendBG.webp", 7, { 0, SkCodec::kNone, SkCodec::kNone, SkCodec::kNone, + 3, 3 }, + { kOpaque, kOpaque, kUnpremul, kOpaque, kUnpremul, kUnpremul }, + { 525, 500, 525, 437, 609, 729, 444 }, 7 }, }; #undef kOpaque #undef kUnpremul @@ -190,17 +222,6 @@ DEF_TEST(Codec_frames, r) { rec.fName, i, rec.fDurations[i], frameInfo.fDuration); } - if (0 == i) { - REPORTER_ASSERT(r, frameInfo.fRequiredFrame == SkCodec::kNone); - REPORTER_ASSERT(r, frameInfo.fAlphaType == codec->getInfo().alphaType()); - continue; - } - - if (rec.fRequiredFrames[i-1] != frameInfo.fRequiredFrame) { - ERRORF(r, "%s's frame %i has wrong dependency! expected: %i\tactual: %i", - rec.fName, i, rec.fRequiredFrames[i-1], frameInfo.fRequiredFrame); - } - auto to_string = [](SkAlphaType type) { switch (type) { case kUnpremul_SkAlphaType: @@ -212,12 +233,19 @@ DEF_TEST(Codec_frames, r) { } }; - auto expectedAlpha = rec.fAlphaTypes[i-1]; + auto expectedAlpha = 0 == i ? codec->getInfo().alphaType() : rec.fAlphaTypes[i-1]; auto alpha = frameInfo.fAlphaType; if (expectedAlpha != alpha) { ERRORF(r, "%s's frame %i has wrong alpha type! expected: %s\tactual: %s", rec.fName, i, to_string(expectedAlpha), to_string(alpha)); } + + if (0 == i) { + REPORTER_ASSERT(r, frameInfo.fRequiredFrame == SkCodec::kNone); + } else if (rec.fRequiredFrames[i-1] != frameInfo.fRequiredFrame) { + ERRORF(r, "%s's frame %i has wrong dependency! expected: %i\tactual: %i", + rec.fName, i, rec.fRequiredFrames[i-1], frameInfo.fRequiredFrame); + } } if (TestMode::kIndividual == mode) { -- cgit v1.2.3