• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
write_bm(const char * name,const SkBitmap & bm)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 
DEF_TEST(Codec_frames,r)34 DEF_TEST(Codec_frames, r) {
35     static const struct {
36         const char*         fName;
37         size_t              fFrameCount;
38         // One less than fFramecount, since the first frame is always
39         // independent.
40         std::vector<size_t> fRequiredFrames;
41         // The size of this one should match fFrameCount for animated, empty
42         // otherwise.
43         std::vector<size_t> fDurations;
44         int                 fRepetitionCount;
45     } gRecs[] = {
46         { "randPixelsAnim.gif", 13,
47             // required frames
48             { SkCodec::kNone, 1, 2, 3, 4, 4, 6, 7, 7, 7, 7, 7 },
49             // durations
50             { 0, 1000, 170, 40, 220, 7770, 90, 90, 90, 90, 90, 90, 90 },
51             // repetition count
52             0 },
53         { "box.gif", 1, {}, {}, 0 },
54         { "color_wheel.gif", 1, {}, {}, 0 },
55         { "test640x479.gif", 4, { 0, 1, 2 }, { 200, 200, 200, 200 },
56                 SkCodec::kRepetitionCountInfinite },
57         { "colorTables.gif", 2, { 0 }, { 1000, 1000 }, 5 },
58 
59         { "arrow.png",  1, {}, {}, 0 },
60         { "google_chrome.ico", 1, {}, {}, 0 },
61         { "brickwork-texture.jpg", 1, {}, {}, 0 },
62 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
63         { "dng_with_preview.dng", 1, {}, {}, 0 },
64 #endif
65         { "mandrill.wbmp", 1, {}, {}, 0 },
66         { "randPixels.bmp", 1, {}, {}, 0 },
67         { "yellow_rose.webp", 1, {}, {}, 0 },
68     };
69 
70     for (auto rec : gRecs) {
71         std::unique_ptr<SkStream> stream(GetResourceAsStream(rec.fName));
72         if (!stream) {
73             // Useful error statement, but sometimes people run tests without
74             // resources, and they do not want to see these messages.
75             //ERRORF(r, "Missing resources? Could not find '%s'", rec.fName);
76             continue;
77         }
78 
79         std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
80         if (!codec) {
81             ERRORF(r, "Failed to create an SkCodec from '%s'", rec.fName);
82             continue;
83         }
84 
85         const int repetitionCount = codec->getRepetitionCount();
86         if (repetitionCount != rec.fRepetitionCount) {
87             ERRORF(r, "%s repetition count does not match! expected: %i\tactual: %i",
88                       rec.fName, rec.fRepetitionCount, repetitionCount);
89         }
90 
91         const size_t expected = rec.fFrameCount;
92         const auto frameInfos = codec->getFrameInfo();
93         // getFrameInfo returns empty set for non-animated.
94         const size_t frameCount = frameInfos.size() == 0 ? 1 : frameInfos.size();
95         if (frameCount != expected) {
96             ERRORF(r, "'%s' expected frame count: %i\tactual: %i", rec.fName, expected, frameCount);
97             continue;
98         }
99 
100         if (rec.fRequiredFrames.size() + 1 != expected) {
101             ERRORF(r, "'%s' has wrong number entries in fRequiredFrames; expected: %i\tactual: %i",
102                    rec.fName, expected, rec.fRequiredFrames.size() + 1);
103             continue;
104         }
105 
106         if (1 == frameCount) {
107             continue;
108         }
109 
110         // From here on, we are only concerned with animated images.
111         REPORTER_ASSERT(r, frameInfos[0].fRequiredFrame == SkCodec::kNone);
112         for (size_t i = 1; i < frameCount; i++) {
113             if (rec.fRequiredFrames[i-1] != frameInfos[i].fRequiredFrame) {
114                 ERRORF(r, "%s's frame %i has wrong dependency! expected: %i\tactual: %i",
115                        rec.fName, i, rec.fRequiredFrames[i-1], frameInfos[i].fRequiredFrame);
116             }
117         }
118 
119         // Compare decoding in two ways:
120         // 1. Provide the frame that a frame depends on, so the codec just has to blend.
121         //    (in the array cachedFrames)
122         // 2. Do not provide the frame that a frame depends on, so the codec has to decode all the
123         //    way back to a key-frame. (in a local variable uncachedFrame)
124         // The two should look the same.
125         std::vector<SkBitmap> cachedFrames(frameCount);
126         const auto& info = codec->getInfo().makeColorType(kN32_SkColorType);
127 
128         auto decode = [&](SkBitmap* bm, bool cached, size_t index) {
129             bm->allocPixels(info);
130             if (cached) {
131                 // First copy the pixels from the cached frame
132                 const size_t requiredFrame = frameInfos[index].fRequiredFrame;
133                 if (requiredFrame != SkCodec::kNone) {
134                     const bool success = cachedFrames[requiredFrame].copyTo(bm);
135                     REPORTER_ASSERT(r, success);
136                 }
137             }
138             SkCodec::Options opts;
139             opts.fFrameIndex = index;
140             opts.fHasPriorFrame = cached;
141             const SkCodec::Result result = codec->getPixels(info, bm->getPixels(), bm->rowBytes(),
142                                                             &opts, nullptr, nullptr);
143             REPORTER_ASSERT(r, result == SkCodec::kSuccess);
144         };
145 
146         for (size_t i = 0; i < frameCount; i++) {
147             SkBitmap& cachedFrame = cachedFrames[i];
148             decode(&cachedFrame, true, i);
149             SkBitmap uncachedFrame;
150             decode(&uncachedFrame, false, i);
151 
152             // Now verify they're equal.
153             const size_t rowLen = info.bytesPerPixel() * info.width();
154             for (int y = 0; y < info.height(); y++) {
155                 const void* cachedAddr = cachedFrame.getAddr(0, y);
156                 SkASSERT(cachedAddr != nullptr);
157                 const void* uncachedAddr = uncachedFrame.getAddr(0, y);
158                 SkASSERT(uncachedAddr != nullptr);
159                 const bool lineMatches = memcmp(cachedAddr, uncachedAddr, rowLen) == 0;
160                 if (!lineMatches) {
161                     SkString name = SkStringPrintf("cached_%i", i);
162                     write_bm(name.c_str(), cachedFrame);
163                     name = SkStringPrintf("uncached_%i", i);
164                     write_bm(name.c_str(), uncachedFrame);
165                     ERRORF(r, "%s's frame %i is different depending on caching!", rec.fName, i);
166                     break;
167                 }
168             }
169         }
170 
171         if (rec.fDurations.size() != expected) {
172             ERRORF(r, "'%s' has wrong number entries in fDurations; expected: %i\tactual: %i",
173                    rec.fName, expected, rec.fDurations.size());
174             continue;
175         }
176 
177         for (size_t i = 0; i < frameCount; i++) {
178             if (rec.fDurations[i] != frameInfos[i].fDuration) {
179                 ERRORF(r, "%s frame %i's durations do not match! expected: %i\tactual: %i",
180                        rec.fName, i, rec.fDurations[i], frameInfos[i].fDuration);
181             }
182         }
183     }
184 }
185