Correct GIF frame dependencies and track alpha
[platform/upstream/libSkiaSharp.git] / tests / CodecAnimTest.cpp
1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7
8 #include "SkBitmap.h"
9 #include "SkCodec.h"
10 #include "SkCommonFlags.h"
11 #include "SkImageEncoder.h"
12 #include "SkOSPath.h"
13 #include "SkStream.h"
14
15 #include "Resources.h"
16 #include "Test.h"
17
18 #include <initializer_list>
19 #include <vector>
20
21 static void write_bm(const char* name, const SkBitmap& bm) {
22     if (FLAGS_writePath.isEmpty()) {
23         return;
24     }
25
26     SkString filename = SkOSPath::Join(FLAGS_writePath[0], name);
27     filename.appendf(".png");
28     SkFILEWStream file(filename.c_str());
29     if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) {
30         SkDebugf("failed to write '%s'\n", filename.c_str());
31     }
32 }
33
34 DEF_TEST(Codec_frames, r) {
35     #define kOpaque     kOpaque_SkAlphaType
36     #define kUnpremul   kUnpremul_SkAlphaType
37     static const struct {
38         const char*              fName;
39         size_t                   fFrameCount;
40         // One less than fFramecount, since the first frame is always
41         // independent.
42         std::vector<size_t>      fRequiredFrames;
43         // Same, since the first frame should match getInfo.
44         std::vector<SkAlphaType> fAlphaTypes;
45         // The size of this one should match fFrameCount for animated, empty
46         // otherwise.
47         std::vector<size_t>      fDurations;
48         int                      fRepetitionCount;
49     } gRecs[] = {
50         { "alphabetAnim.gif", 13,
51             { SkCodec::kNone, 0, 0, 0, 0, 5, 6, SkCodec::kNone,
52               SkCodec::kNone, SkCodec::kNone, 10, 11 },
53             { kUnpremul, kUnpremul, kUnpremul, kUnpremul, kUnpremul, kUnpremul,
54               kUnpremul, kUnpremul, kUnpremul, kOpaque, kOpaque, kUnpremul },
55             { 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100 },
56             0 },
57         { "randPixelsAnim2.gif", 4,
58             // required frames
59             { 0, 0, 1 },
60             // alphas
61             { kOpaque, kOpaque, kOpaque },
62             // durations
63             { 0, 1000, 170, 40 },
64             // repetition count
65             0 },
66         { "randPixelsAnim.gif", 13,
67             // required frames
68             { SkCodec::kNone, 1, 2, 3, 4, 3, 6, 7, 7, 7, 9, 9 },
69             { kUnpremul, kUnpremul, kUnpremul, kUnpremul, kUnpremul, kUnpremul,
70               kUnpremul, kUnpremul, kUnpremul, kUnpremul, kUnpremul, kUnpremul },
71             // durations
72             { 0, 1000, 170, 40, 220, 7770, 90, 90, 90, 90, 90, 90, 90 },
73             // repetition count
74             0 },
75         { "box.gif", 1, {}, {}, {}, 0 },
76         { "color_wheel.gif", 1, {}, {}, {}, 0 },
77         { "test640x479.gif", 4, { 0, 1, 2 },
78                 { kOpaque, kOpaque, kOpaque },
79                 { 200, 200, 200, 200 },
80                 SkCodec::kRepetitionCountInfinite },
81         { "colorTables.gif", 2, { 0 }, { kOpaque }, { 1000, 1000 }, 5 },
82
83         { "arrow.png",  1, {}, {}, {}, 0 },
84         { "google_chrome.ico", 1, {}, {}, {}, 0 },
85         { "brickwork-texture.jpg", 1, {}, {}, {}, 0 },
86 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
87         { "dng_with_preview.dng", 1, {}, {}, {}, 0 },
88 #endif
89         { "mandrill.wbmp", 1, {}, {}, {}, 0 },
90         { "randPixels.bmp", 1, {}, {}, {}, 0 },
91         { "yellow_rose.webp", 1, {}, {}, {}, 0 },
92     };
93     #undef kOpaque
94     #undef kUnpremul
95
96     for (const auto& rec : gRecs) {
97         std::unique_ptr<SkStream> stream(GetResourceAsStream(rec.fName));
98         if (!stream) {
99             // Useful error statement, but sometimes people run tests without
100             // resources, and they do not want to see these messages.
101             //ERRORF(r, "Missing resources? Could not find '%s'", rec.fName);
102             continue;
103         }
104
105         std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
106         if (!codec) {
107             ERRORF(r, "Failed to create an SkCodec from '%s'", rec.fName);
108             continue;
109         }
110
111         const int repetitionCount = codec->getRepetitionCount();
112         if (repetitionCount != rec.fRepetitionCount) {
113             ERRORF(r, "%s repetition count does not match! expected: %i\tactual: %i",
114                       rec.fName, rec.fRepetitionCount, repetitionCount);
115         }
116
117         const size_t expected = rec.fFrameCount;
118         const auto frameInfos = codec->getFrameInfo();
119         // getFrameInfo returns empty set for non-animated.
120         const size_t frameCount = frameInfos.size() == 0 ? 1 : frameInfos.size();
121         if (frameCount != expected) {
122             ERRORF(r, "'%s' expected frame count: %i\tactual: %i", rec.fName, expected, frameCount);
123             continue;
124         }
125
126         if (rec.fRequiredFrames.size() + 1 != expected) {
127             ERRORF(r, "'%s' has wrong number entries in fRequiredFrames; expected: %i\tactual: %i",
128                    rec.fName, expected, rec.fRequiredFrames.size() + 1);
129             continue;
130         }
131
132         if (1 == frameCount) {
133             continue;
134         }
135
136         auto to_string = [](SkAlphaType type) {
137             switch (type) {
138                 case kUnpremul_SkAlphaType:
139                     return "unpremul";
140                 case kOpaque_SkAlphaType:
141                     return "opaque";
142                 default:
143                     return "other";
144             }
145         };
146         // From here on, we are only concerned with animated images.
147         REPORTER_ASSERT(r, frameInfos[0].fRequiredFrame == SkCodec::kNone);
148         REPORTER_ASSERT(r, frameInfos[0].fAlphaType == codec->getInfo().alphaType());
149         for (size_t i = 1; i < frameCount; i++) {
150             if (rec.fRequiredFrames[i-1] != frameInfos[i].fRequiredFrame) {
151                 ERRORF(r, "%s's frame %i has wrong dependency! expected: %i\tactual: %i",
152                        rec.fName, i, rec.fRequiredFrames[i-1], frameInfos[i].fRequiredFrame);
153             }
154             auto expectedAlpha = rec.fAlphaTypes[i-1];
155             auto alpha = frameInfos[i].fAlphaType;
156             if (expectedAlpha != alpha) {
157                 ERRORF(r, "%s's frame %i has wrong alpha type! expected: %s\tactual: %s",
158                        rec.fName, i, to_string(expectedAlpha), to_string(alpha));
159             }
160         }
161
162         // Compare decoding in two ways:
163         // 1. Provide the frame that a frame depends on, so the codec just has to blend.
164         //    (in the array cachedFrames)
165         // 2. Do not provide the frame that a frame depends on, so the codec has to decode all the
166         //    way back to a key-frame. (in a local variable uncachedFrame)
167         // The two should look the same.
168         std::vector<SkBitmap> cachedFrames(frameCount);
169         const auto& info = codec->getInfo().makeColorType(kN32_SkColorType);
170
171         auto decode = [&](SkBitmap* bm, bool cached, size_t index) {
172             bm->allocPixels(info);
173             if (cached) {
174                 // First copy the pixels from the cached frame
175                 const size_t requiredFrame = frameInfos[index].fRequiredFrame;
176                 if (requiredFrame != SkCodec::kNone) {
177                     const bool success = cachedFrames[requiredFrame].copyTo(bm);
178                     REPORTER_ASSERT(r, success);
179                 }
180             }
181             SkCodec::Options opts;
182             opts.fFrameIndex = index;
183             opts.fHasPriorFrame = cached;
184             const SkCodec::Result result = codec->getPixels(info, bm->getPixels(), bm->rowBytes(),
185                                                             &opts, nullptr, nullptr);
186             REPORTER_ASSERT(r, result == SkCodec::kSuccess);
187         };
188
189         for (size_t i = 0; i < frameCount; i++) {
190             SkBitmap& cachedFrame = cachedFrames[i];
191             decode(&cachedFrame, true, i);
192             SkBitmap uncachedFrame;
193             decode(&uncachedFrame, false, i);
194
195             // Now verify they're equal.
196             const size_t rowLen = info.bytesPerPixel() * info.width();
197             for (int y = 0; y < info.height(); y++) {
198                 const void* cachedAddr = cachedFrame.getAddr(0, y);
199                 SkASSERT(cachedAddr != nullptr);
200                 const void* uncachedAddr = uncachedFrame.getAddr(0, y);
201                 SkASSERT(uncachedAddr != nullptr);
202                 const bool lineMatches = memcmp(cachedAddr, uncachedAddr, rowLen) == 0;
203                 if (!lineMatches) {
204                     SkString name = SkStringPrintf("cached_%i", i);
205                     write_bm(name.c_str(), cachedFrame);
206                     name = SkStringPrintf("uncached_%i", i);
207                     write_bm(name.c_str(), uncachedFrame);
208                     ERRORF(r, "%s's frame %i is different depending on caching!", rec.fName, i);
209                     break;
210                 }
211             }
212         }
213
214         if (rec.fDurations.size() != expected) {
215             ERRORF(r, "'%s' has wrong number entries in fDurations; expected: %i\tactual: %i",
216                    rec.fName, expected, rec.fDurations.size());
217             continue;
218         }
219
220         for (size_t i = 0; i < frameCount; i++) {
221             if (rec.fDurations[i] != frameInfos[i].fDuration) {
222                 ERRORF(r, "%s frame %i's durations do not match! expected: %i\tactual: %i",
223                        rec.fName, i, rec.fDurations[i], frameInfos[i].fDuration);
224             }
225         }
226     }
227 }