• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 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 "CodecPriv.h"
9 #include "Resources.h"
10 #include "SkAndroidCodec.h"
11 #include "SkBitmap.h"
12 #include "SkData.h"
13 #include "SkImage.h"
14 #include "SkStream.h"
15 #include "SkTypes.h"
16 #include "Test.h"
17 
18 static unsigned char gGIFData[] = {
19   0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x03, 0x00, 0x03, 0x00, 0xe3, 0x08,
20   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00,
21   0xff, 0x80, 0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
22   0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
24   0xff, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x04,
25   0x07, 0x50, 0x1c, 0x43, 0x40, 0x41, 0x23, 0x44, 0x00, 0x3b
26 };
27 
28 static unsigned char gGIFDataNoColormap[] = {
29   // Header
30   0x47, 0x49, 0x46, 0x38, 0x39, 0x61,
31   // Screen descriptor
32   0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
33   // Graphics control extension
34   0x21, 0xf9, 0x04, 0x01, 0x0a, 0x00, 0x01, 0x00,
35   // Image descriptor
36   0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
37   // Image data
38   0x02, 0x02, 0x4c, 0x01, 0x00,
39   // Trailer
40   0x3b
41 };
42 
43 static unsigned char gInterlacedGIF[] = {
44   0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x09, 0x00, 0x09, 0x00, 0xe3, 0x08, 0x00,
45   0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x80,
46   0x80, 0x80, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff,
47   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
48   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00,
49   0x00, 0x09, 0x00, 0x09, 0x00, 0x40, 0x04, 0x1b, 0x50, 0x1c, 0x23, 0xe9, 0x44,
50   0x23, 0x60, 0x9d, 0x09, 0x28, 0x1e, 0xf8, 0x6d, 0x64, 0x56, 0x9d, 0x53, 0xa8,
51   0x7e, 0xa8, 0x65, 0x94, 0x5c, 0xb0, 0x8a, 0x45, 0x04, 0x00, 0x3b
52 };
53 
test_gif_data_no_colormap(skiatest::Reporter * r,void * data,size_t size)54 static void test_gif_data_no_colormap(skiatest::Reporter* r,
55                                       void* data,
56                                       size_t size) {
57     SkBitmap bm;
58     bool imageDecodeSuccess = decode_memory(data, size, &bm);
59     REPORTER_ASSERT(r, imageDecodeSuccess);
60     REPORTER_ASSERT(r, bm.width() == 1);
61     REPORTER_ASSERT(r, bm.height() == 1);
62     REPORTER_ASSERT(r, !(bm.empty()));
63     if (!(bm.empty())) {
64         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0x00000000);
65     }
66 }
test_gif_data(skiatest::Reporter * r,void * data,size_t size)67 static void test_gif_data(skiatest::Reporter* r, void* data, size_t size) {
68     SkBitmap bm;
69     bool imageDecodeSuccess = decode_memory(data, size, &bm);
70     REPORTER_ASSERT(r, imageDecodeSuccess);
71     REPORTER_ASSERT(r, bm.width() == 3);
72     REPORTER_ASSERT(r, bm.height() == 3);
73     REPORTER_ASSERT(r, !(bm.empty()));
74     if (!(bm.empty())) {
75         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
76         REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
77         REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
78         REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
79         REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
80         REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
81         REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff);
82         REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff);
83         REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff);
84     }
85 }
test_gif_data_dims(skiatest::Reporter * r,void * data,size_t size,int width,int height)86 static void test_gif_data_dims(skiatest::Reporter* r, void* data, size_t size, int width,
87         int height) {
88     SkBitmap bm;
89     bool imageDecodeSuccess = decode_memory(data, size, &bm);
90     REPORTER_ASSERT(r, imageDecodeSuccess);
91     REPORTER_ASSERT(r, bm.width() == width);
92     REPORTER_ASSERT(r, bm.height() == height);
93     REPORTER_ASSERT(r, !(bm.empty()));
94 }
test_interlaced_gif_data(skiatest::Reporter * r,void * data,size_t size)95 static void test_interlaced_gif_data(skiatest::Reporter* r,
96                                      void* data,
97                                      size_t size) {
98     SkBitmap bm;
99     bool imageDecodeSuccess = decode_memory(data, size, &bm);
100     REPORTER_ASSERT(r, imageDecodeSuccess);
101     REPORTER_ASSERT(r, bm.width() == 9);
102     REPORTER_ASSERT(r, bm.height() == 9);
103     REPORTER_ASSERT(r, !(bm.empty()));
104     if (!(bm.empty())) {
105         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
106         REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
107         REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
108 
109         REPORTER_ASSERT(r, bm.getColor(0, 2) == 0xffffffff);
110         REPORTER_ASSERT(r, bm.getColor(1, 2) == 0xffff00ff);
111         REPORTER_ASSERT(r, bm.getColor(2, 2) == 0xff0000ff);
112 
113         REPORTER_ASSERT(r, bm.getColor(0, 4) == 0xff808080);
114         REPORTER_ASSERT(r, bm.getColor(1, 4) == 0xff000000);
115         REPORTER_ASSERT(r, bm.getColor(2, 4) == 0xff00ff00);
116 
117         REPORTER_ASSERT(r, bm.getColor(0, 6) == 0xffff0000);
118         REPORTER_ASSERT(r, bm.getColor(1, 6) == 0xffffff00);
119         REPORTER_ASSERT(r, bm.getColor(2, 6) == 0xff00ffff);
120 
121         REPORTER_ASSERT(r, bm.getColor(0, 8) == 0xffffffff);
122         REPORTER_ASSERT(r, bm.getColor(1, 8) == 0xffff00ff);
123         REPORTER_ASSERT(r, bm.getColor(2, 8) == 0xff0000ff);
124     }
125 }
126 
test_gif_data_short(skiatest::Reporter * r,void * data,size_t size)127 static void test_gif_data_short(skiatest::Reporter* r,
128                                 void* data,
129                                 size_t size) {
130     SkBitmap bm;
131     bool imageDecodeSuccess = decode_memory(data, size, &bm);
132     REPORTER_ASSERT(r, imageDecodeSuccess);
133     REPORTER_ASSERT(r, bm.width() == 3);
134     REPORTER_ASSERT(r, bm.height() == 3);
135     REPORTER_ASSERT(r, !(bm.empty()));
136     if (!(bm.empty())) {
137         REPORTER_ASSERT(r, bm.getColor(0, 0) == 0xffff0000);
138         REPORTER_ASSERT(r, bm.getColor(1, 0) == 0xffffff00);
139         REPORTER_ASSERT(r, bm.getColor(2, 0) == 0xff00ffff);
140         REPORTER_ASSERT(r, bm.getColor(0, 1) == 0xff808080);
141         REPORTER_ASSERT(r, bm.getColor(1, 1) == 0xff000000);
142         REPORTER_ASSERT(r, bm.getColor(2, 1) == 0xff00ff00);
143     }
144 }
145 
146 /**
147   This test will test the ability of the SkCodec to deal with
148   GIF files which have been mangled somehow.  We want to display as
149   much of the GIF as possible.
150 */
DEF_TEST(Gif,reporter)151 DEF_TEST(Gif, reporter) {
152     // test perfectly good images.
153     test_gif_data(reporter, static_cast<void *>(gGIFData), sizeof(gGIFData));
154     test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
155                           sizeof(gInterlacedGIF));
156 
157     unsigned char badData[sizeof(gGIFData)];
158 
159     memcpy(badData, gGIFData, sizeof(gGIFData));
160     badData[6] = 0x01;  // image too wide
161     test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
162     // "libgif warning [image too wide, expanding output to size]"
163 
164     memcpy(badData, gGIFData, sizeof(gGIFData));
165     badData[8] = 0x01;  // image too tall
166     test_gif_data(reporter, static_cast<void *>(badData), sizeof(gGIFData));
167     // "libgif warning [image too tall,  expanding output to size]"
168 
169     memcpy(badData, gGIFData, sizeof(gGIFData));
170     badData[62] = 0x01;  // image shifted right
171     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 4, 3);
172 
173     memcpy(badData, gGIFData, sizeof(gGIFData));
174     badData[64] = 0x01;  // image shifted down
175     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3, 4);
176 
177     memcpy(badData, gGIFData, sizeof(gGIFData));
178     badData[62] = 0xff;  // image shifted right
179     badData[63] = 0xff;
180     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3 + 0xFFFF, 3);
181 
182     memcpy(badData, gGIFData, sizeof(gGIFData));
183     badData[64] = 0xff;  // image shifted down
184     badData[65] = 0xff;
185     test_gif_data_dims(reporter, static_cast<void *>(badData), sizeof(gGIFData), 3, 3 + 0xFFFF);
186 
187     test_gif_data_no_colormap(reporter, static_cast<void *>(gGIFDataNoColormap),
188                               sizeof(gGIFDataNoColormap));
189 
190     // Since there is no color map, we do not even need to parse the image data
191     // to know that we should draw transparent. Truncate the file before the
192     // data. This should still succeed.
193     test_gif_data_no_colormap(reporter, static_cast<void *>(gGIFDataNoColormap), 31);
194 
195     // Likewise, incremental decoding should succeed here.
196     {
197         sk_sp<SkData> data = SkData::MakeWithoutCopy(gGIFDataNoColormap, 31);
198         std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
199         REPORTER_ASSERT(reporter, codec);
200         if (codec) {
201             auto info = codec->getInfo().makeColorType(kN32_SkColorType);
202             SkBitmap bm;
203             bm.allocPixels(info);
204             REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->startIncrementalDecode(
205                     info, bm.getPixels(), bm.rowBytes()));
206             REPORTER_ASSERT(reporter, SkCodec::kSuccess == codec->incrementalDecode());
207             REPORTER_ASSERT(reporter, bm.width() == 1);
208             REPORTER_ASSERT(reporter, bm.height() == 1);
209             REPORTER_ASSERT(reporter, !(bm.empty()));
210             if (!(bm.empty())) {
211                 REPORTER_ASSERT(reporter, bm.getColor(0, 0) == 0x00000000);
212             }
213         }
214     }
215 
216     // test short Gif.  80 is missing a few bytes.
217     test_gif_data_short(reporter, static_cast<void *>(gGIFData), 80);
218     // "libgif warning [DGifGetLine]"
219 
220     test_interlaced_gif_data(reporter, static_cast<void *>(gInterlacedGIF),
221                              100);  // 100 is missing a few bytes
222     // "libgif warning [interlace DGifGetLine]"
223 }
224 
225 // Regression test for decoding a gif image with sampleSize of 4, which was
226 // previously crashing.
DEF_TEST(Gif_Sampled,r)227 DEF_TEST(Gif_Sampled, r) {
228     std::unique_ptr<SkFILEStream> stream(
229             new SkFILEStream(GetResourcePath("test640x479.gif").c_str()));
230     REPORTER_ASSERT(r, stream->isValid());
231     if (!stream->isValid()) {
232         return;
233     }
234 
235     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(stream.release()));
236     REPORTER_ASSERT(r, codec);
237     if (!codec) {
238         return;
239     }
240 
241     // Construct a color table for the decode if necessary
242     sk_sp<SkColorTable> colorTable(nullptr);
243     SkPMColor* colorPtr = nullptr;
244     int* colorCountPtr = nullptr;
245     int maxColors = 256;
246     if (kIndex_8_SkColorType == codec->getInfo().colorType()) {
247         SkPMColor colors[256];
248         colorTable.reset(new SkColorTable(colors, maxColors));
249         colorPtr = const_cast<SkPMColor*>(colorTable->readColors());
250         colorCountPtr = &maxColors;
251     }
252 
253     SkAndroidCodec::AndroidOptions options;
254     options.fSampleSize = 4;
255     options.fColorPtr = colorPtr;
256     options.fColorCount = colorCountPtr;
257 
258     SkBitmap bm;
259     bm.allocPixels(codec->getInfo(), nullptr, colorTable.get());
260     const SkCodec::Result result = codec->getAndroidPixels(codec->getInfo(), bm.getPixels(),
261             bm.rowBytes(), &options);
262     REPORTER_ASSERT(r, result == SkCodec::kSuccess);
263 }
264 
265 // If a GIF file is truncated before the header for the first image is defined,
266 // we should not create an SkCodec.
DEF_TEST(Codec_GifTruncated,r)267 DEF_TEST(Codec_GifTruncated, r) {
268     SkString path = GetResourcePath("test640x479.gif");
269     sk_sp<SkData> data(SkData::MakeFromFileName(path.c_str()));
270 
271     // This is right before the header for the first image.
272     data = SkData::MakeSubset(data.get(), 0, 446);
273     std::unique_ptr<SkCodec> codec(SkCodec::NewFromData(data));
274     REPORTER_ASSERT(r, !codec);
275 }
276 
277 // There was a bug where SkAndroidCodec::computeOutputColorType returned kIndex_8 for
278 // GIFs that did not support kIndex_8. Verify that for such an image, the method computes
279 // something that it can actually decode to.
DEF_TEST(Codec_GifIndex8,r)280 DEF_TEST(Codec_GifIndex8, r) {
281     std::unique_ptr<SkStream> stream(GetResourceAsStream("randPixelsOffset.gif"));
282     if (!stream) {
283         return;
284     }
285 
286     std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(stream.release()));
287     REPORTER_ASSERT(r, codec);
288     if (!codec) {
289         return;
290     }
291 
292     REPORTER_ASSERT(r, codec->getInfo().colorType() == kN32_SkColorType);
293     const SkColorType outputColorType = codec->computeOutputColorType(kN32_SkColorType);
294     REPORTER_ASSERT(r, outputColorType == kN32_SkColorType);
295 
296     SkAndroidCodec::AndroidOptions options;
297     sk_sp<SkColorTable> colorTable(nullptr);
298     int maxColors = 256;
299     if (kIndex_8_SkColorType == outputColorType) {
300         SkPMColor colors[256];
301         colorTable.reset(new SkColorTable(colors, maxColors));
302         options.fColorPtr = const_cast<SkPMColor*>(colorTable->readColors());
303         options.fColorCount = &maxColors;
304     }
305 
306     auto info = codec->getInfo().makeColorType(outputColorType);
307     SkBitmap bm;
308     bm.setInfo(info);
309     bm.allocPixels(colorTable.get());
310 
311     REPORTER_ASSERT(r, SkCodec::kSuccess == codec->getAndroidPixels(info, bm.getPixels(),
312             bm.rowBytes(), &options));
313 }
314