Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: tests/CodecTest.cpp

Issue 1997703003: Make SkPngCodec decode progressively. (Closed) Base URL: https://skia.googlesource.com/skia.git@foil
Patch Set: Rebase Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tests/CodecPartialTest.cpp ('k') | tests/ImageTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "Resources.h" 8 #include "Resources.h"
9 #include "SkAndroidCodec.h" 9 #include "SkAndroidCodec.h"
10 #include "SkBitmap.h" 10 #include "SkBitmap.h"
11 #include "SkCodec.h" 11 #include "SkCodec.h"
12 #include "SkCodecImageGenerator.h" 12 #include "SkCodecImageGenerator.h"
13 #include "SkData.h" 13 #include "SkData.h"
14 #include "SkImageEncoder.h" 14 #include "SkImageEncoder.h"
15 #include "SkFrontBufferedStream.h" 15 #include "SkFrontBufferedStream.h"
16 #include "SkMD5.h" 16 #include "SkMD5.h"
17 #include "SkRandom.h" 17 #include "SkRandom.h"
18 #include "SkStream.h" 18 #include "SkStream.h"
19 #include "SkStreamPriv.h" 19 #include "SkStreamPriv.h"
20 #include "SkPngChunkReader.h" 20 #include "SkPngChunkReader.h"
21 #include "Test.h" 21 #include "Test.h"
22 22
23 #include "png.h" 23 #include "png.h"
24 24
25 #if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR < 5
26 // FIXME (scroggo): Google3 needs to be updated to use a newer version of li bpng. In
27 // the meantime, we had to break some pieces of SkPngCodec in order to suppo rt Google3.
28 // The parts that are broken are likely not used by Google3.
29 #define SK_PNG_DISABLE_TESTS
30 #endif
31
25 static void md5(const SkBitmap& bm, SkMD5::Digest* digest) { 32 static void md5(const SkBitmap& bm, SkMD5::Digest* digest) {
26 SkAutoLockPixels autoLockPixels(bm); 33 SkAutoLockPixels autoLockPixels(bm);
27 SkASSERT(bm.getPixels()); 34 SkASSERT(bm.getPixels());
28 SkMD5 md5; 35 SkMD5 md5;
29 size_t rowLen = bm.info().bytesPerPixel() * bm.width(); 36 size_t rowLen = bm.info().bytesPerPixel() * bm.width();
30 for (int y = 0; y < bm.height(); ++y) { 37 for (int y = 0; y < bm.height(); ++y) {
31 md5.write(bm.getAddr(0, y), rowLen); 38 md5.write(bm.getAddr(0, y), rowLen);
32 } 39 }
33 md5.finish(*digest); 40 md5.finish(*digest);
34 } 41 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 do { 79 do {
73 rect.fLeft = rand->nextRangeU(0, w); 80 rect.fLeft = rand->nextRangeU(0, w);
74 rect.fTop = rand->nextRangeU(0, h); 81 rect.fTop = rand->nextRangeU(0, h);
75 rect.fRight = rand->nextRangeU(0, w); 82 rect.fRight = rand->nextRangeU(0, w);
76 rect.fBottom = rand->nextRangeU(0, h); 83 rect.fBottom = rand->nextRangeU(0, h);
77 rect.sort(); 84 rect.sort();
78 } while (rect.isEmpty()); 85 } while (rect.isEmpty());
79 return rect; 86 return rect;
80 } 87 }
81 88
89 static void test_incremental_decode(skiatest::Reporter* r, SkCodec* codec, const SkImageInfo& info,
90 const SkMD5::Digest& goodDigest) {
91 SkBitmap bm;
92 bm.allocPixels(info);
93 SkAutoLockPixels autoLockPixels(bm);
94
95 REPORTER_ASSERT(r, SkCodec::kSuccess == codec->startIncrementalDecode(info, bm.getPixels(),
96 bm.row Bytes()));
97
98 REPORTER_ASSERT(r, SkCodec::kSuccess == codec->incrementalDecode());
99
100 compare_to_good_digest(r, goodDigest, bm);
101 }
102
103 // Test in stripes, similar to DM's kStripe_Mode
104 static void test_in_stripes(skiatest::Reporter* r, SkCodec* codec, const SkImage Info& info,
105 const SkMD5::Digest& goodDigest) {
106 SkBitmap bm;
107 bm.allocPixels(info);
108 bm.eraseColor(SK_ColorYELLOW);
109
110 const int height = info.height();
111 // Note that if numStripes does not evenly divide height there will be an ex tra
112 // stripe.
113 const int numStripes = 4;
114
115 if (numStripes > height) {
116 // Image is too small.
117 return;
118 }
119
120 const int stripeHeight = height / numStripes;
121
122 // Iterate through the image twice. Once to decode odd stripes, and once for even.
123 for (int oddEven = 1; oddEven >= 0; oddEven--) {
124 for (int y = oddEven * stripeHeight; y < height; y += 2 * stripeHeight) {
125 SkIRect subset = SkIRect::MakeLTRB(0, y, info.width(),
126 SkTMin(y + stripeHeight, height)) ;
127 SkCodec::Options options;
128 options.fSubset = &subset;
129 if (SkCodec::kSuccess != codec->startIncrementalDecode(info, bm.getA ddr(0, y),
130 bm.rowBytes(), &options)) {
131 ERRORF(r, "failed to start incremental decode!\ttop: %i\tbottom% i\n",
132 subset.top(), subset.bottom());
133 return;
134 }
135 if (SkCodec::kSuccess != codec->incrementalDecode()) {
136 ERRORF(r, "failed incremental decode starting from line %i\n", y );
137 return;
138 }
139 }
140 }
141
142 compare_to_good_digest(r, goodDigest, bm);
143 }
144
82 template<typename Codec> 145 template<typename Codec>
83 static void test_codec(skiatest::Reporter* r, Codec* codec, SkBitmap& bm, const SkImageInfo& info, 146 static void test_codec(skiatest::Reporter* r, Codec* codec, SkBitmap& bm, const SkImageInfo& info,
84 const SkISize& size, SkCodec::Result expectedResult, SkMD5::Digest* dige st, 147 const SkISize& size, SkCodec::Result expectedResult, SkMD5::Digest* dige st,
85 const SkMD5::Digest* goodDigest) { 148 const SkMD5::Digest* goodDigest) {
86 149
87 REPORTER_ASSERT(r, info.dimensions() == size); 150 REPORTER_ASSERT(r, info.dimensions() == size);
88 bm.allocPixels(info); 151 bm.allocPixels(info);
89 SkAutoLockPixels autoLockPixels(bm); 152 SkAutoLockPixels autoLockPixels(bm);
90 153
91 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes( )); 154 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes( ));
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 }; 243 };
181 244
182 for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) { 245 for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) {
183 if (SkStrEndsWith(path, exts[i])) { 246 if (SkStrEndsWith(path, exts[i])) {
184 return true; 247 return true;
185 } 248 }
186 } 249 }
187 return false; 250 return false;
188 } 251 }
189 252
253 // FIXME: Break up this giant function
190 static void check(skiatest::Reporter* r, 254 static void check(skiatest::Reporter* r,
191 const char path[], 255 const char path[],
192 SkISize size, 256 SkISize size,
193 bool supportsScanlineDecoding, 257 bool supportsScanlineDecoding,
194 bool supportsSubsetDecoding, 258 bool supportsSubsetDecoding,
195 bool supportsIncomplete = true) { 259 bool supportsIncomplete,
260 bool supportsNewScanlineDecoding = false) {
196 261
197 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); 262 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path));
198 if (!stream) { 263 if (!stream) {
199 return; 264 return;
200 } 265 }
201 266
202 SkAutoTDelete<SkCodec> codec(nullptr); 267 SkAutoTDelete<SkCodec> codec(nullptr);
203 bool isIncomplete = supportsIncomplete; 268 bool isIncomplete = supportsIncomplete;
204 if (isIncomplete) { 269 if (isIncomplete) {
205 size_t size = stream->getLength(); 270 size_t size = stream->getLength();
206 sk_sp<SkData> data((SkData::MakeFromStream(stream, 2 * size / 3))); 271 sk_sp<SkData> data((SkData::MakeFromStream(stream, 2 * size / 3)));
207 codec.reset(SkCodec::NewFromData(data)); 272 codec.reset(SkCodec::NewFromData(data));
208 } else { 273 } else {
209 codec.reset(SkCodec::NewFromStream(stream.release())); 274 codec.reset(SkCodec::NewFromStream(stream.release()));
210 } 275 }
211 if (!codec) { 276 if (!codec) {
212 ERRORF(r, "Unable to decode '%s'", path); 277 ERRORF(r, "Unable to decode '%s'", path);
213 return; 278 return;
214 } 279 }
215 280
216 // Test full image decodes with SkCodec 281 // Test full image decodes with SkCodec
217 SkMD5::Digest codecDigest; 282 SkMD5::Digest codecDigest;
218 const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); 283 const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
219 SkBitmap bm; 284 SkBitmap bm;
220 SkCodec::Result expectedResult = isIncomplete ? SkCodec::kIncompleteInput : SkCodec::kSuccess; 285 SkCodec::Result expectedResult = isIncomplete ? SkCodec::kIncompleteInput : SkCodec::kSuccess;
221 test_codec(r, codec.get(), bm, info, size, expectedResult, &codecDigest, nul lptr); 286 test_codec(r, codec.get(), bm, info, size, expectedResult, &codecDigest, nul lptr);
222 287
223 // Scanline decoding follows. 288 // Scanline decoding follows.
289
290 if (supportsNewScanlineDecoding && !isIncomplete) {
291 test_incremental_decode(r, codec, info, codecDigest);
292 test_in_stripes(r, codec, info, codecDigest);
293 }
294
224 // Need to call startScanlineDecode() first. 295 // Need to call startScanlineDecode() first.
225 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) 296 REPORTER_ASSERT(r, codec->getScanlines(bm.getAddr(0, 0), 1, 0) == 0);
226 == 0); 297 REPORTER_ASSERT(r, !codec->skipScanlines(1));
227 REPORTER_ASSERT(r, codec->skipScanlines(1)
228 == 0);
229
230 const SkCodec::Result startResult = codec->startScanlineDecode(info); 298 const SkCodec::Result startResult = codec->startScanlineDecode(info);
231 if (supportsScanlineDecoding) { 299 if (supportsScanlineDecoding) {
232 bm.eraseColor(SK_ColorYELLOW); 300 bm.eraseColor(SK_ColorYELLOW);
233 301
234 REPORTER_ASSERT(r, startResult == SkCodec::kSuccess); 302 REPORTER_ASSERT(r, startResult == SkCodec::kSuccess);
235 303
236 for (int y = 0; y < info.height(); y++) { 304 for (int y = 0; y < info.height(); y++) {
237 const int lines = codec->getScanlines(bm.getAddr(0, y), 1, 0); 305 const int lines = codec->getScanlines(bm.getAddr(0, y), 1, 0);
238 if (!isIncomplete) { 306 if (!isIncomplete) {
239 REPORTER_ASSERT(r, 1 == lines); 307 REPORTER_ASSERT(r, 1 == lines);
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 // Webp is the only codec that supports subsets, and it will have mo dified the subset 382 // Webp is the only codec that supports subsets, and it will have mo dified the subset
315 // to have even left/top. 383 // to have even left/top.
316 REPORTER_ASSERT(r, SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTo p)); 384 REPORTER_ASSERT(r, SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTo p));
317 } else { 385 } else {
318 // No subsets will work. 386 // No subsets will work.
319 REPORTER_ASSERT(r, result == SkCodec::kUnimplemented); 387 REPORTER_ASSERT(r, result == SkCodec::kUnimplemented);
320 } 388 }
321 } 389 }
322 390
323 // SkAndroidCodec tests 391 // SkAndroidCodec tests
324 if (supportsScanlineDecoding || supportsSubsetDecoding) { 392 if (supportsScanlineDecoding || supportsSubsetDecoding || supportsNewScanlin eDecoding) {
325 393
326 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); 394 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path));
327 if (!stream) { 395 if (!stream) {
328 return; 396 return;
329 } 397 }
330 398
331 SkAutoTDelete<SkAndroidCodec> androidCodec(nullptr); 399 SkAutoTDelete<SkAndroidCodec> androidCodec(nullptr);
332 if (isIncomplete) { 400 if (isIncomplete) {
333 size_t size = stream->getLength(); 401 size_t size = stream->getLength();
334 sk_sp<SkData> data((SkData::MakeFromStream(stream, 2 * size / 3))); 402 sk_sp<SkData> data((SkData::MakeFromStream(stream, 2 * size / 3)));
(...skipping 17 matching lines...) Expand all
352 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); 420 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path));
353 sk_sp<SkData> fullData(SkData::MakeFromStream(stream, stream->getLength( ))); 421 sk_sp<SkData> fullData(SkData::MakeFromStream(stream, stream->getLength( )));
354 SkAutoTDelete<SkImageGenerator> gen( 422 SkAutoTDelete<SkImageGenerator> gen(
355 SkCodecImageGenerator::NewFromEncodedCodec(fullData.get())); 423 SkCodecImageGenerator::NewFromEncodedCodec(fullData.get()));
356 SkBitmap bm; 424 SkBitmap bm;
357 bm.allocPixels(info); 425 bm.allocPixels(info);
358 SkAutoLockPixels autoLockPixels(bm); 426 SkAutoLockPixels autoLockPixels(bm);
359 REPORTER_ASSERT(r, gen->getPixels(info, bm.getPixels(), bm.rowBytes())); 427 REPORTER_ASSERT(r, gen->getPixels(info, bm.getPixels(), bm.rowBytes()));
360 compare_to_good_digest(r, codecDigest, bm); 428 compare_to_good_digest(r, codecDigest, bm);
361 429
430 #ifndef SK_PNG_DISABLE_TESTS
362 // Test using SkFrontBufferedStream, as Android does 431 // Test using SkFrontBufferedStream, as Android does
363 SkStream* bufferedStream = SkFrontBufferedStream::Create( 432 SkStream* bufferedStream = SkFrontBufferedStream::Create(
364 new SkMemoryStream(std::move(fullData)), SkCodec::MinBufferedByt esNeeded()); 433 new SkMemoryStream(std::move(fullData)), SkCodec::MinBufferedByt esNeeded());
365 REPORTER_ASSERT(r, bufferedStream); 434 REPORTER_ASSERT(r, bufferedStream);
366 codec.reset(SkCodec::NewFromStream(bufferedStream)); 435 codec.reset(SkCodec::NewFromStream(bufferedStream));
367 REPORTER_ASSERT(r, codec); 436 REPORTER_ASSERT(r, codec);
368 if (codec) { 437 if (codec) {
369 test_info(r, codec.get(), info, SkCodec::kSuccess, &codecDigest); 438 test_info(r, codec.get(), info, SkCodec::kSuccess, &codecDigest);
370 } 439 }
440 #endif
371 } 441 }
372 442
373 // If we've just tested incomplete decodes, let's run the same test again on full decodes. 443 // If we've just tested incomplete decodes, let's run the same test again on full decodes.
374 if (isIncomplete) { 444 if (isIncomplete) {
375 check(r, path, size, supportsScanlineDecoding, supportsSubsetDecoding, f alse); 445 check(r, path, size, supportsScanlineDecoding, supportsSubsetDecoding, f alse,
446 supportsNewScanlineDecoding);
376 } 447 }
377 } 448 }
378 449
379 DEF_TEST(Codec, r) { 450 DEF_TEST(Codec, r) {
380 // WBMP 451 // WBMP
381 check(r, "mandrill.wbmp", SkISize::Make(512, 512), true, false); 452 check(r, "mandrill.wbmp", SkISize::Make(512, 512), true, false, true);
382 453
383 // WEBP 454 // WEBP
384 check(r, "baby_tux.webp", SkISize::Make(386, 395), false, true); 455 check(r, "baby_tux.webp", SkISize::Make(386, 395), false, true, true);
385 check(r, "color_wheel.webp", SkISize::Make(128, 128), false, true); 456 check(r, "color_wheel.webp", SkISize::Make(128, 128), false, true, true);
386 check(r, "yellow_rose.webp", SkISize::Make(400, 301), false, true); 457 check(r, "yellow_rose.webp", SkISize::Make(400, 301), false, true, true);
387 458
388 // BMP 459 // BMP
389 check(r, "randPixels.bmp", SkISize::Make(8, 8), true, false); 460 check(r, "randPixels.bmp", SkISize::Make(8, 8), true, false, true);
390 check(r, "rle.bmp", SkISize::Make(320, 240), true, false); 461 check(r, "rle.bmp", SkISize::Make(320, 240), true, false, true);
391 462
392 // ICO 463 // ICO
393 // FIXME: We are not ready to test incomplete ICOs 464 // FIXME: We are not ready to test incomplete ICOs
394 // These two tests examine interestingly different behavior: 465 // These two tests examine interestingly different behavior:
395 // Decodes an embedded BMP image 466 // Decodes an embedded BMP image
396 check(r, "color_wheel.ico", SkISize::Make(128, 128), true, false, false); 467 check(r, "color_wheel.ico", SkISize::Make(128, 128), true, false, false);
397 // Decodes an embedded PNG image 468 // Decodes an embedded PNG image
398 check(r, "google_chrome.ico", SkISize::Make(256, 256), true, false, false); 469 check(r, "google_chrome.ico", SkISize::Make(256, 256), false, false, false, true);
399 470
400 // GIF 471 // GIF
401 // FIXME: We are not ready to test incomplete GIFs 472 // FIXME: We are not ready to test incomplete GIFs
402 check(r, "box.gif", SkISize::Make(200, 55), true, false, false); 473 check(r, "box.gif", SkISize::Make(200, 55), true, false, false);
403 check(r, "color_wheel.gif", SkISize::Make(128, 128), true, false, false); 474 check(r, "color_wheel.gif", SkISize::Make(128, 128), true, false, false);
404 // randPixels.gif is too small to test incomplete 475 // randPixels.gif is too small to test incomplete
405 check(r, "randPixels.gif", SkISize::Make(8, 8), true, false, false); 476 check(r, "randPixels.gif", SkISize::Make(8, 8), true, false, false);
406 477
407 // JPG 478 // JPG
408 check(r, "CMYK.jpg", SkISize::Make(642, 516), true, false); 479 check(r, "CMYK.jpg", SkISize::Make(642, 516), true, false, true);
409 check(r, "color_wheel.jpg", SkISize::Make(128, 128), true, false); 480 check(r, "color_wheel.jpg", SkISize::Make(128, 128), true, false, true);
410 // grayscale.jpg is too small to test incomplete 481 // grayscale.jpg is too small to test incomplete
411 check(r, "grayscale.jpg", SkISize::Make(128, 128), true, false, false); 482 check(r, "grayscale.jpg", SkISize::Make(128, 128), true, false, false);
412 check(r, "mandrill_512_q075.jpg", SkISize::Make(512, 512), true, false); 483 check(r, "mandrill_512_q075.jpg", SkISize::Make(512, 512), true, false, true );
413 // randPixels.jpg is too small to test incomplete 484 // randPixels.jpg is too small to test incomplete
414 check(r, "randPixels.jpg", SkISize::Make(8, 8), true, false, false); 485 check(r, "randPixels.jpg", SkISize::Make(8, 8), true, false, false);
415 486
416 // PNG 487 // PNG
417 check(r, "arrow.png", SkISize::Make(187, 312), true, false, false); 488 check(r, "arrow.png", SkISize::Make(187, 312), false, false, true, true);
418 check(r, "baby_tux.png", SkISize::Make(240, 246), true, false, false); 489 check(r, "baby_tux.png", SkISize::Make(240, 246), false, false, true, true);
419 check(r, "color_wheel.png", SkISize::Make(128, 128), true, false, false); 490 check(r, "color_wheel.png", SkISize::Make(128, 128), false, false, true, tru e);
420 check(r, "half-transparent-white-pixel.png", SkISize::Make(1, 1), true, fals e, false); 491 // half-transparent-white-pixel.png is too small to test incomplete
421 check(r, "mandrill_128.png", SkISize::Make(128, 128), true, false, false); 492 check(r, "half-transparent-white-pixel.png", SkISize::Make(1, 1), false, fal se, false, true);
422 check(r, "mandrill_16.png", SkISize::Make(16, 16), true, false, false); 493 check(r, "mandrill_128.png", SkISize::Make(128, 128), false, false, true, tr ue);
423 check(r, "mandrill_256.png", SkISize::Make(256, 256), true, false, false); 494 check(r, "mandrill_16.png", SkISize::Make(16, 16), false, false, true, true) ;
424 check(r, "mandrill_32.png", SkISize::Make(32, 32), true, false, false); 495 check(r, "mandrill_256.png", SkISize::Make(256, 256), false, false, true, tr ue);
425 check(r, "mandrill_512.png", SkISize::Make(512, 512), true, false, false); 496 check(r, "mandrill_32.png", SkISize::Make(32, 32), false, false, true, true) ;
426 check(r, "mandrill_64.png", SkISize::Make(64, 64), true, false, false); 497 check(r, "mandrill_512.png", SkISize::Make(512, 512), false, false, true, tr ue);
427 check(r, "plane.png", SkISize::Make(250, 126), true, false, false); 498 check(r, "mandrill_64.png", SkISize::Make(64, 64), false, false, true, true) ;
428 // FIXME: We are not ready to test incomplete interlaced pngs 499 check(r, "plane.png", SkISize::Make(250, 126), false, false, true, true);
429 check(r, "plane_interlaced.png", SkISize::Make(250, 126), true, false, false ); 500 check(r, "plane_interlaced.png", SkISize::Make(250, 126), false, false, true , true);
430 check(r, "randPixels.png", SkISize::Make(8, 8), true, false, false); 501 check(r, "randPixels.png", SkISize::Make(8, 8), false, false, true, true);
431 check(r, "yellow_rose.png", SkISize::Make(400, 301), true, false, false); 502 check(r, "yellow_rose.png", SkISize::Make(400, 301), false, false, true, tru e);
432 503
433 // RAW 504 // RAW
434 // Disable RAW tests for Win32. 505 // Disable RAW tests for Win32.
435 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32)) 506 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32))
436 check(r, "sample_1mp.dng", SkISize::Make(600, 338), false, false, false); 507 check(r, "sample_1mp.dng", SkISize::Make(600, 338), false, false, false);
437 check(r, "sample_1mp_rotated.dng", SkISize::Make(600, 338), false, false, fa lse); 508 check(r, "sample_1mp_rotated.dng", SkISize::Make(600, 338), false, false, fa lse);
438 check(r, "dng_with_preview.dng", SkISize::Make(600, 338), true, false, false ); 509 check(r, "dng_with_preview.dng", SkISize::Make(600, 338), true, false, false );
439 #endif 510 #endif
440 } 511 }
441 512
442 // Test interlaced PNG in stripes, similar to DM's kStripe_Mode
443 DEF_TEST(Codec_stripes, r) {
444 const char * path = "plane_interlaced.png";
445 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path));
446 REPORTER_ASSERT(r, stream);
447 if (!stream) {
448 return;
449 }
450
451 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
452 REPORTER_ASSERT(r, codec);
453
454 if (!codec) {
455 return;
456 }
457
458 switch (codec->getScanlineOrder()) {
459 case SkCodec::kBottomUp_SkScanlineOrder:
460 case SkCodec::kOutOfOrder_SkScanlineOrder:
461 ERRORF(r, "This scanline order will not match the original.");
462 return;
463 default:
464 break;
465 }
466
467 // Baseline for what the image should look like, using N32.
468 const SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
469
470 SkBitmap bm;
471 bm.allocPixels(info);
472 SkAutoLockPixels autoLockPixels(bm);
473 SkCodec::Result result = codec->getPixels(info, bm.getPixels(), bm.rowBytes( ));
474 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
475
476 SkMD5::Digest digest;
477 md5(bm, &digest);
478
479 // Now decode in stripes
480 const int height = info.height();
481 const int numStripes = 4;
482 int stripeHeight;
483 int remainingLines;
484 SkTDivMod(height, numStripes, &stripeHeight, &remainingLines);
485
486 bm.eraseColor(SK_ColorYELLOW);
487
488 result = codec->startScanlineDecode(info);
489 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
490
491 // Odd stripes
492 for (int i = 1; i < numStripes; i += 2) {
493 // Skip the even stripes
494 bool skipResult = codec->skipScanlines(stripeHeight);
495 REPORTER_ASSERT(r, skipResult);
496
497 int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeight,
498 bm.rowBytes());
499 REPORTER_ASSERT(r, linesDecoded == stripeHeight);
500 }
501
502 // Even stripes
503 result = codec->startScanlineDecode(info);
504 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
505
506 for (int i = 0; i < numStripes; i += 2) {
507 int linesDecoded = codec->getScanlines(bm.getAddr(0, i * stripeHeight), stripeHeight,
508 bm.rowBytes());
509 REPORTER_ASSERT(r, linesDecoded == stripeHeight);
510
511 // Skip the odd stripes
512 if (i + 1 < numStripes) {
513 bool skipResult = codec->skipScanlines(stripeHeight);
514 REPORTER_ASSERT(r, skipResult);
515 }
516 }
517
518 // Remainder at the end
519 if (remainingLines > 0) {
520 result = codec->startScanlineDecode(info);
521 REPORTER_ASSERT(r, result == SkCodec::kSuccess);
522
523 bool skipResult = codec->skipScanlines(height - remainingLines);
524 REPORTER_ASSERT(r, skipResult);
525
526 int linesDecoded = codec->getScanlines(bm.getAddr(0, height - remainingL ines),
527 remainingLines, bm.rowBytes());
528 REPORTER_ASSERT(r, linesDecoded == remainingLines);
529 }
530
531 compare_to_good_digest(r, digest, bm);
532 }
533
534 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_ t len) { 513 static void test_invalid_stream(skiatest::Reporter* r, const void* stream, size_ t len) {
535 // Neither of these calls should return a codec. Bots should catch us if we leaked anything. 514 // Neither of these calls should return a codec. Bots should catch us if we leaked anything.
536 SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, fals e)); 515 SkCodec* codec = SkCodec::NewFromStream(new SkMemoryStream(stream, len, fals e));
537 REPORTER_ASSERT(r, !codec); 516 REPORTER_ASSERT(r, !codec);
538 517
539 SkAndroidCodec* androidCodec = 518 SkAndroidCodec* androidCodec =
540 SkAndroidCodec::NewFromStream(new SkMemoryStream(stream, len, false) ); 519 SkAndroidCodec::NewFromStream(new SkMemoryStream(stream, len, false) );
541 REPORTER_ASSERT(r, !androidCodec); 520 REPORTER_ASSERT(r, !androidCodec);
542 } 521 }
543 522
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
663 // This image is an ico with an embedded mask-bmp. This is illegal. 642 // This image is an ico with an embedded mask-bmp. This is illegal.
664 test_invalid(r, "invalid_images/mask-bmp-ico.ico"); 643 test_invalid(r, "invalid_images/mask-bmp-ico.ico");
665 } 644 }
666 645
667 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { 646 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) {
668 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); 647 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path));
669 if (!stream) { 648 if (!stream) {
670 return; 649 return;
671 } 650 }
672 SkAutoTDelete<SkCodec> decoder(SkCodec::NewFromStream(stream.release())); 651 SkAutoTDelete<SkCodec> decoder(SkCodec::NewFromStream(stream.release()));
652 if (!decoder) {
653 SkDebugf("Missing codec for %s\n", path);
654 return;
655 }
656
657 const SkImageInfo info = decoder->getInfo().makeColorType(kIndex_8_SkColorTy pe);
673 658
674 // This should return kSuccess because kIndex8 is supported. 659 // This should return kSuccess because kIndex8 is supported.
675 SkPMColor colorStorage[256]; 660 SkPMColor colorStorage[256];
676 int colorCount; 661 int colorCount;
677 SkCodec::Result result = decoder->startScanlineDecode( 662 SkCodec::Result result = decoder->startScanlineDecode(info, nullptr, colorSt orage,
678 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, colorSt orage, &colorCount); 663 &colorCount);
679 REPORTER_ASSERT(r, SkCodec::kSuccess == result); 664 if (SkCodec::kSuccess == result) {
680 // The rest of the test is uninteresting if kIndex8 is not supported 665 // This should return kInvalidParameters because, in kIndex_8 mode, we m ust pass in a valid
681 if (SkCodec::kSuccess != result) { 666 // colorPtr and a valid colorCountPtr.
667 result = decoder->startScanlineDecode(info, nullptr, nullptr, nullptr);
668 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result);
669 result = decoder->startScanlineDecode(info);
670 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result);
671 } else if (SkCodec::kUnimplemented == result) {
672 // New method should be supported:
673 SkBitmap bm;
674 sk_sp<SkColorTable> colorTable(new SkColorTable(colorStorage, 256));
675 bm.allocPixels(info, nullptr, colorTable.get());
676 result = decoder->startIncrementalDecode(info, bm.getPixels(), bm.rowByt es(), nullptr,
677 colorStorage, &colorCount);
678 REPORTER_ASSERT(r, SkCodec::kSuccess == result);
679 result = decoder->startIncrementalDecode(info, bm.getPixels(), bm.rowByt es());
680 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result);
681 } else {
682 // The test is uninteresting if kIndex8 is not supported
683 ERRORF(r, "Should not call test_invalid_parameters for non-Index8 file: %s\n", path);
682 return; 684 return;
683 } 685 }
684 686
685 // This should return kInvalidParameters because, in kIndex_8 mode, we must pass in a valid
686 // colorPtr and a valid colorCountPtr.
687 result = decoder->startScanlineDecode(
688 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, nullptr , nullptr);
689 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result);
690 result = decoder->startScanlineDecode(
691 decoder->getInfo().makeColorType(kIndex_8_SkColorType));
692 REPORTER_ASSERT(r, SkCodec::kInvalidParameters == result);
693 } 687 }
694 688
695 DEF_TEST(Codec_Params, r) { 689 DEF_TEST(Codec_Params, r) {
696 test_invalid_parameters(r, "index8.png"); 690 test_invalid_parameters(r, "index8.png");
697 test_invalid_parameters(r, "mandrill.wbmp"); 691 test_invalid_parameters(r, "mandrill.wbmp");
698 } 692 }
699 693
694 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
695
696 #ifndef SK_PNG_DISABLE_TESTS // reading chunks does not work properly with old er versions.
697 // It does not appear that anyone in Google3 is r eading chunks.
698
700 static void codex_test_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { 699 static void codex_test_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
701 SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr); 700 SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr);
702 if (!sk_stream->write(data, len)) { 701 if (!sk_stream->write(data, len)) {
703 png_error(png_ptr, "sk_write_fn Error!"); 702 png_error(png_ptr, "sk_write_fn Error!");
704 } 703 }
705 } 704 }
706 705
707 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
708 DEF_TEST(Codec_pngChunkReader, r) { 706 DEF_TEST(Codec_pngChunkReader, r) {
709 // Create a dummy bitmap. Use unpremul RGBA for libpng. 707 // Create a dummy bitmap. Use unpremul RGBA for libpng.
710 SkBitmap bm; 708 SkBitmap bm;
711 const int w = 1; 709 const int w = 1;
712 const int h = 1; 710 const int h = 1;
713 const SkImageInfo bmInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType, 711 const SkImageInfo bmInfo = SkImageInfo::Make(w, h, kRGBA_8888_SkColorType,
714 kUnpremul_SkAlphaType); 712 kUnpremul_SkAlphaType);
715 bm.setInfo(bmInfo); 713 bm.setInfo(bmInfo);
716 bm.allocPixels(); 714 bm.allocPixels();
717 bm.eraseColor(SK_ColorBLUE); 715 bm.eraseColor(SK_ColorBLUE);
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
843 compare_to_good_digest(r, goodDigest, decodedBm); 841 compare_to_good_digest(r, goodDigest, decodedBm);
844 REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen()); 842 REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());
845 843
846 // Decoding again will read the chunks again. 844 // Decoding again will read the chunks again.
847 chunkReader.reset(); 845 chunkReader.reset();
848 REPORTER_ASSERT(r, !chunkReader.allHaveBeenSeen()); 846 REPORTER_ASSERT(r, !chunkReader.allHaveBeenSeen());
849 result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(), decodedBm .rowBytes()); 847 result = codec->getPixels(codec->getInfo(), decodedBm.getPixels(), decodedBm .rowBytes());
850 REPORTER_ASSERT(r, SkCodec::kSuccess == result); 848 REPORTER_ASSERT(r, SkCodec::kSuccess == result);
851 REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen()); 849 REPORTER_ASSERT(r, chunkReader.allHaveBeenSeen());
852 } 850 }
851 #endif // SK_PNG_DISABLE_TESTS
853 #endif // PNG_READ_UNKNOWN_CHUNKS_SUPPORTED 852 #endif // PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
854 853
855 // Stream that can only peek up to a limit 854 // Stream that can only peek up to a limit
856 class LimitedPeekingMemStream : public SkStream { 855 class LimitedPeekingMemStream : public SkStream {
857 public: 856 public:
858 LimitedPeekingMemStream(sk_sp<SkData> data, size_t limit) 857 LimitedPeekingMemStream(sk_sp<SkData> data, size_t limit)
859 : fStream(std::move(data)) 858 : fStream(std::move(data))
860 , fLimit(limit) {} 859 , fLimit(limit) {}
861 860
862 size_t peek(void* buf, size_t bytes) const override { 861 size_t peek(void* buf, size_t bytes) const override {
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after
1160 codec.reset(SkCodec::NewFromStream(stream.release())); 1159 codec.reset(SkCodec::NewFromStream(stream.release()));
1161 1160
1162 for (SkAlphaType alphaType : alphaTypes) { 1161 for (SkAlphaType alphaType : alphaTypes) {
1163 SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType) 1162 SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType)
1164 .makeColorSpace(nullptr); 1163 .makeColorSpace(nullptr);
1165 check_round_trip(r, codec.get(), newInfo); 1164 check_round_trip(r, codec.get(), newInfo);
1166 } 1165 }
1167 } 1166 }
1168 1167
1169 static void test_conversion_possible(skiatest::Reporter* r, const char* path, 1168 static void test_conversion_possible(skiatest::Reporter* r, const char* path,
1170 bool testScanlineDecoder) { 1169 bool supportsScanlineDecoder,
1170 bool supportsIncrementalDecoder) {
1171 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); 1171 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path));
1172 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); 1172 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release()));
1173 SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType); 1173 SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType);
1174 1174
1175 SkBitmap bm; 1175 SkBitmap bm;
1176 bm.allocPixels(infoF16); 1176 bm.allocPixels(infoF16);
1177 SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowByt es()); 1177 SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowByt es());
1178 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); 1178 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result);
1179 if (testScanlineDecoder) { 1179
1180 result = codec->startScanlineDecode(infoF16); 1180 result = codec->startScanlineDecode(infoF16);
1181 if (supportsScanlineDecoder) {
1181 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); 1182 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result);
1183 } else {
1184 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result);
1185 }
1186
1187 result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes( ));
1188 if (supportsIncrementalDecoder) {
1189 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result);
1190 } else {
1191 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result);
1182 } 1192 }
1183 1193
1184 infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma()); 1194 infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma());
1185 result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes()); 1195 result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes());
1186 REPORTER_ASSERT(r, SkCodec::kSuccess == result); 1196 REPORTER_ASSERT(r, SkCodec::kSuccess == result);
1187 if (testScanlineDecoder) { 1197 result = codec->startScanlineDecode(infoF16);
1188 result = codec->startScanlineDecode(infoF16); 1198 if (supportsScanlineDecoder) {
1189 REPORTER_ASSERT(r, SkCodec::kSuccess == result); 1199 REPORTER_ASSERT(r, SkCodec::kSuccess == result);
1200 } else {
1201 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result);
1202 }
1203
1204 result = codec->startIncrementalDecode(infoF16, bm.getPixels(), bm.rowBytes( ));
1205 if (supportsIncrementalDecoder) {
1206 REPORTER_ASSERT(r, SkCodec::kSuccess == result);
1207 } else {
1208 REPORTER_ASSERT(r, SkCodec::kUnimplemented == result);
1190 } 1209 }
1191 } 1210 }
1192 1211
1193 DEF_TEST(Codec_F16ConversionPossible, r) { 1212 DEF_TEST(Codec_F16ConversionPossible, r) {
1194 test_conversion_possible(r, "color_wheel.webp", false); 1213 test_conversion_possible(r, "color_wheel.webp", false, false);
1195 test_conversion_possible(r, "mandrill_512_q075.jpg", true); 1214 test_conversion_possible(r, "mandrill_512_q075.jpg", true, false);
1196 test_conversion_possible(r, "yellow_rose.png", true); 1215 test_conversion_possible(r, "yellow_rose.png", false, true);
1197 } 1216 }
1217
1218 // Only rewinds up to a limit.
1219 class LimitedRewindingStream : public SkStream {
1220 public:
1221 static SkStream* Make(const char path[], size_t limit) {
1222 SkStream* stream = GetResourceAsStream(path);
1223 if (!stream) {
1224 return nullptr;
1225 }
1226 return new LimitedRewindingStream(stream, limit);
1227 }
1228
1229 size_t read(void* buffer, size_t size) override {
1230 const size_t bytes = fStream->read(buffer, size);
1231 fPosition += bytes;
1232 return bytes;
1233 }
1234
1235 bool isAtEnd() const override {
1236 return fStream->isAtEnd();
1237 }
1238
1239 bool rewind() override {
1240 if (fPosition <= fLimit && fStream->rewind()) {
1241 fPosition = 0;
1242 return true;
1243 }
1244
1245 return false;
1246 }
1247
1248 private:
1249 SkAutoTDelete<SkStream> fStream;
1250 const size_t fLimit;
1251 size_t fPosition;
1252
1253 LimitedRewindingStream(SkStream* stream, size_t limit)
1254 : fStream(stream)
1255 , fLimit(limit)
1256 , fPosition(0)
1257 {
1258 SkASSERT(fStream);
1259 }
1260 };
1261
1262 DEF_TEST(Codec_fallBack, r) {
1263 // SkAndroidCodec needs to be able to fall back to scanline decoding
1264 // if incremental decoding does not work. Make sure this does not
1265 // require a rewind.
1266
1267 // Formats that currently do not support incremental decoding
1268 auto files = {
1269 "box.gif",
1270 "CMYK.jpg",
1271 "color_wheel.ico",
1272 "mandrill.wbmp",
1273 "randPixels.bmp",
1274 };
1275 for (auto file : files) {
1276 SkStream* stream = LimitedRewindingStream::Make(file, 14);
1277 if (!stream) {
1278 SkDebugf("Missing resources (%s). Set --resourcePath.\n", file);
1279 return;
1280 }
1281
1282 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream));
1283 if (!codec) {
1284 ERRORF(r, "Failed to create codec for %s,", file);
1285 continue;
1286 }
1287
1288 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
1289 SkBitmap bm;
1290 bm.allocPixels(info);
1291
1292 if (SkCodec::kUnimplemented != codec->startIncrementalDecode(info, bm.ge tPixels(),
1293 bm.rowBytes())) {
1294 ERRORF(r, "Is scanline decoding now implemented for %s?", file);
1295 continue;
1296 }
1297
1298 // Scanline decoding should not require a rewind.
1299 SkCodec::Result result = codec->startScanlineDecode(info);
1300 if (SkCodec::kSuccess != result) {
1301 ERRORF(r, "Scanline decoding failed for %s with %i", file, result);
1302 }
1303 }
1304 }
OLDNEW
« no previous file with comments | « tests/CodecPartialTest.cpp ('k') | tests/ImageTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698