| OLD | NEW |
| 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 static SkStreamAsset* resource(const char path[]) { |
| 26 SkString fullPath = GetResourcePath(path); |
| 27 return SkStream::NewFromFile(fullPath.c_str()); |
| 28 } |
| 29 |
| 25 static void md5(const SkBitmap& bm, SkMD5::Digest* digest) { | 30 static void md5(const SkBitmap& bm, SkMD5::Digest* digest) { |
| 26 SkAutoLockPixels autoLockPixels(bm); | 31 SkAutoLockPixels autoLockPixels(bm); |
| 27 SkASSERT(bm.getPixels()); | 32 SkASSERT(bm.getPixels()); |
| 28 SkMD5 md5; | 33 SkMD5 md5; |
| 29 size_t rowLen = bm.info().bytesPerPixel() * bm.width(); | 34 size_t rowLen = bm.info().bytesPerPixel() * bm.width(); |
| 30 for (int y = 0; y < bm.height(); ++y) { | 35 for (int y = 0; y < bm.height(); ++y) { |
| 31 md5.write(bm.getAddr(0, y), rowLen); | 36 md5.write(bm.getAddr(0, y), rowLen); |
| 32 } | 37 } |
| 33 md5.finish(*digest); | 38 md5.finish(*digest); |
| 34 } | 39 } |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 return false; | 192 return false; |
| 188 } | 193 } |
| 189 | 194 |
| 190 static void check(skiatest::Reporter* r, | 195 static void check(skiatest::Reporter* r, |
| 191 const char path[], | 196 const char path[], |
| 192 SkISize size, | 197 SkISize size, |
| 193 bool supportsScanlineDecoding, | 198 bool supportsScanlineDecoding, |
| 194 bool supportsSubsetDecoding, | 199 bool supportsSubsetDecoding, |
| 195 bool supportsIncomplete = true) { | 200 bool supportsIncomplete = true) { |
| 196 | 201 |
| 197 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); | 202 SkAutoTDelete<SkStream> stream(resource(path)); |
| 198 if (!stream) { | 203 if (!stream) { |
| 204 SkDebugf("Missing resource '%s'\n", path); |
| 199 return; | 205 return; |
| 200 } | 206 } |
| 201 | 207 |
| 202 SkAutoTDelete<SkCodec> codec(nullptr); | 208 SkAutoTDelete<SkCodec> codec(nullptr); |
| 203 bool isIncomplete = supportsIncomplete; | 209 bool isIncomplete = supportsIncomplete; |
| 204 if (isIncomplete) { | 210 if (isIncomplete) { |
| 205 size_t size = stream->getLength(); | 211 size_t size = stream->getLength(); |
| 206 sk_sp<SkData> data((SkData::MakeFromStream(stream, 2 * size / 3))); | 212 sk_sp<SkData> data((SkData::MakeFromStream(stream, 2 * size / 3))); |
| 207 codec.reset(SkCodec::NewFromData(data)); | 213 codec.reset(SkCodec::NewFromData(data)); |
| 208 } else { | 214 } else { |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 REPORTER_ASSERT(r, SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTo
p)); | 322 REPORTER_ASSERT(r, SkIsAlign2(subset.fLeft) && SkIsAlign2(subset.fTo
p)); |
| 317 } else { | 323 } else { |
| 318 // No subsets will work. | 324 // No subsets will work. |
| 319 REPORTER_ASSERT(r, result == SkCodec::kUnimplemented); | 325 REPORTER_ASSERT(r, result == SkCodec::kUnimplemented); |
| 320 } | 326 } |
| 321 } | 327 } |
| 322 | 328 |
| 323 // SkAndroidCodec tests | 329 // SkAndroidCodec tests |
| 324 if (supportsScanlineDecoding || supportsSubsetDecoding) { | 330 if (supportsScanlineDecoding || supportsSubsetDecoding) { |
| 325 | 331 |
| 326 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); | 332 SkAutoTDelete<SkStream> stream(resource(path)); |
| 327 if (!stream) { | 333 if (!stream) { |
| 334 SkDebugf("Missing resource '%s'\n", path); |
| 328 return; | 335 return; |
| 329 } | 336 } |
| 330 | 337 |
| 331 SkAutoTDelete<SkAndroidCodec> androidCodec(nullptr); | 338 SkAutoTDelete<SkAndroidCodec> androidCodec(nullptr); |
| 332 if (isIncomplete) { | 339 if (isIncomplete) { |
| 333 size_t size = stream->getLength(); | 340 size_t size = stream->getLength(); |
| 334 sk_sp<SkData> data((SkData::MakeFromStream(stream, 2 * size / 3))); | 341 sk_sp<SkData> data((SkData::MakeFromStream(stream, 2 * size / 3))); |
| 335 androidCodec.reset(SkAndroidCodec::NewFromData(data)); | 342 androidCodec.reset(SkAndroidCodec::NewFromData(data)); |
| 336 } else { | 343 } else { |
| 337 androidCodec.reset(SkAndroidCodec::NewFromStream(stream.release())); | 344 androidCodec.reset(SkAndroidCodec::NewFromStream(stream.release())); |
| 338 } | 345 } |
| 339 if (!androidCodec) { | 346 if (!androidCodec) { |
| 340 ERRORF(r, "Unable to decode '%s'", path); | 347 ERRORF(r, "Unable to decode '%s'", path); |
| 341 return; | 348 return; |
| 342 } | 349 } |
| 343 | 350 |
| 344 SkBitmap bm; | 351 SkBitmap bm; |
| 345 SkMD5::Digest androidCodecDigest; | 352 SkMD5::Digest androidCodecDigest; |
| 346 test_codec(r, androidCodec.get(), bm, info, size, expectedResult, &andro
idCodecDigest, | 353 test_codec(r, androidCodec.get(), bm, info, size, expectedResult, &andro
idCodecDigest, |
| 347 &codecDigest); | 354 &codecDigest); |
| 348 } | 355 } |
| 349 | 356 |
| 350 if (!isIncomplete) { | 357 if (!isIncomplete) { |
| 351 // Test SkCodecImageGenerator | 358 // Test SkCodecImageGenerator |
| 352 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); | 359 SkAutoTDelete<SkStream> stream(resource(path)); |
| 353 sk_sp<SkData> fullData(SkData::MakeFromStream(stream, stream->getLength(
))); | 360 sk_sp<SkData> fullData(SkData::MakeFromStream(stream, stream->getLength(
))); |
| 354 SkAutoTDelete<SkImageGenerator> gen( | 361 SkAutoTDelete<SkImageGenerator> gen( |
| 355 SkCodecImageGenerator::NewFromEncodedCodec(fullData.get())); | 362 SkCodecImageGenerator::NewFromEncodedCodec(fullData.get())); |
| 356 SkBitmap bm; | 363 SkBitmap bm; |
| 357 bm.allocPixels(info); | 364 bm.allocPixels(info); |
| 358 SkAutoLockPixels autoLockPixels(bm); | 365 SkAutoLockPixels autoLockPixels(bm); |
| 359 REPORTER_ASSERT(r, gen->getPixels(info, bm.getPixels(), bm.rowBytes())); | 366 REPORTER_ASSERT(r, gen->getPixels(info, bm.getPixels(), bm.rowBytes())); |
| 360 compare_to_good_digest(r, codecDigest, bm); | 367 compare_to_good_digest(r, codecDigest, bm); |
| 361 | 368 |
| 362 // Test using SkFrontBufferedStream, as Android does | 369 // Test using SkFrontBufferedStream, as Android does |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 435 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32)) | 442 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32)) |
| 436 check(r, "sample_1mp.dng", SkISize::Make(600, 338), false, false, false); | 443 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); | 444 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
); | 445 check(r, "dng_with_preview.dng", SkISize::Make(600, 338), true, false, false
); |
| 439 #endif | 446 #endif |
| 440 } | 447 } |
| 441 | 448 |
| 442 // Test interlaced PNG in stripes, similar to DM's kStripe_Mode | 449 // Test interlaced PNG in stripes, similar to DM's kStripe_Mode |
| 443 DEF_TEST(Codec_stripes, r) { | 450 DEF_TEST(Codec_stripes, r) { |
| 444 const char * path = "plane_interlaced.png"; | 451 const char * path = "plane_interlaced.png"; |
| 445 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); | 452 SkAutoTDelete<SkStream> stream(resource(path)); |
| 446 REPORTER_ASSERT(r, stream); | |
| 447 if (!stream) { | 453 if (!stream) { |
| 448 return; | 454 SkDebugf("Missing resource '%s'\n", path); |
| 449 } | 455 } |
| 450 | 456 |
| 451 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); | 457 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); |
| 452 REPORTER_ASSERT(r, codec); | 458 REPORTER_ASSERT(r, codec); |
| 453 | 459 |
| 454 if (!codec) { | 460 if (!codec) { |
| 455 return; | 461 return; |
| 456 } | 462 } |
| 457 | 463 |
| 458 switch (codec->getScanlineOrder()) { | 464 switch (codec->getScanlineOrder()) { |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 569 // crash. | 575 // crash. |
| 570 SkCodec* codec = SkCodec::NewFromStream(nullptr); | 576 SkCodec* codec = SkCodec::NewFromStream(nullptr); |
| 571 REPORTER_ASSERT(r, !codec); | 577 REPORTER_ASSERT(r, !codec); |
| 572 | 578 |
| 573 SkAndroidCodec* androidCodec = SkAndroidCodec::NewFromStream(nullptr); | 579 SkAndroidCodec* androidCodec = SkAndroidCodec::NewFromStream(nullptr); |
| 574 REPORTER_ASSERT(r, !androidCodec); | 580 REPORTER_ASSERT(r, !androidCodec); |
| 575 } | 581 } |
| 576 | 582 |
| 577 static void test_dimensions(skiatest::Reporter* r, const char path[]) { | 583 static void test_dimensions(skiatest::Reporter* r, const char path[]) { |
| 578 // Create the codec from the resource file | 584 // Create the codec from the resource file |
| 579 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); | 585 SkAutoTDelete<SkStream> stream(resource(path)); |
| 580 if (!stream) { | 586 if (!stream) { |
| 587 SkDebugf("Missing resource '%s'\n", path); |
| 581 return; | 588 return; |
| 582 } | 589 } |
| 583 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(stream.rel
ease())); | 590 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(stream.rel
ease())); |
| 584 if (!codec) { | 591 if (!codec) { |
| 585 ERRORF(r, "Unable to create codec '%s'", path); | 592 ERRORF(r, "Unable to create codec '%s'", path); |
| 586 return; | 593 return; |
| 587 } | 594 } |
| 588 | 595 |
| 589 // Check that the decode is successful for a variety of scales | 596 // Check that the decode is successful for a variety of scales |
| 590 for (int sampleSize = 1; sampleSize < 32; sampleSize++) { | 597 for (int sampleSize = 1; sampleSize < 32; sampleSize++) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 633 // RAW | 640 // RAW |
| 634 // Disable RAW tests for Win32. | 641 // Disable RAW tests for Win32. |
| 635 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32)) | 642 #if defined(SK_CODEC_DECODES_RAW) && (!defined(_WIN32)) |
| 636 test_dimensions(r, "sample_1mp.dng"); | 643 test_dimensions(r, "sample_1mp.dng"); |
| 637 test_dimensions(r, "sample_1mp_rotated.dng"); | 644 test_dimensions(r, "sample_1mp_rotated.dng"); |
| 638 test_dimensions(r, "dng_with_preview.dng"); | 645 test_dimensions(r, "dng_with_preview.dng"); |
| 639 #endif | 646 #endif |
| 640 } | 647 } |
| 641 | 648 |
| 642 static void test_invalid(skiatest::Reporter* r, const char path[]) { | 649 static void test_invalid(skiatest::Reporter* r, const char path[]) { |
| 643 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); | 650 SkAutoTDelete<SkStream> stream(resource(path)); |
| 644 if (!stream) { | 651 if (!stream) { |
| 652 SkDebugf("Missing resource '%s'\n", path); |
| 645 return; | 653 return; |
| 646 } | 654 } |
| 647 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); | 655 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); |
| 648 REPORTER_ASSERT(r, nullptr == codec); | 656 REPORTER_ASSERT(r, nullptr == codec); |
| 649 } | 657 } |
| 650 | 658 |
| 651 DEF_TEST(Codec_Empty, r) { | 659 DEF_TEST(Codec_Empty, r) { |
| 652 // Test images that should not be able to create a codec | 660 // Test images that should not be able to create a codec |
| 653 test_invalid(r, "empty_images/zero-dims.gif"); | 661 test_invalid(r, "empty_images/zero-dims.gif"); |
| 654 test_invalid(r, "empty_images/zero-embedded.ico"); | 662 test_invalid(r, "empty_images/zero-embedded.ico"); |
| 655 test_invalid(r, "empty_images/zero-width.bmp"); | 663 test_invalid(r, "empty_images/zero-width.bmp"); |
| 656 test_invalid(r, "empty_images/zero-height.bmp"); | 664 test_invalid(r, "empty_images/zero-height.bmp"); |
| 657 test_invalid(r, "empty_images/zero-width.jpg"); | 665 test_invalid(r, "empty_images/zero-width.jpg"); |
| 658 test_invalid(r, "empty_images/zero-height.jpg"); | 666 test_invalid(r, "empty_images/zero-height.jpg"); |
| 659 test_invalid(r, "empty_images/zero-width.png"); | 667 test_invalid(r, "empty_images/zero-width.png"); |
| 660 test_invalid(r, "empty_images/zero-height.png"); | 668 test_invalid(r, "empty_images/zero-height.png"); |
| 661 test_invalid(r, "empty_images/zero-width.wbmp"); | 669 test_invalid(r, "empty_images/zero-width.wbmp"); |
| 662 test_invalid(r, "empty_images/zero-height.wbmp"); | 670 test_invalid(r, "empty_images/zero-height.wbmp"); |
| 663 // This image is an ico with an embedded mask-bmp. This is illegal. | 671 // This image is an ico with an embedded mask-bmp. This is illegal. |
| 664 test_invalid(r, "invalid_images/mask-bmp-ico.ico"); | 672 test_invalid(r, "invalid_images/mask-bmp-ico.ico"); |
| 665 } | 673 } |
| 666 | 674 |
| 667 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { | 675 static void test_invalid_parameters(skiatest::Reporter* r, const char path[]) { |
| 668 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); | 676 SkAutoTDelete<SkStream> stream(resource(path)); |
| 669 if (!stream) { | 677 if (!stream) { |
| 678 SkDebugf("Missing resource '%s'\n", path); |
| 670 return; | 679 return; |
| 671 } | 680 } |
| 672 SkAutoTDelete<SkCodec> decoder(SkCodec::NewFromStream(stream.release())); | 681 SkAutoTDelete<SkCodec> decoder(SkCodec::NewFromStream(stream.release())); |
| 673 | 682 |
| 674 // This should return kSuccess because kIndex8 is supported. | 683 // This should return kSuccess because kIndex8 is supported. |
| 675 SkPMColor colorStorage[256]; | 684 SkPMColor colorStorage[256]; |
| 676 int colorCount; | 685 int colorCount; |
| 677 SkCodec::Result result = decoder->startScanlineDecode( | 686 SkCodec::Result result = decoder->startScanlineDecode( |
| 678 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, colorSt
orage, &colorCount); | 687 decoder->getInfo().makeColorType(kIndex_8_SkColorType), nullptr, colorSt
orage, &colorCount); |
| 679 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 688 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 949 | 958 |
| 950 test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr); | 959 test_info(r, codec.get(), codec->getInfo(), SkCodec::kSuccess, nullptr); |
| 951 } | 960 } |
| 952 | 961 |
| 953 // SkCodec's wbmp decoder was initially unnecessarily restrictive. | 962 // SkCodec's wbmp decoder was initially unnecessarily restrictive. |
| 954 // It required the second byte to be zero. The wbmp specification allows | 963 // It required the second byte to be zero. The wbmp specification allows |
| 955 // a couple of bits to be 1 (so long as they do not overlap with 0x9F). | 964 // a couple of bits to be 1 (so long as they do not overlap with 0x9F). |
| 956 // Test that SkCodec now supports an image with these bits set. | 965 // Test that SkCodec now supports an image with these bits set. |
| 957 DEF_TEST(Codec_wbmp, r) { | 966 DEF_TEST(Codec_wbmp, r) { |
| 958 const char* path = "mandrill.wbmp"; | 967 const char* path = "mandrill.wbmp"; |
| 959 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); | 968 SkAutoTDelete<SkStream> stream(resource(path)); |
| 960 if (!stream) { | 969 if (!stream) { |
| 970 SkDebugf("Missing resource '%s'\n", path); |
| 961 return; | 971 return; |
| 962 } | 972 } |
| 963 | 973 |
| 964 // Modify the stream to contain a second byte with some bits set. | 974 // Modify the stream to contain a second byte with some bits set. |
| 965 auto data = SkCopyStreamToData(stream); | 975 auto data = SkCopyStreamToData(stream); |
| 966 uint8_t* writeableData = static_cast<uint8_t*>(data->writable_data()); | 976 uint8_t* writeableData = static_cast<uint8_t*>(data->writable_data()); |
| 967 writeableData[1] = static_cast<uint8_t>(~0x9F); | 977 writeableData[1] = static_cast<uint8_t>(~0x9F); |
| 968 | 978 |
| 969 // SkCodec should support this. | 979 // SkCodec should support this. |
| 970 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data)); | 980 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data)); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 999 0x84, 0x80, 0x00, // W: 65536 | 1009 0x84, 0x80, 0x00, // W: 65536 |
| 1000 0x84, 0x80, 0x00 }; // H: 65536 | 1010 0x84, 0x80, 0x00 }; // H: 65536 |
| 1001 stream.reset(new SkMemoryStream(tooBigWbmp, sizeof(tooBigWbmp), false)); | 1011 stream.reset(new SkMemoryStream(tooBigWbmp, sizeof(tooBigWbmp), false)); |
| 1002 codec.reset(SkCodec::NewFromStream(stream.release())); | 1012 codec.reset(SkCodec::NewFromStream(stream.release())); |
| 1003 | 1013 |
| 1004 REPORTER_ASSERT(r, !codec); | 1014 REPORTER_ASSERT(r, !codec); |
| 1005 } | 1015 } |
| 1006 | 1016 |
| 1007 DEF_TEST(Codec_jpeg_rewind, r) { | 1017 DEF_TEST(Codec_jpeg_rewind, r) { |
| 1008 const char* path = "mandrill_512_q075.jpg"; | 1018 const char* path = "mandrill_512_q075.jpg"; |
| 1009 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); | 1019 SkAutoTDelete<SkStream> stream(resource(path)); |
| 1010 if (!stream) { | 1020 if (!stream) { |
| 1021 SkDebugf("Missing resource '%s'\n", path); |
| 1011 return; | 1022 return; |
| 1012 } | 1023 } |
| 1013 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(stream.rel
ease())); | 1024 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(stream.rel
ease())); |
| 1014 if (!codec) { | 1025 if (!codec) { |
| 1015 ERRORF(r, "Unable to create codec '%s'.", path); | 1026 ERRORF(r, "Unable to create codec '%s'.", path); |
| 1016 return; | 1027 return; |
| 1017 } | 1028 } |
| 1018 | 1029 |
| 1019 const int width = codec->getInfo().width(); | 1030 const int width = codec->getInfo().width(); |
| 1020 const int height = codec->getInfo().height(); | 1031 const int height = codec->getInfo().height(); |
| 1021 size_t rowBytes = sizeof(SkPMColor) * width; | 1032 size_t rowBytes = sizeof(SkPMColor) * width; |
| 1022 SkAutoMalloc pixelStorage(height * rowBytes); | 1033 SkAutoMalloc pixelStorage(height * rowBytes); |
| 1023 | 1034 |
| 1024 // Perform a sampled decode. | 1035 // Perform a sampled decode. |
| 1025 SkAndroidCodec::AndroidOptions opts; | 1036 SkAndroidCodec::AndroidOptions opts; |
| 1026 opts.fSampleSize = 12; | 1037 opts.fSampleSize = 12; |
| 1027 codec->getAndroidPixels(codec->getInfo().makeWH(width / 12, height / 12), pi
xelStorage.get(), | 1038 codec->getAndroidPixels(codec->getInfo().makeWH(width / 12, height / 12), pi
xelStorage.get(), |
| 1028 rowBytes, &opts); | 1039 rowBytes, &opts); |
| 1029 | 1040 |
| 1030 // Rewind the codec and perform a full image decode. | 1041 // Rewind the codec and perform a full image decode. |
| 1031 SkCodec::Result result = codec->getPixels(codec->getInfo(), pixelStorage.get
(), rowBytes); | 1042 SkCodec::Result result = codec->getPixels(codec->getInfo(), pixelStorage.get
(), rowBytes); |
| 1032 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 1043 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 1033 } | 1044 } |
| 1034 | 1045 |
| 1035 static void check_color_xform(skiatest::Reporter* r, const char* path) { | 1046 static void check_color_xform(skiatest::Reporter* r, const char* path) { |
| 1036 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(GetResourc
eAsStream(path))); | 1047 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(resource(p
ath))); |
| 1037 | 1048 |
| 1038 SkAndroidCodec::AndroidOptions opts; | 1049 SkAndroidCodec::AndroidOptions opts; |
| 1039 opts.fSampleSize = 3; | 1050 opts.fSampleSize = 3; |
| 1040 const int subsetWidth = codec->getInfo().width() / 2; | 1051 const int subsetWidth = codec->getInfo().width() / 2; |
| 1041 const int subsetHeight = codec->getInfo().height() / 2; | 1052 const int subsetHeight = codec->getInfo().height() / 2; |
| 1042 SkIRect subset = SkIRect::MakeWH(subsetWidth, subsetHeight); | 1053 SkIRect subset = SkIRect::MakeWH(subsetWidth, subsetHeight); |
| 1043 opts.fSubset = ⊂ | 1054 opts.fSubset = ⊂ |
| 1044 | 1055 |
| 1045 const int dstWidth = subsetWidth / opts.fSampleSize; | 1056 const int dstWidth = subsetWidth / opts.fSampleSize; |
| 1046 const int dstHeight = subsetHeight / opts.fSampleSize; | 1057 const int dstHeight = subsetHeight / opts.fSampleSize; |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1112 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 1123 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 1113 | 1124 |
| 1114 SkMD5::Digest d1, d2; | 1125 SkMD5::Digest d1, d2; |
| 1115 md5(bm1, &d1); | 1126 md5(bm1, &d1); |
| 1116 md5(bm2, &d2); | 1127 md5(bm2, &d2); |
| 1117 REPORTER_ASSERT(r, d1 == d2); | 1128 REPORTER_ASSERT(r, d1 == d2); |
| 1118 } | 1129 } |
| 1119 | 1130 |
| 1120 DEF_TEST(Codec_PngRoundTrip, r) { | 1131 DEF_TEST(Codec_PngRoundTrip, r) { |
| 1121 const char* path = "mandrill_512_q075.jpg"; | 1132 const char* path = "mandrill_512_q075.jpg"; |
| 1122 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); | 1133 SkAutoTDelete<SkStream> stream(resource(path)); |
| 1123 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); | 1134 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); |
| 1124 | 1135 |
| 1125 SkColorType colorTypesOpaque[] = { | 1136 SkColorType colorTypesOpaque[] = { |
| 1126 kRGB_565_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType | 1137 kRGB_565_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType |
| 1127 }; | 1138 }; |
| 1128 for (SkColorType colorType : colorTypesOpaque) { | 1139 for (SkColorType colorType : colorTypesOpaque) { |
| 1129 SkImageInfo newInfo = codec->getInfo().makeColorType(colorType); | 1140 SkImageInfo newInfo = codec->getInfo().makeColorType(colorType); |
| 1130 check_round_trip(r, codec.get(), newInfo); | 1141 check_round_trip(r, codec.get(), newInfo); |
| 1131 } | 1142 } |
| 1132 | 1143 |
| 1133 path = "grayscale.jpg"; | 1144 path = "grayscale.jpg"; |
| 1134 stream.reset(GetResourceAsStream(path)); | 1145 stream.reset(resource(path)); |
| 1135 codec.reset(SkCodec::NewFromStream(stream.release())); | 1146 codec.reset(SkCodec::NewFromStream(stream.release())); |
| 1136 check_round_trip(r, codec.get(), codec->getInfo()); | 1147 check_round_trip(r, codec.get(), codec->getInfo()); |
| 1137 | 1148 |
| 1138 path = "yellow_rose.png"; | 1149 path = "yellow_rose.png"; |
| 1139 stream.reset(GetResourceAsStream(path)); | 1150 stream.reset(resource(path)); |
| 1140 codec.reset(SkCodec::NewFromStream(stream.release())); | 1151 codec.reset(SkCodec::NewFromStream(stream.release())); |
| 1141 | 1152 |
| 1142 SkColorType colorTypesWithAlpha[] = { | 1153 SkColorType colorTypesWithAlpha[] = { |
| 1143 kRGBA_8888_SkColorType, kBGRA_8888_SkColorType | 1154 kRGBA_8888_SkColorType, kBGRA_8888_SkColorType |
| 1144 }; | 1155 }; |
| 1145 SkAlphaType alphaTypes[] = { | 1156 SkAlphaType alphaTypes[] = { |
| 1146 kUnpremul_SkAlphaType, kPremul_SkAlphaType | 1157 kUnpremul_SkAlphaType, kPremul_SkAlphaType |
| 1147 }; | 1158 }; |
| 1148 for (SkColorType colorType : colorTypesWithAlpha) { | 1159 for (SkColorType colorType : colorTypesWithAlpha) { |
| 1149 for (SkAlphaType alphaType : alphaTypes) { | 1160 for (SkAlphaType alphaType : alphaTypes) { |
| 1150 // Set color space to nullptr because color correct premultiplies do
not round trip. | 1161 // Set color space to nullptr because color correct premultiplies do
not round trip. |
| 1151 SkImageInfo newInfo = codec->getInfo().makeColorType(colorType) | 1162 SkImageInfo newInfo = codec->getInfo().makeColorType(colorType) |
| 1152 .makeAlphaType(alphaType) | 1163 .makeAlphaType(alphaType) |
| 1153 .makeColorSpace(nullptr); | 1164 .makeColorSpace(nullptr); |
| 1154 check_round_trip(r, codec.get(), newInfo); | 1165 check_round_trip(r, codec.get(), newInfo); |
| 1155 } | 1166 } |
| 1156 } | 1167 } |
| 1157 | 1168 |
| 1158 path = "index8.png"; | 1169 path = "index8.png"; |
| 1159 stream.reset(GetResourceAsStream(path)); | 1170 stream.reset(resource(path)); |
| 1160 codec.reset(SkCodec::NewFromStream(stream.release())); | 1171 codec.reset(SkCodec::NewFromStream(stream.release())); |
| 1161 | 1172 |
| 1162 for (SkAlphaType alphaType : alphaTypes) { | 1173 for (SkAlphaType alphaType : alphaTypes) { |
| 1163 SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType) | 1174 SkImageInfo newInfo = codec->getInfo().makeAlphaType(alphaType) |
| 1164 .makeColorSpace(nullptr); | 1175 .makeColorSpace(nullptr); |
| 1165 check_round_trip(r, codec.get(), newInfo); | 1176 check_round_trip(r, codec.get(), newInfo); |
| 1166 } | 1177 } |
| 1167 } | 1178 } |
| 1168 | 1179 |
| 1169 static void test_conversion_possible(skiatest::Reporter* r, const char* path, | 1180 static void test_conversion_possible(skiatest::Reporter* r, const char* path, |
| 1170 bool testScanlineDecoder) { | 1181 bool testScanlineDecoder) { |
| 1171 SkAutoTDelete<SkStream> stream(GetResourceAsStream(path)); | 1182 SkAutoTDelete<SkStream> stream(resource(path)); |
| 1172 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); | 1183 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream.release())); |
| 1173 SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType); | 1184 SkImageInfo infoF16 = codec->getInfo().makeColorType(kRGBA_F16_SkColorType); |
| 1174 | 1185 |
| 1175 SkBitmap bm; | 1186 SkBitmap bm; |
| 1176 bm.allocPixels(infoF16); | 1187 bm.allocPixels(infoF16); |
| 1177 SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowByt
es()); | 1188 SkCodec::Result result = codec->getPixels(infoF16, bm.getPixels(), bm.rowByt
es()); |
| 1178 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); | 1189 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
| 1179 if (testScanlineDecoder) { | 1190 if (testScanlineDecoder) { |
| 1180 result = codec->startScanlineDecode(infoF16); | 1191 result = codec->startScanlineDecode(infoF16); |
| 1181 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); | 1192 REPORTER_ASSERT(r, SkCodec::kInvalidConversion == result); |
| 1182 } | 1193 } |
| 1183 | 1194 |
| 1184 infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma()); | 1195 infoF16 = infoF16.makeColorSpace(infoF16.colorSpace()->makeLinearGamma()); |
| 1185 result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes()); | 1196 result = codec->getPixels(infoF16, bm.getPixels(), bm.rowBytes()); |
| 1186 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 1197 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 1187 if (testScanlineDecoder) { | 1198 if (testScanlineDecoder) { |
| 1188 result = codec->startScanlineDecode(infoF16); | 1199 result = codec->startScanlineDecode(infoF16); |
| 1189 REPORTER_ASSERT(r, SkCodec::kSuccess == result); | 1200 REPORTER_ASSERT(r, SkCodec::kSuccess == result); |
| 1190 } | 1201 } |
| 1191 } | 1202 } |
| 1192 | 1203 |
| 1193 DEF_TEST(Codec_F16ConversionPossible, r) { | 1204 DEF_TEST(Codec_F16ConversionPossible, r) { |
| 1194 test_conversion_possible(r, "color_wheel.webp", false); | 1205 test_conversion_possible(r, "color_wheel.webp", false); |
| 1195 test_conversion_possible(r, "mandrill_512_q075.jpg", true); | 1206 test_conversion_possible(r, "mandrill_512_q075.jpg", true); |
| 1196 test_conversion_possible(r, "yellow_rose.png", true); | 1207 test_conversion_possible(r, "yellow_rose.png", true); |
| 1197 } | 1208 } |
| OLD | NEW |