Reland "Add an SkImageGenerator that uses NDK APIs"

This reverts commit 07438b0cda.

Bug: skia:10369
Bug: skia:10371

This will allow Skia clients developing for Android 11+ to rely on
Android's NDK APIs for decoding, which will allow them to decode
without including their own decoding libraries (e.g. libjpeg-turbo).
Using these APIs also provides support for static HEIF images.

Run ImageGenSrc in kPlatform_Mode on Android to verify decoding
visually.

Add tests and a grayscale png.

Update some test bots running Android R to specify ndk_api so they will
run the new code.

Change-Id: I4ca07d832dbd6a9d8cff0faea975fd70da00718f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/308185
Reviewed-by: Mike Klein <mtklein@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
This commit is contained in:
Leon Scroggins III 2020-08-05 10:44:17 -04:00 committed by Skia Commit-Bot
parent 749149278c
commit f21d6b9b71
13 changed files with 1101 additions and 18 deletions

View File

@ -820,6 +820,13 @@ optional("jpeg_encode") {
]
}
optional("ndk_decode") {
enabled = skia_use_ndk_decode
public_defines = [ "SK_ENABLE_NDK_DECODING" ]
sources = [ "src/ports/SkImageGeneratorNDK.cpp" ]
libs = [ "jnigraphics" ]
}
optional("pdf") {
enabled = skia_use_zlib && skia_enable_pdf
public_defines = [ "SK_SUPPORT_PDF" ]
@ -1044,6 +1051,7 @@ component("skia") {
":hsw",
":jpeg_decode",
":jpeg_encode",
":ndk_decode",
":none",
":png_decode",
":png_encode",

View File

@ -7,6 +7,9 @@ This file includes a list of high level updates for each milestone release.
Milestone 86
------------
* Add SkImageGeneratorNDK for using Android's NDK APIs to decode.
https://review.skia.org/305689
* SkImage:remove DecodeToRaster, DecodeToTexture
https://review.skia.org/306331

View File

@ -838,6 +838,8 @@ static void push_codec_srcs(Path path) {
{
push_image_gen_src(path, ImageGenSrc::kPlatform_Mode, alphaType, false);
}
#elif defined(SK_ENABLE_NDK_DECODING)
push_image_gen_src(path, ImageGenSrc::kPlatform_Mode, alphaType, false);
#endif
}
}

View File

@ -24,6 +24,7 @@
#include "include/gpu/GrBackendSurface.h"
#include "include/gpu/GrDirectContext.h"
#include "include/ports/SkImageGeneratorCG.h"
#include "include/ports/SkImageGeneratorNDK.h"
#include "include/ports/SkImageGeneratorWIC.h"
#include "include/private/SkImageInfoPriv.h"
#include "include/private/SkTLogic.h"
@ -923,6 +924,8 @@ Result ImageGenSrc::draw(GrDirectContext*, SkCanvas* canvas) const {
gen = SkImageGeneratorCG::MakeFromEncodedCG(encoded);
#elif defined(SK_BUILD_FOR_WIN)
gen = SkImageGeneratorWIC::MakeFromEncodedWIC(encoded);
#elif defined(SK_ENABLE_NDK_DECODING)
gen = SkImageGeneratorNDK::MakeFromEncodedNDK(encoded);
#endif
if (!gen) {
return Result::Fatal("Could not create platform image generator.");

View File

@ -64,6 +64,7 @@ declare_args() {
skia_use_libwebp_encode = true
skia_use_lua = is_skia_dev_build && !is_ios
skia_use_metal = false
skia_use_ndk_decode = is_android && defined(ndk_api) && ndk_api >= 30
skia_use_opencl = false
skia_use_piex = !is_win
skia_use_wuffs = false

View File

@ -161,6 +161,7 @@ tests_sources = [
"$_tests/MetaDataTest.cpp",
"$_tests/MipMapTest.cpp",
"$_tests/MultiPictureDocumentTest.cpp",
"$_tests/NdkDecodeTest.cpp",
"$_tests/NonlinearBlendingTest.cpp",
"$_tests/OSPathTest.cpp",
"$_tests/OctoBoundsTest.cpp",

View File

@ -0,0 +1,36 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkTypes.h"
#ifdef SK_ENABLE_NDK_DECODING
#include "include/core/SkData.h"
#include "include/core/SkImageGenerator.h"
#include <memory>
namespace SkImageGeneratorNDK {
/**
* Create a generator that uses the Android NDK's APIs for decoding images.
*
* Only supported on devices where __ANDROID_API__ >= 30.
*
* As with SkCodec, the SkColorSpace passed to getPixels() determines the
* type of color space transformations to apply. A null SkColorSpace means to
* apply none.
*
* A note on scaling: Calling getPixels() on the resulting SkImageGenerator
* with dimensions that do not match getInfo() requests a scale. For WebP
* files, dimensions smaller than those of getInfo are supported. For Jpeg
* files, dimensions of 1/2, 1/4, and 1/8 are supported. TODO: Provide an
* API like SkCodecImageGenerator::getScaledDimensions() to report which
* dimensions are supported?
*/
SK_API std::unique_ptr<SkImageGenerator> MakeFromEncodedNDK(sk_sp<SkData>);
}
#endif

View File

@ -17,10 +17,12 @@
"Build-Debian10-Clang-arm-Release-Android_Vulkan",
"Build-Debian10-Clang-arm-Release-Chromebook_GLES",
"Build-Debian10-Clang-arm64-Debug-Android",
"Build-Debian10-Clang-arm64-Debug-Android_API30",
"Build-Debian10-Clang-arm64-Debug-Android_ASAN",
"Build-Debian10-Clang-arm64-Debug-Android_ASAN_Vulkan",
"Build-Debian10-Clang-arm64-Debug-Android_Vulkan",
"Build-Debian10-Clang-arm64-Release-Android",
"Build-Debian10-Clang-arm64-Release-Android_API30",
"Build-Debian10-Clang-arm64-Release-Android_Vulkan",
"Build-Debian10-Clang-arm64-Release-Android_Wuffs",
"Build-Debian10-Clang-x64-Debug-Android",
@ -386,9 +388,9 @@
"Test-Android-Clang-Pixel3a-GPU-Adreno615-arm64-Debug-All-Android_Vulkan",
"Test-Android-Clang-Pixel3a-GPU-Adreno615-arm64-Release-All-Android",
"Test-Android-Clang-Pixel3a-GPU-Adreno615-arm64-Release-All-Android_Vulkan",
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android",
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_API30",
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_Vulkan",
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android",
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android_API30",
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android_Vulkan",
"Test-Android-Clang-Pixel4XL-GPU-Adreno640-arm64-Debug-All-Android",
"Test-Android-Clang-Pixel4XL-GPU-Adreno640-arm64-Debug-All-Android_Vulkan",

View File

@ -50,6 +50,11 @@
"Build-Debian10-Clang-arm64-Debug-Android"
]
},
"Build-Debian10-Clang-arm64-Debug-Android_API30": {
"tasks": [
"Build-Debian10-Clang-arm64-Debug-Android_API30"
]
},
"Build-Debian10-Clang-arm64-Debug-Android_ASAN": {
"tasks": [
"Build-Debian10-Clang-arm64-Debug-Android_ASAN"
@ -70,6 +75,11 @@
"Build-Debian10-Clang-arm64-Release-Android"
]
},
"Build-Debian10-Clang-arm64-Release-Android_API30": {
"tasks": [
"Build-Debian10-Clang-arm64-Release-Android_API30"
]
},
"Build-Debian10-Clang-arm64-Release-Android_Vulkan": {
"tasks": [
"Build-Debian10-Clang-arm64-Release-Android_Vulkan"
@ -1953,9 +1963,9 @@
"Upload-Test-Android-Clang-Pixel3a-GPU-Adreno615-arm64-Release-All-Android_Vulkan"
]
},
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android": {
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_API30": {
"tasks": [
"Upload-Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android"
"Upload-Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_API30"
]
},
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_Vulkan": {
@ -1963,9 +1973,9 @@
"Upload-Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_Vulkan"
]
},
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android": {
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android_API30": {
"tasks": [
"Upload-Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android"
"Upload-Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android_API30"
]
},
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android_Vulkan": {
@ -4062,6 +4072,76 @@
],
"service_account": "skia-external-compile-tasks@skia-swarming-bots.iam.gserviceaccount.com"
},
"Build-Debian10-Clang-arm64-Debug-Android_API30": {
"caches": [
{
"name": "vpython",
"path": "cache/vpython"
}
],
"cipd_packages": [
{
"name": "infra/tools/luci-auth/${platform}",
"path": "cipd_bin_packages",
"version": "git_revision:08768c6d238082f3c552dcabef6aaf4c6792d91a"
},
{
"name": "infra/tools/luci/kitchen/${platform}",
"path": ".",
"version": "git_revision:08768c6d238082f3c552dcabef6aaf4c6792d91a"
},
{
"name": "infra/tools/luci/vpython/${platform}",
"path": "cipd_bin_packages",
"version": "git_revision:08768c6d238082f3c552dcabef6aaf4c6792d91a"
},
{
"name": "skia/bots/android_ndk_linux",
"path": "android_ndk_linux",
"version": "version:16"
}
],
"command": [
"cipd_bin_packages/vpython${EXECUTABLE_SUFFIX}",
"-u",
"skia/infra/bots/run_recipe.py",
"${ISOLATED_OUTDIR}",
"compile",
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildername\":\"Build-Debian10-Clang-arm64-Debug-Android_API30\",\"swarm_out_dir\":\"build\"}",
"skia"
],
"dependencies": [
"Housekeeper-PerCommit-BundleRecipes"
],
"dimensions": [
"cpu:x86-64-Haswell_GCE",
"gpu:none",
"machine_type:n1-highcpu-64",
"os:Debian-10.3",
"pool:Skia"
],
"env_prefixes": {
"PATH": [
"cipd_bin_packages",
"cipd_bin_packages/bin"
],
"VPYTHON_VIRTUALENV_ROOT": [
"cache/vpython"
]
},
"execution_timeout_ns": 3600000000000,
"extra_tags": {
"log_location": "logdog://logs.chromium.org/skia/${SWARMING_TASK_ID}/+/annotations"
},
"idempotent": true,
"io_timeout_ns": 3600000000000,
"isolate": "compile.isolate",
"max_attempts": 2,
"outputs": [
"build"
],
"service_account": "skia-external-compile-tasks@skia-swarming-bots.iam.gserviceaccount.com"
},
"Build-Debian10-Clang-arm64-Debug-Android_ASAN": {
"caches": [
{
@ -4342,6 +4422,76 @@
],
"service_account": "skia-external-compile-tasks@skia-swarming-bots.iam.gserviceaccount.com"
},
"Build-Debian10-Clang-arm64-Release-Android_API30": {
"caches": [
{
"name": "vpython",
"path": "cache/vpython"
}
],
"cipd_packages": [
{
"name": "infra/tools/luci-auth/${platform}",
"path": "cipd_bin_packages",
"version": "git_revision:08768c6d238082f3c552dcabef6aaf4c6792d91a"
},
{
"name": "infra/tools/luci/kitchen/${platform}",
"path": ".",
"version": "git_revision:08768c6d238082f3c552dcabef6aaf4c6792d91a"
},
{
"name": "infra/tools/luci/vpython/${platform}",
"path": "cipd_bin_packages",
"version": "git_revision:08768c6d238082f3c552dcabef6aaf4c6792d91a"
},
{
"name": "skia/bots/android_ndk_linux",
"path": "android_ndk_linux",
"version": "version:16"
}
],
"command": [
"cipd_bin_packages/vpython${EXECUTABLE_SUFFIX}",
"-u",
"skia/infra/bots/run_recipe.py",
"${ISOLATED_OUTDIR}",
"compile",
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildername\":\"Build-Debian10-Clang-arm64-Release-Android_API30\",\"swarm_out_dir\":\"build\"}",
"skia"
],
"dependencies": [
"Housekeeper-PerCommit-BundleRecipes"
],
"dimensions": [
"cpu:x86-64-Haswell_GCE",
"gpu:none",
"machine_type:n1-highcpu-64",
"os:Debian-10.3",
"pool:Skia"
],
"env_prefixes": {
"PATH": [
"cipd_bin_packages",
"cipd_bin_packages/bin"
],
"VPYTHON_VIRTUALENV_ROOT": [
"cache/vpython"
]
},
"execution_timeout_ns": 3600000000000,
"extra_tags": {
"log_location": "logdog://logs.chromium.org/skia/${SWARMING_TASK_ID}/+/annotations"
},
"idempotent": true,
"io_timeout_ns": 3600000000000,
"isolate": "compile.isolate",
"max_attempts": 2,
"outputs": [
"build"
],
"service_account": "skia-external-compile-tasks@skia-swarming-bots.iam.gserviceaccount.com"
},
"Build-Debian10-Clang-arm64-Release-Android_Vulkan": {
"caches": [
{
@ -32290,7 +32440,7 @@
"test"
]
},
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android": {
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_API30": {
"caches": [
{
"name": "vpython",
@ -32320,11 +32470,11 @@
"skia/infra/bots/run_recipe.py",
"${ISOLATED_OUTDIR}",
"test",
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"arm64\\\",\\\"compiler\\\",\\\"Clang\\\",\\\"configuration\\\",\\\"Debug\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"Adreno640\\\",\\\"extra_config\\\",\\\"Android\\\",\\\"model\\\",\\\"Pixel4\\\",\\\"os\\\",\\\"Android\\\",\\\"style\\\",\\\"default\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"gles\\\",\\\"glesdft\\\",\\\"glessrgb\\\",\\\"glesmsaa4\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--skip\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"glessrgb\\\",\\\"image\\\",\\\"_\\\",\\\"_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"test\\\",\\\"_\\\",\\\"GrStyledShape\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_API30\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"arm64\\\",\\\"compiler\\\",\\\"Clang\\\",\\\"configuration\\\",\\\"Debug\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"Adreno640\\\",\\\"extra_config\\\",\\\"Android_API30\\\",\\\"model\\\",\\\"Pixel4\\\",\\\"os\\\",\\\"Android\\\",\\\"style\\\",\\\"default\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"gles\\\",\\\"glesdft\\\",\\\"glessrgb\\\",\\\"glesmsaa4\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--skip\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"glessrgb\\\",\\\"image\\\",\\\"_\\\",\\\"_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"test\\\",\\\"_\\\",\\\"GrStyledShape\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_API30\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
"skia"
],
"dependencies": [
"Build-Debian10-Clang-arm64-Debug-Android",
"Build-Debian10-Clang-arm64-Debug-Android_API30",
"Housekeeper-PerCommit-BundleRecipes",
"Housekeeper-PerCommit-IsolateSKP",
"Housekeeper-PerCommit-IsolateSVG",
@ -32424,7 +32574,7 @@
"test"
]
},
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android": {
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android_API30": {
"caches": [
{
"name": "vpython",
@ -32454,11 +32604,11 @@
"skia/infra/bots/run_recipe.py",
"${ISOLATED_OUTDIR}",
"test",
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"arm64\\\",\\\"compiler\\\",\\\"Clang\\\",\\\"configuration\\\",\\\"Release\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"Adreno640\\\",\\\"extra_config\\\",\\\"Android\\\",\\\"model\\\",\\\"Pixel4\\\",\\\"os\\\",\\\"Android\\\",\\\"style\\\",\\\"default\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"gles\\\",\\\"glesdft\\\",\\\"glessrgb\\\",\\\"glesmsaa4\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--skip\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"glessrgb\\\",\\\"image\\\",\\\"_\\\",\\\"_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"test\\\",\\\"_\\\",\\\"GrStyledShape\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android_API30\",\"dm_flags\":\"[\\\"dm\\\",\\\"--nameByHash\\\",\\\"--key\\\",\\\"arch\\\",\\\"arm64\\\",\\\"compiler\\\",\\\"Clang\\\",\\\"configuration\\\",\\\"Release\\\",\\\"cpu_or_gpu\\\",\\\"GPU\\\",\\\"cpu_or_gpu_value\\\",\\\"Adreno640\\\",\\\"extra_config\\\",\\\"Android_API30\\\",\\\"model\\\",\\\"Pixel4\\\",\\\"os\\\",\\\"Android\\\",\\\"style\\\",\\\"default\\\",\\\"--nocpu\\\",\\\"--config\\\",\\\"gles\\\",\\\"glesdft\\\",\\\"glessrgb\\\",\\\"glesmsaa4\\\",\\\"--src\\\",\\\"tests\\\",\\\"gm\\\",\\\"image\\\",\\\"colorImage\\\",\\\"svg\\\",\\\"--skip\\\",\\\"_\\\",\\\"svg\\\",\\\"_\\\",\\\"svgparse_\\\",\\\"glessrgb\\\",\\\"image\\\",\\\"_\\\",\\\"_\\\",\\\"_\\\",\\\"image\\\",\\\"gen_platf\\\",\\\"error\\\",\\\"_\\\",\\\"test\\\",\\\"_\\\",\\\"GrStyledShape\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced1.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced2.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\"interlaced3.png\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".arw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".cr2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".dng\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".nrw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".orf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".raf\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".rw2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".pef\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".srw\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ARW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".CR2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".DNG\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".NRW\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".ORF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RAF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".RW2\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".PEF\\\",\\\"_\\\",\\\"image\\\",\\\"_\\\",\\\".SRW\\\",\\\"--nonativeFonts\\\",\\\"--verbose\\\"]\",\"dm_properties\":\"{\\\"buildbucket_build_id\\\":\\\"<(BUILDBUCKET_BUILD_ID)\\\",\\\"builder\\\":\\\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android_API30\\\",\\\"gitHash\\\":\\\"<(REVISION)\\\",\\\"issue\\\":\\\"<(ISSUE)\\\",\\\"patch_storage\\\":\\\"<(PATCH_STORAGE)\\\",\\\"patchset\\\":\\\"<(PATCHSET)\\\",\\\"swarming_bot_id\\\":\\\"${SWARMING_BOT_ID}\\\",\\\"swarming_task_id\\\":\\\"${SWARMING_TASK_ID}\\\",\\\"task_id\\\":\\\"<(TASK_ID)\\\"}\",\"do_upload\":\"true\",\"gold_hashes_url\":\"https://storage.googleapis.com/skia-infra-gm/hash_files/gold-prod-hashes.txt\",\"images\":\"true\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"resources\":\"true\",\"revision\":\"<(REVISION)\",\"skps\":\"true\",\"svgs\":\"true\",\"swarm_out_dir\":\"test\",\"task_id\":\"<(TASK_ID)\"}",
"skia"
],
"dependencies": [
"Build-Debian10-Clang-arm64-Release-Android",
"Build-Debian10-Clang-arm64-Release-Android_API30",
"Housekeeper-PerCommit-BundleRecipes",
"Housekeeper-PerCommit-IsolateSKP",
"Housekeeper-PerCommit-IsolateSVG",
@ -68689,7 +68839,7 @@
"max_attempts": 2,
"service_account": "skia-external-gm-uploader@skia-swarming-bots.iam.gserviceaccount.com"
},
"Upload-Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android": {
"Upload-Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_API30": {
"caches": [
{
"name": "vpython",
@ -68724,12 +68874,12 @@
"skia/infra/bots/run_recipe.py",
"${ISOLATED_OUTDIR}",
"upload_dm_results",
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android\",\"gs_bucket\":\"skia-infra-gm\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"output_ignored\",\"task_id\":\"<(TASK_ID)\"}",
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_API30\",\"gs_bucket\":\"skia-infra-gm\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"output_ignored\",\"task_id\":\"<(TASK_ID)\"}",
"skia"
],
"dependencies": [
"Housekeeper-PerCommit-BundleRecipes",
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android"
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Debug-All-Android_API30"
],
"dimensions": [
"cpu:x86-64-Haswell_GCE",
@ -68823,7 +68973,7 @@
"max_attempts": 2,
"service_account": "skia-external-gm-uploader@skia-swarming-bots.iam.gserviceaccount.com"
},
"Upload-Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android": {
"Upload-Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android_API30": {
"caches": [
{
"name": "vpython",
@ -68858,12 +69008,12 @@
"skia/infra/bots/run_recipe.py",
"${ISOLATED_OUTDIR}",
"upload_dm_results",
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android\",\"gs_bucket\":\"skia-infra-gm\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"output_ignored\",\"task_id\":\"<(TASK_ID)\"}",
"{\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"buildbucket_build_id\":\"<(BUILDBUCKET_BUILD_ID)\",\"buildername\":\"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android_API30\",\"gs_bucket\":\"skia-infra-gm\",\"patch_issue\":\"<(ISSUE_INT)\",\"patch_ref\":\"<(PATCH_REF)\",\"patch_repo\":\"<(PATCH_REPO)\",\"patch_set\":\"<(PATCHSET_INT)\",\"patch_storage\":\"<(PATCH_STORAGE)\",\"repository\":\"<(REPO)\",\"revision\":\"<(REVISION)\",\"swarm_out_dir\":\"output_ignored\",\"task_id\":\"<(TASK_ID)\"}",
"skia"
],
"dependencies": [
"Housekeeper-PerCommit-BundleRecipes",
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android"
"Test-Android-Clang-Pixel4-GPU-Adreno640-arm64-Release-All-Android_API30"
],
"dimensions": [
"cpu:x86-64-Haswell_GCE",

View File

@ -289,6 +289,7 @@ PORTS_SRCS_UNIX = struct(
"src/ports/*mozalloc*",
"src/ports/*nacl*",
"src/ports/*win*",
"src/ports/*NDK*",
"src/ports/SkFontMgr_custom_directory_factory.cpp",
"src/ports/SkFontMgr_custom_embedded_factory.cpp",
"src/ports/SkFontMgr_custom_empty_factory.cpp",
@ -324,6 +325,7 @@ PORTS_SRCS_ANDROID = struct(
"src/ports/*mozalloc*",
"src/ports/*nacl*",
"src/ports/*win*",
"src/ports/*NDK*", # TODO (scroggo): enable NDK decoding/encoding in Google3
"src/ports/SkDebug_stdio.cpp",
"src/ports/SkFontMgr_custom_directory_factory.cpp",
"src/ports/SkFontMgr_custom_embedded_factory.cpp",
@ -360,6 +362,7 @@ PORTS_SRCS_IOS = struct(
"src/ports/*mozalloc*",
"src/ports/*nacl*",
"src/ports/*win*",
"src/ports/*NDK*",
"src/ports/SkFontMgr_custom.cpp",
"src/ports/SkFontMgr_custom_directory.cpp",
"src/ports/SkFontMgr_custom_embedded.cpp",
@ -403,6 +406,7 @@ PORTS_SRCS_WASM = struct(
"src/ports/*mozalloc*",
"src/ports/*nacl*",
"src/ports/*win*",
"src/ports/*NDK*",
#"src/ports/SkDebug_stdio.cpp",
"src/ports/SkFontMgr_custom.cpp",
"src/ports/SkFontMgr_custom_directory.cpp",
@ -441,6 +445,7 @@ PORTS_SRCS_FUCHSIA = struct(
"src/ports/*mozalloc*",
"src/ports/*nacl*",
"src/ports/*win*",
"src/ports/*NDK*",
#"src/ports/SkDebug_stdio.cpp",
#"src/ports/SkFontMgr_custom.cpp",
"src/ports/SkFontMgr_custom_directory.cpp",

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,307 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkImageGenerator.h"
#include "include/core/SkImageInfo.h"
#include "include/ports/SkImageGeneratorNDK.h"
#include <android/bitmap.h>
#include <android/data_space.h>
#include <android/imagedecoder.h>
namespace {
class ImageGeneratorNDK : public SkImageGenerator {
public:
ImageGeneratorNDK(const SkImageInfo&, sk_sp<SkData>, AImageDecoder*);
~ImageGeneratorNDK() override;
protected:
sk_sp<SkData> onRefEncodedData() override;
bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
const Options& opts) override;
private:
sk_sp<SkData> fData;
AImageDecoder* fDecoder;
// Setting the ADataSpace is sticky - it is set for all future decodes
// until it is set again. But as of R there is no way to reset it to
// ADATASPACE_UNKNOWN to skip color correction. If the client requests
// skipping correction after having set it to something else, we need
// to recreate the AImageDecoder.
bool fPreviouslySetADataSpace;
typedef SkImageGenerator INHERITED;
};
} // anonymous namespace
static bool ok(int result) {
return result == ANDROID_IMAGE_DECODER_SUCCESS;
}
namespace {
static const struct {
SkColorType colorType;
AndroidBitmapFormat format;
} gColorTypeTable[] = {
{ kRGBA_8888_SkColorType, ANDROID_BITMAP_FORMAT_RGBA_8888 },
{ kRGBA_F16_SkColorType, ANDROID_BITMAP_FORMAT_RGBA_F16 },
{ kRGB_565_SkColorType, ANDROID_BITMAP_FORMAT_RGB_565 },
// Android allows using its alpha 8 format to get 8 bit gray pixels.
{ kGray_8_SkColorType, ANDROID_BITMAP_FORMAT_A_8 },
};
} // anonymous namespace
static bool set_android_bitmap_format(AImageDecoder* decoder, SkColorType colorType) {
for (const auto& entry : gColorTypeTable) {
if (entry.colorType == colorType) {
return ok(AImageDecoder_setAndroidBitmapFormat(decoder, entry.format));
}
}
return false;
}
static SkColorType colorType(AImageDecoder* decoder, const AImageDecoderHeaderInfo* headerInfo) {
// AImageDecoder never defaults to gray, but allows setting it if the image is 8 bit gray.
if (set_android_bitmap_format(decoder, kGray_8_SkColorType)) {
return kGray_8_SkColorType;
}
const auto format = AImageDecoderHeaderInfo_getAndroidBitmapFormat(headerInfo);
for (const auto& entry : gColorTypeTable) {
if (format == entry.format) {
return entry.colorType;
}
}
SkUNREACHABLE;
}
static constexpr skcms_TransferFunction k2Dot6 = {2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
static constexpr skcms_Matrix3x3 kDCIP3 = {{
{0.486143, 0.323835, 0.154234},
{0.226676, 0.710327, 0.0629966},
{0.000800549, 0.0432385, 0.78275},
}};
namespace {
static const struct {
ADataSpace dataSpace;
skcms_TransferFunction transferFunction;
skcms_Matrix3x3 gamut;
} gColorSpaceTable[] = {
// Note: ADATASPACE_SCRGB would look the same as ADATASPACE_SRGB. Leaving it out of the table is
// fine, since users of the table will will still use SRGB.
{ ADATASPACE_SRGB, SkNamedTransferFn::kSRGB, SkNamedGamut::kSRGB },
{ ADATASPACE_SCRGB_LINEAR, SkNamedTransferFn::kLinear, SkNamedGamut::kSRGB },
{ ADATASPACE_SRGB_LINEAR, SkNamedTransferFn::kLinear, SkNamedGamut::kSRGB },
{ ADATASPACE_ADOBE_RGB, SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB },
{ ADATASPACE_DISPLAY_P3, SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3 },
{ ADATASPACE_BT2020, SkNamedTransferFn::kRec2020, SkNamedGamut::kRec2020 },
{ ADATASPACE_BT709, SkNamedTransferFn::kRec2020, SkNamedGamut::kSRGB },
{ ADATASPACE_DCI_P3, k2Dot6, kDCIP3 },
};
} // anonymous namespace
static sk_sp<SkColorSpace> get_default_colorSpace(const AImageDecoderHeaderInfo* headerInfo) {
auto dataSpace = AImageDecoderHeaderInfo_getDataSpace(headerInfo);
for (const auto& entry : gColorSpaceTable) {
if (entry.dataSpace == dataSpace) {
return SkColorSpace::MakeRGB(entry.transferFunction, entry.gamut);
}
}
return SkColorSpace::MakeSRGB();
}
std::unique_ptr<SkImageGenerator> SkImageGeneratorNDK::MakeFromEncodedNDK(sk_sp<SkData> data) {
if (!data) return nullptr;
AImageDecoder* rawDecoder;
if (!ok(AImageDecoder_createFromBuffer(data->data(), data->size(), &rawDecoder))) {
return nullptr;
}
const AImageDecoderHeaderInfo* headerInfo = AImageDecoder_getHeaderInfo(rawDecoder);
int32_t width = AImageDecoderHeaderInfo_getWidth(headerInfo);
int32_t height = AImageDecoderHeaderInfo_getHeight(headerInfo);
SkColorType ct = colorType(rawDecoder, headerInfo);
// Although the encoded data stores unpremultiplied pixels, AImageDecoder defaults to premul
// (if the image may have alpha).
SkAlphaType at = AImageDecoderHeaderInfo_getAlphaFlags(headerInfo)
== ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
auto imageInfo = SkImageInfo::Make(width, height, ct, at, get_default_colorSpace(headerInfo));
return std::unique_ptr<SkImageGenerator>(
new ImageGeneratorNDK(imageInfo, std::move(data), rawDecoder));
}
ImageGeneratorNDK::ImageGeneratorNDK(const SkImageInfo& info, sk_sp<SkData> data,
AImageDecoder* decoder)
: INHERITED(info)
, fData(std::move(data))
, fDecoder(decoder)
, fPreviouslySetADataSpace(false)
{
SkASSERT(fDecoder);
}
ImageGeneratorNDK::~ImageGeneratorNDK() {
AImageDecoder_delete(fDecoder);
}
static bool nearly_equal(float a, float b) {
return fabs(a - b) < .002f;
}
static bool nearly_equal(const skcms_TransferFunction& x, const skcms_TransferFunction& y) {
return nearly_equal(x.g, y.g)
&& nearly_equal(x.a, y.a)
&& nearly_equal(x.b, y.b)
&& nearly_equal(x.c, y.c)
&& nearly_equal(x.d, y.d)
&& nearly_equal(x.e, y.e)
&& nearly_equal(x.f, y.f);
}
static bool nearly_equal(const skcms_Matrix3x3& a, const skcms_Matrix3x3& b) {
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++) {
if (!nearly_equal(a.vals[i][j], b.vals[i][j])) return false;
}
return true;
}
static bool set_target_size(AImageDecoder* decoder, const SkISize& size, const SkISize targetSize) {
if (size != targetSize) {
// AImageDecoder will scale to arbitrary sizes. Only support a size if it's supported by the
// underlying library.
const AImageDecoderHeaderInfo* headerInfo = AImageDecoder_getHeaderInfo(decoder);
const char* mimeType = AImageDecoderHeaderInfo_getMimeType(headerInfo);
if (0 == strcmp(mimeType, "image/jpeg")) {
bool supported = false;
for (int sampleSize : { 2, 4, 8 }) {
int32_t width;
int32_t height;
if (ok(AImageDecoder_computeSampledSize(decoder, sampleSize, &width, &height))
&& targetSize == SkISize::Make(width, height)) {
supported = true;
break;
}
}
if (!supported) return false;
} else if (0 == strcmp(mimeType, "image/webp")) {
// libwebp supports arbitrary downscaling.
if (targetSize.width() > size.width() || targetSize.height() > size.height()) {
return false;
}
} else {
return false;
}
}
return ok(AImageDecoder_setTargetSize(decoder, targetSize.width(), targetSize.height()));
}
bool ImageGeneratorNDK::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
const Options& opts) {
if (auto* cs = info.colorSpace()) {
skcms_TransferFunction fn;
skcms_Matrix3x3 gamut;
if (!cs->isNumericalTransferFn(&fn) || !cs->toXYZD50(&gamut)) {
return false;
}
ADataSpace dataSpace = ADATASPACE_UNKNOWN;
for (const auto& entry : gColorSpaceTable) {
if (nearly_equal(gamut, entry.gamut) && nearly_equal(fn, entry.transferFunction)) {
dataSpace = entry.dataSpace;
}
}
if (!ok(AImageDecoder_setDataSpace(fDecoder, dataSpace))) {
return false;
}
fPreviouslySetADataSpace = true;
} else {
// If the requested SkColorSpace is null, the client wants the "raw" colors, without color
// space transformations applied. (This is primarily useful for a client that wants to do
// their own color transformations.) This is AImageDecoder's default, but if a previous call
// set an ADataSpace, AImageDecoder is no longer using its default, so we need to set it
// back.
if (fPreviouslySetADataSpace) {
// AImageDecoderHeaderInfo_getDataSpace always returns the same value for the same
// image, regardless of prior calls to AImageDecoder_setDataSpace. Check if it's
// ADATASPACE_UNKNOWN, which needs to be handled specially.
const AImageDecoderHeaderInfo* headerInfo = AImageDecoder_getHeaderInfo(fDecoder);
const auto defaultDataSpace = AImageDecoderHeaderInfo_getDataSpace(headerInfo);
if (defaultDataSpace == ADATASPACE_UNKNOWN) {
// As of R, there's no way to reset AImageDecoder to ADATASPACE_UNKNOWN, so
// create a new one.
AImageDecoder* decoder;
if (!ok(AImageDecoder_createFromBuffer(fData->data(), fData->size(), &decoder))) {
return false;
}
AImageDecoder_delete(fDecoder);
fDecoder = decoder;
} else {
if (!ok(AImageDecoder_setDataSpace(fDecoder, defaultDataSpace))) {
return false;
}
}
// Whether by recreating AImageDecoder or calling AImageDecoder_setDataSpace, the
// AImageDecoder is back to its default, so if the next call has a null SkColorSpace, it
// does not need to reset it again.
fPreviouslySetADataSpace = false;
}
}
if (!set_android_bitmap_format(fDecoder, info.colorType())) {
return false;
}
switch (info.alphaType()) {
case kUnknown_SkAlphaType:
return false;
case kOpaque_SkAlphaType:
if (this->getInfo().alphaType() != kOpaque_SkAlphaType) {
return false;
}
break;
case kUnpremul_SkAlphaType:
if (!ok(AImageDecoder_setUnpremultipliedRequired(fDecoder, true))) {
return false;
}
break;
case kPremul_SkAlphaType:
break;
}
if (!set_target_size(fDecoder, getInfo().dimensions(), info.dimensions())) {
return false;
}
auto byteSize = info.computeByteSize(rowBytes);
switch (AImageDecoder_decodeImage(fDecoder, pixels, rowBytes, byteSize)) {
case ANDROID_IMAGE_DECODER_INCOMPLETE:
// The image was partially decoded, but the input was truncated. The client may be
// happy with the partial image.
case ANDROID_IMAGE_DECODER_ERROR:
// Similarly, the image was partially decoded, but the input had an error. The client
// may be happy with the partial image.
case ANDROID_IMAGE_DECODER_SUCCESS:
return true;
default:
return false;
}
}
sk_sp<SkData> ImageGeneratorNDK::onRefEncodedData() {
return fData;
}

565
tests/NdkDecodeTest.cpp Normal file
View File

@ -0,0 +1,565 @@
/*
* Copyright 2020 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/core/SkTypes.h"
#ifdef SK_ENABLE_NDK_DECODING
#include "include/ports/SkImageGeneratorNDK.h"
#include "tests/Test.h"
#include "tools/Resources.h"
#include <vector>
static std::unique_ptr<SkImageGenerator> make_generator(const char* path, skiatest::Reporter* r) {
auto data = GetResourceAsData(path);
if (data) {
auto gen = SkImageGeneratorNDK::MakeFromEncodedNDK(std::move(data));
if (gen) {
return gen;
}
ERRORF(r, "Failed to create NDK generator from %s\n", path);
} else {
// Silently fail so developers can skip using --resources
}
return nullptr;
}
DEF_TEST(NdkDecode, r) {
static const struct {
const char* fPath;
SkISize fSize;
} recs[] = {
{"images/CMYK.jpg", {642, 516}},
{"images/arrow.png", {187, 312}},
{"images/baby_tux.webp", {386, 395}},
{"images/color_wheel.gif", {128, 128}},
{"images/rle.bmp", {320, 240}},
{"images/color_wheel.ico", {128, 128}},
{"images/google_chrome.ico", {256, 256}},
{"images/mandrill.wbmp", {512, 512}},
};
for (auto& rec : recs) {
auto gen = make_generator(rec.fPath, r);
if (!gen) continue;
const auto& info = gen->getInfo();
REPORTER_ASSERT(r, info.dimensions() == rec.fSize);
SkBitmap bm;
bm.allocPixels(info);
REPORTER_ASSERT(r, gen->getPixels(bm.pixmap()));
REPORTER_ASSERT(r, info.alphaType() != kUnpremul_SkAlphaType);
auto unpremulInfo = info.makeAlphaType(kUnpremul_SkAlphaType);
bm.allocPixels(unpremulInfo);
REPORTER_ASSERT(r, gen->getPixels(bm.pixmap()));
}
}
DEF_TEST(NdkDecode_nullData, r) {
auto gen = SkImageGeneratorNDK::MakeFromEncodedNDK(nullptr);
REPORTER_ASSERT(r, !gen);
}
static constexpr skcms_TransferFunction k2Dot6 = {2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
static constexpr skcms_Matrix3x3 kDCIP3 = {{
{0.486143, 0.323835, 0.154234},
{0.226676, 0.710327, 0.0629966},
{0.000800549, 0.0432385, 0.78275},
}};
DEF_TEST(NdkDecode_reportedColorSpace, r) {
for (sk_sp<SkColorSpace> cs : {
sk_sp<SkColorSpace>(nullptr),
SkColorSpace::MakeSRGB(),
SkColorSpace::MakeSRGBLinear(),
SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, SkNamedGamut::kSRGB),
SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, SkNamedGamut::kRec2020),
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3),
SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB),
SkColorSpace::MakeRGB(k2Dot6, kDCIP3),
}) {
SkBitmap bm;
bm.allocPixels(SkImageInfo::Make(10, 10, kRGBA_F16_SkColorType, kOpaque_SkAlphaType, cs));
bm.eraseColor(SK_ColorBLUE);
for (auto format : { SkEncodedImageFormat::kPNG,
SkEncodedImageFormat::kJPEG,
SkEncodedImageFormat::kWEBP }) {
auto data = SkEncodeBitmap(bm, format, 80);
auto gen = SkImageGeneratorNDK::MakeFromEncodedNDK(std::move(data));
if (!gen) {
ERRORF(r, "Failed to encode!");
return;
}
if (!cs) cs = SkColorSpace::MakeSRGB();
REPORTER_ASSERT(r, SkColorSpace::Equals(gen->getInfo().colorSpace(), cs.get()));
}
}
}
DEF_TEST(NdkDecode_ColorSpace, r) {
for (const char* path: {
"images/CMYK.jpg",
"images/arrow.png",
"images/baby_tux.webp",
"images/color_wheel.gif",
"images/rle.bmp",
"images/color_wheel.ico",
"images/google_chrome.ico",
"images/mandrill.wbmp",
}) {
auto gen = make_generator(path, r);
if (!gen) continue;
for (sk_sp<SkColorSpace> cs : {
sk_sp<SkColorSpace>(nullptr),
SkColorSpace::MakeSRGB(),
SkColorSpace::MakeSRGBLinear(),
SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, SkNamedGamut::kSRGB),
SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, SkNamedGamut::kRec2020),
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3),
SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, SkNamedGamut::kAdobeRGB),
SkColorSpace::MakeRGB(k2Dot6, kDCIP3),
}) {
auto info = gen->getInfo().makeColorSpace(cs);
SkBitmap bm;
bm.allocPixels(info);
REPORTER_ASSERT(r, gen->getPixels(bm.pixmap()));
}
std::vector<sk_sp<SkColorSpace>> unsupportedCs;
for (auto gamut : { SkNamedGamut::kSRGB, SkNamedGamut::kAdobeRGB, SkNamedGamut::kDisplayP3,
SkNamedGamut::kRec2020, SkNamedGamut::kXYZ }) {
unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut));
unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut));
unsupportedCs.push_back(SkColorSpace::MakeRGB(k2Dot6, gamut));
}
for (auto gamut : { SkNamedGamut::kSRGB, SkNamedGamut::kDisplayP3,
SkNamedGamut::kRec2020, SkNamedGamut::kXYZ }) {
unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, gamut));
}
for (auto gamut : { SkNamedGamut::kAdobeRGB, SkNamedGamut::kDisplayP3,
SkNamedGamut::kXYZ }) {
unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut));
}
for (auto gamut : { SkNamedGamut::kAdobeRGB, SkNamedGamut::kDisplayP3,
SkNamedGamut::kRec2020, SkNamedGamut::kXYZ }) {
unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut));
}
for (auto gamut : { SkNamedGamut::kAdobeRGB,
SkNamedGamut::kRec2020, SkNamedGamut::kXYZ }) {
unsupportedCs.push_back(SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut));
}
for (auto fn : { SkNamedTransferFn::kSRGB, SkNamedTransferFn::k2Dot2,
SkNamedTransferFn::kLinear, SkNamedTransferFn::kRec2020 }) {
unsupportedCs.push_back(SkColorSpace::MakeRGB(fn, kDCIP3));
}
for (auto unsupported : unsupportedCs) {
auto info = gen->getInfo().makeColorSpace(unsupported);
SkBitmap bm;
bm.allocPixels(info);
REPORTER_ASSERT(r, !gen->getPixels(bm.pixmap()));
}
}
}
DEF_TEST(NdkDecode_reuseNoColorSpace, r) {
static const struct {
const char* fPath;
sk_sp<SkColorSpace> fCorrectedColorSpace;
bool fIsOpaque;
} recs[] = {
// AImageDecoder defaults to ADATASPACE_UNKNOWN for this image.
{"images/wide_gamut_yellow_224_224_64.jpeg", SkColorSpace::MakeSRGB(), true},
// This image is SRGB, so convert to a different color space.
{"images/example_1.png", SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2,
SkNamedGamut::kAdobeRGB), false},
};
for (auto& rec : recs) {
auto gen = make_generator(rec.fPath, r);
if (!gen) continue;
REPORTER_ASSERT(r, gen->getInfo().colorSpace()->isSRGB());
REPORTER_ASSERT(r, gen->getInfo().isOpaque() == rec.fIsOpaque);
auto noColorCorrection = gen->getInfo().makeColorSpace(nullptr);
if (rec.fIsOpaque) {
// Use something other than the default color type to verify that the modified color
// type is used even when the color space is reset.
noColorCorrection = noColorCorrection.makeColorType(kRGB_565_SkColorType);
}
SkBitmap orig;
orig.allocPixels(noColorCorrection);
REPORTER_ASSERT(r, gen->getPixels(orig.pixmap()));
SkBitmap corrected;
corrected.allocPixels(noColorCorrection.makeColorSpace(rec.fCorrectedColorSpace));
REPORTER_ASSERT(r, gen->getPixels(corrected.pixmap()));
bool same = true;
for (int y = 0; y < gen->getInfo().height(); y++) {
auto* origLine = orig.getAddr(0, y);
auto* correctedLine = corrected.getAddr(0, y);
if (memcmp(origLine, correctedLine, orig.rowBytes()) != 0) {
same = false;
break;
}
}
REPORTER_ASSERT(r, !same);
SkBitmap reuse;
reuse.allocPixels(noColorCorrection);
REPORTER_ASSERT(r, gen->getPixels(reuse.pixmap()));
for (int y = 0; y < gen->getInfo().height(); y++) {
auto* origLine = orig.getAddr(0, y);
auto* reuseLine = reuse.getAddr(0, y);
if (memcmp(origLine, reuseLine, orig.rowBytes()) != 0) {
ERRORF(r, "Bitmaps do not match!\n");
break;
}
}
}
}
// The NDK supports scaling up to arbitrary dimensions. Skia forces clients to do this in a
// separate step, so the client is in charge of how to do the upscale.
DEF_TEST(NdkDecode_noUpscale, r) {
for (const char* path: {
"images/CMYK.jpg",
"images/arrow.png",
"images/baby_tux.webp",
"images/color_wheel.gif",
"images/rle.bmp",
"images/color_wheel.ico",
"images/google_chrome.ico",
"images/mandrill.wbmp",
}) {
auto gen = make_generator(path, r);
if (!gen) continue;
const auto actualDimensions = gen->getInfo().dimensions();
const int width = actualDimensions.width();
const int height = actualDimensions.height();
for (SkISize dims : {
SkISize{width*2, height*2},
SkISize{width + 1, height + 1},
}) {
auto info = gen->getInfo().makeDimensions(dims);
SkBitmap bm;
bm.allocPixels(info);
REPORTER_ASSERT(r, !gen->getPixels(bm.pixmap()));
}
}
}
// libwebp supports downscaling to an arbitrary scale factor, and this is supported by the NDK.
DEF_TEST(NdkDecode_webpArbitraryDownscale, r) {
for (const char* path: {
"images/baby_tux.webp",
"images/yellow_rose.webp",
"images/webp-color-profile-lossless.webp",
}) {
auto gen = make_generator(path, r);
if (!gen) continue;
const auto actualDimensions = gen->getInfo().dimensions();
const int width = actualDimensions.width();
const int height = actualDimensions.height();
for (SkISize dims : {
SkISize{width/2, height/2},
SkISize{width/4, height/4},
SkISize{width/7, height/7},
SkISize{width - 1, height - 1},
SkISize{1, 1},
SkISize{5, 20}
}) {
auto info = gen->getInfo().makeDimensions(dims);
SkBitmap bm;
bm.allocPixels(info);
REPORTER_ASSERT(r, gen->getPixels(bm.pixmap()));
REPORTER_ASSERT(r, info.alphaType() != kUnpremul_SkAlphaType);
auto unpremulInfo = info.makeAlphaType(kUnpremul_SkAlphaType);
bm.allocPixels(unpremulInfo);
REPORTER_ASSERT(r, gen->getPixels(bm.pixmap()));
}
}
}
// libjpeg-turbo supports downscaling to some scale factors.
DEF_TEST(NdkDecode_jpegDownscale, r) {
static const struct {
const char* fPath;
SkISize fSupportedSizes[4];
} recs[] = {
{"images/CMYK.jpg", {{642,516},{321,258},{161,129},{81,65}}},
{"images/dog.jpg", {{180,180},{90,90},{45,45},{23,23}}},
{"images/grayscale.jpg", {{128,128},{64,64},{32,32},{16,16}}},
{"images/brickwork-texture.jpg", {{512,512},{256,256},{128,128},{64,64}}},
{"images/mandrill_h2v1.jpg", {{512,512},{256,256},{128,128},{64,64}}},
{"images/ducky.jpg", {{489,537},{245,269},{123,135},{62,68}}},
};
for (auto& rec : recs) {
auto gen = make_generator(rec.fPath, r);
if (!gen) continue;
for (SkISize dims : rec.fSupportedSizes) {
auto info = gen->getInfo().makeDimensions(dims);
SkBitmap bm;
bm.allocPixels(info);
if (!gen->getPixels(bm.pixmap())) {
ERRORF(r, "failed to decode %s to {%i,%i}\n", rec.fPath, dims.width(),
dims.height());
}
REPORTER_ASSERT(r, info.alphaType() != kUnpremul_SkAlphaType);
auto unpremulInfo = info.makeAlphaType(kUnpremul_SkAlphaType);
bm.allocPixels(unpremulInfo);
REPORTER_ASSERT(r, gen->getPixels(bm.pixmap()));
}
}
}
DEF_TEST(NdkDecode_reuseJpeg, r) {
auto gen = make_generator("images/CMYK.jpg", r);
if (!gen) return;
SkImageInfo info = gen->getInfo();
SkBitmap orig;
orig.allocPixels(info);
REPORTER_ASSERT(r, gen->getPixels(orig.pixmap()));
info = info.makeWH(321, 258);
SkBitmap downscaled;
downscaled.allocPixels(info);
REPORTER_ASSERT(r, gen->getPixels(downscaled.pixmap()));
SkBitmap reuse;
reuse.allocPixels(gen->getInfo());
REPORTER_ASSERT(r, gen->getPixels(reuse.pixmap()));
for (int y = 0; y < gen->getInfo().height(); y++) {
auto* origLine = orig.getAddr32(0, y);
auto* reuseLine = reuse.getAddr32(0, y);
if (memcmp(origLine, reuseLine, orig.rowBytes()) != 0) {
ERRORF(r, "Bitmaps do not match!\n");
break;
}
}
}
// The NDK supports scaling down to arbitrary dimensions. Skia forces clients to do this in a
// separate step, so the client is in charge of how to do the downscale.
DEF_TEST(NdkDecode_noDownscale, r) {
for (const char* path: {
"images/arrow.png",
"images/color_wheel.gif",
"images/rle.bmp",
"images/color_wheel.ico",
"images/google_chrome.ico",
"images/mandrill.wbmp",
}) {
auto gen = make_generator(path, r);
if (!gen) continue;
const auto actualDimensions = gen->getInfo().dimensions();
const int width = actualDimensions.width();
const int height = actualDimensions.height();
for (SkISize dims : {
SkISize{width/2, height/2},
SkISize{width/3, height/3},
SkISize{width/4, height/4},
SkISize{width/8, height/8},
SkISize{width - 1, height - 1},
}) {
auto info = gen->getInfo().makeDimensions(dims);
SkBitmap bm;
bm.allocPixels(info);
REPORTER_ASSERT(r, !gen->getPixels(bm.pixmap()));
}
}
}
DEF_TEST(NdkDecode_Gray8, r) {
static const struct {
const char* fPath;
bool fGrayscale;
} recs[] = {
{"images/CMYK.jpg", false},
{"images/arrow.png", false},
{"images/baby_tux.webp", false},
{"images/color_wheel.gif", false},
{"images/rle.bmp", false},
{"images/color_wheel.ico", false},
{"images/google_chrome.ico", false},
{"images/mandrill.wbmp", true},
{"images/grayscale.jpg", true},
{"images/grayscale.png", true},
};
for (auto& rec : recs) {
auto gen = make_generator(rec.fPath, r);
if (!gen) continue;
SkImageInfo info = gen->getInfo();
if (rec.fGrayscale) {
REPORTER_ASSERT(r, info.colorType() == kGray_8_SkColorType);
REPORTER_ASSERT(r, info.alphaType() == kOpaque_SkAlphaType);
} else {
info = info.makeColorType(kGray_8_SkColorType);
}
SkBitmap bm;
bm.allocPixels(info);
bool success = gen->getPixels(bm.pixmap());
if (success != rec.fGrayscale) {
ERRORF(r, "Expected decoding %s to Gray8 to %s. Actual: %s\n", rec.fPath,
(rec.fGrayscale ? "succeed" : "fail"), (success ? "succeed" : "fail"));
}
}
}
DEF_TEST(NdkDecode_Opaque_and_565, r) {
for (const char* path: {
"images/CMYK.jpg",
"images/dog.jpg",
"images/ducky.jpg",
"images/arrow.png",
"images/example_1.png",
"images/explosion_sprites.png",
"images/lut_identity.png",
"images/grayscale.png",
"images/baby_tux.webp",
"images/yellow_rose.webp",
"images/webp-color-profile-lossless.webp",
"images/colorTables.gif",
"images/color_wheel.gif",
"images/flightAnim.gif",
"images/randPixels.gif",
"images/rle.bmp",
"images/color_wheel.ico",
"images/google_chrome.ico",
"images/mandrill.wbmp",
}) {
auto gen = make_generator(path, r);
if (!gen) continue;
auto info = gen->getInfo().makeAlphaType(kOpaque_SkAlphaType);
SkBitmap bm;
bm.allocPixels(info);
bool success = gen->getPixels(bm.pixmap());
REPORTER_ASSERT(r, success == gen->getInfo().isOpaque());
info = info.makeColorType(kRGB_565_SkColorType);
bm.allocPixels(info);
success = gen->getPixels(bm.pixmap());
REPORTER_ASSERT(r, success == gen->getInfo().isOpaque());
}
}
DEF_TEST(NdkDecode_AlwaysSupportedColorTypes, r) {
for (const char* path: {
"images/CMYK.jpg",
"images/dog.jpg",
"images/ducky.jpg",
"images/arrow.png",
"images/example_1.png",
"images/explosion_sprites.png",
"images/lut_identity.png",
"images/grayscale.png",
"images/baby_tux.webp",
"images/yellow_rose.webp",
"images/webp-color-profile-lossless.webp",
"images/colorTables.gif",
"images/color_wheel.gif",
"images/flightAnim.gif",
"images/randPixels.gif",
"images/rle.bmp",
"images/color_wheel.ico",
"images/google_chrome.ico",
"images/mandrill.wbmp",
}) {
auto gen = make_generator(path, r);
if (!gen) continue;
auto info = gen->getInfo().makeColorType(kRGBA_F16_SkColorType);
SkBitmap bm;
bm.allocPixels(info);
REPORTER_ASSERT(r, gen->getPixels(bm.pixmap()));
// This also tests that we can reuse the same generator for a different
// color type.
info = info.makeColorType(kRGBA_8888_SkColorType);
bm.allocPixels(info);
REPORTER_ASSERT(r, gen->getPixels(bm.pixmap()));
}
}
DEF_TEST(NdkDecode_UnsupportedColorTypes, r) {
for (const char* path: {
"images/CMYK.jpg",
"images/dog.jpg",
"images/ducky.jpg",
"images/arrow.png",
"images/example_1.png",
"images/explosion_sprites.png",
"images/lut_identity.png",
"images/grayscale.png",
"images/baby_tux.webp",
"images/yellow_rose.webp",
"images/webp-color-profile-lossless.webp",
"images/colorTables.gif",
"images/color_wheel.gif",
"images/flightAnim.gif",
"images/randPixels.gif",
"images/rle.bmp",
"images/color_wheel.ico",
"images/google_chrome.ico",
"images/mandrill.wbmp",
}) {
auto gen = make_generator(path, r);
if (!gen) continue;
for (SkColorType ct : {
kUnknown_SkColorType,
kAlpha_8_SkColorType,
kARGB_4444_SkColorType,
kRGB_888x_SkColorType,
kBGRA_8888_SkColorType,
kRGBA_1010102_SkColorType,
kBGRA_1010102_SkColorType,
kRGB_101010x_SkColorType,
kBGR_101010x_SkColorType,
kRGBA_F16Norm_SkColorType,
kRGBA_F32_SkColorType,
kR8G8_unorm_SkColorType,
kA16_float_SkColorType,
kR16G16_float_SkColorType,
kA16_unorm_SkColorType,
kR16G16_unorm_SkColorType,
kR16G16B16A16_unorm_SkColorType,
}) {
auto info = gen->getInfo().makeColorType(ct);
SkBitmap bm;
bm.allocPixels(info);
if (gen->getPixels(bm.pixmap())) {
ERRORF(r, "Expected decoding %s to %i to fail!", path, ct);
}
}
}
}
#endif // SK_ENABLE_NDK_DECODING