From 916de9ff18cf3caa29c0821b55244060b6f84f9d Mon Sep 17 00:00:00 2001 From: yujieqin Date: Mon, 25 Jan 2016 08:26:16 -0800 Subject: Add RAW decoding into Skia. TBR=reed@google.com BUG=skia: (Based on the work from ebrauer in https://codereview.chromium.org/1459473007) (Based on the work from adaubert in https://codereview.chromium.org/1494003003) GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1520403003 Committed: https://skia.googlesource.com/skia/+/6bd8639f8c142eedf543f4e5f3b02d2bf11df308 Review URL: https://codereview.chromium.org/1520403003 --- DEPS | 3 + dm/DM.cpp | 24 +- gyp/android_deps.gyp | 24 ++ gyp/codec.gyp | 57 +++++ gyp/common_variables.gypi | 5 + gyp/dng_sdk.gyp | 282 ++++++++++++++++++++++++ gyp/piex.gyp | 103 +++++++++ include/codec/SkEncodedFormat.h | 1 + resources/sample_1mp.dng | Bin 0 -> 87116 bytes src/codec/SkAndroidCodec.cpp | 7 + src/codec/SkCodec.cpp | 8 + src/codec/SkRawAdapterCodec.cpp | 30 +++ src/codec/SkRawAdapterCodec.h | 42 ++++ src/codec/SkRawCodec.cpp | 475 ++++++++++++++++++++++++++++++++++++++++ src/codec/SkRawCodec.h | 60 +++++ tests/CodexTest.cpp | 5 + 16 files changed, 1124 insertions(+), 2 deletions(-) create mode 100644 gyp/dng_sdk.gyp create mode 100644 gyp/piex.gyp create mode 100644 resources/sample_1mp.dng create mode 100644 src/codec/SkRawAdapterCodec.cpp create mode 100644 src/codec/SkRawAdapterCodec.h create mode 100644 src/codec/SkRawCodec.cpp create mode 100644 src/codec/SkRawCodec.h diff --git a/DEPS b/DEPS index d0f366c309..bbdcc06995 100644 --- a/DEPS +++ b/DEPS @@ -21,6 +21,9 @@ deps = { "third_party/externals/libpng" : "https://skia.googlesource.com/third_party/libpng.git@070a616b8275277e18ef8ee91e2ca23f7bdc67d5", "third_party/externals/giflib" : "https://android.googlesource.com/platform/external/giflib.git@ab10e256df4f684260ca239905b1cec727181f6c", + "third_party/externals/dng_sdk" : "https://android.googlesource.com/platform/external/dng_sdk.git@671e9caebb6a6d5580ae9bd7676c09501715b6f8", + "third_party/externals/piex" : "https://android.googlesource.com/platform/external/piex.git@afc6ebdcba72e4eeeaafab1547c19025fcec5d1f", + "third_party/externals/libjpeg-turbo" : "https://skia.googlesource.com/third_party/libjpeg-turbo.git@36422d9e165a33914436068536772cc6ed1e7886", # libjpeg-turbo depends on yasm to compile .asm files "third_party/externals/yasm/source/patched-yasm/" : "https://chromium.googlesource.com/chromium/deps/yasm/patched-yasm.git@4671120cd8558ce62ee8672ebf3eb6f5216f909b", diff --git a/dm/DM.cpp b/dm/DM.cpp index 5124442a20..12ce23c6a1 100644 --- a/dm/DM.cpp +++ b/dm/DM.cpp @@ -520,6 +520,20 @@ static bool brd_supported(const char* ext) { return false; } +static bool is_raw(const SkString& file) { + static const char* const exts[] = { + "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw", + "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW", + }; + + for (uint32_t i = 0; i < SK_ARRAY_COUNT(exts); i++) { + if (file.endsWith(exts[i])) { + return true; + } + } + return false; +} + static void gather_srcs() { for (const skiagm::GMRegistry* r = skiagm::GMRegistry::Head(); r; r = r->next()) { push_src("gm", "", new GMSrc(r->factory())); @@ -538,6 +552,8 @@ static void gather_srcs() { static const char* const exts[] = { "bmp", "gif", "jpg", "jpeg", "png", "webp", "ktx", "astc", "wbmp", "ico", "BMP", "GIF", "JPG", "JPEG", "PNG", "WEBP", "KTX", "ASTC", "WBMP", "ICO", + "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw", + "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW", }; for (int i = 0; i < FLAGS_images.count(); i++) { const char* flag = FLAGS_images[i]; @@ -546,7 +562,9 @@ static void gather_srcs() { SkOSFile::Iter it(flag, exts[j]); for (SkString file; it.next(&file); ) { SkString path = SkOSPath::Join(flag, file.c_str()); - push_src("image", "decode", new ImageSrc(path)); // Decode entire image + if (!is_raw(file)) { + push_src("image", "decode", new ImageSrc(path)); // Decode entire image + } push_codec_srcs(path); if (brd_supported(exts[j])) { push_brd_srcs(path); @@ -555,7 +573,9 @@ static void gather_srcs() { } } else if (sk_exists(flag)) { // assume that FLAGS_images[i] is a valid image if it is a file. - push_src("image", "decode", new ImageSrc(flag)); // Decode entire image. + if (!is_raw(SkString(flag))) { + push_src("image", "decode", new ImageSrc(flag)); // Decode entire image. + } push_codec_srcs(flag); push_brd_srcs(flag); } diff --git a/gyp/android_deps.gyp b/gyp/android_deps.gyp index c439e1987a..1a0c758818 100644 --- a/gyp/android_deps.gyp +++ b/gyp/android_deps.gyp @@ -63,6 +63,30 @@ ], }, }, + { + 'target_name': 'dng_sdk', + 'type': 'none', + 'direct_dependent_settings': { + 'libraries' : [ + '-ldng_sdk', + ], + 'include_dirs': [ + 'external/dng_sdk', + ], + }, + }, + { + 'target_name': 'piex', + 'type': 'none', + 'direct_dependent_settings': { + 'libraries' : [ + '-lpiex', + ], + 'include_dirs': [ + 'external/piex', + ], + }, + }, { 'target_name': 'cpu_features', 'type': 'none', diff --git a/gyp/codec.gyp b/gyp/codec.gyp index 8a35b09d6c..d7272e2a7a 100644 --- a/gyp/codec.gyp +++ b/gyp/codec.gyp @@ -66,6 +66,63 @@ 'defines': [ 'TURBO_HAS_SKIP', ], + 'conditions': [ + # FIXME: fix the support for Windows. (Issue with _hypot in DNG SDK). + ['skia_codec_decodes_raw and skia_os != "win" and skia_os != "chromeos"', { + 'dependencies': [ + 'raw_codec', + ], + },], + ], + }, { + # RAW codec needs exceptions. Due to that, it is a separate target. Its usage can be + # controlled by SK_CODEC_DECODES_RAW flag. + 'target_name': 'raw_codec', + 'product_name': 'raw_codec', + 'type': 'static_library', + 'dependencies': [ + 'core.gyp:*', + 'dng_sdk.gyp:dng_sdk-selector', + 'libjpeg-turbo-selector.gyp:libjpeg-turbo-selector', + 'piex.gyp:piex-selector', + ], + 'cflags':[ + '-fexceptions', + ], + 'include_dirs': [ + '../include/codec', + '../include/private', + '../src/codec', + '../src/core', + ], + 'sources': [ + '../src/codec/SkRawAdapterCodec.cpp', + '../src/codec/SkRawCodec.cpp', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../include/codec', + ], + 'defines': [ + 'SK_CODEC_DECODES_RAW', + ], + }, + 'defines': [ + 'SK_CODEC_DECODES_RAW', + ], + 'conditions': [ + ['skia_arch_type == "x86" or skia_arch_type == "arm"', { + 'defines': [ + 'qDNGBigEndian=0', + ], + }], + ['skia_os == "ios" or skia_os == "mac"', { + 'xcode_settings': { + 'OTHER_CFLAGS': ['-fexceptions'], + 'OTHER_CPLUSPLUSFLAGS': ['-fexceptions'], + }, + }], + ], }, ], } diff --git a/gyp/common_variables.gypi b/gyp/common_variables.gypi index 4cab95899b..abbe729da1 100644 --- a/gyp/common_variables.gypi +++ b/gyp/common_variables.gypi @@ -37,6 +37,11 @@ # 'variables': { # level 1 'angle_path%': '../', + + # RAW codec needs exceptions. Due to that, it is a separate target. Its usage can be controlled + # by this variable. + 'skia_codec_decodes_raw%': 1, + 'variables': { # level 2 # Variables needed by conditions list within the level-2 variables dict. diff --git a/gyp/dng_sdk.gyp b/gyp/dng_sdk.gyp new file mode 100644 index 0000000000..1daebe1439 --- /dev/null +++ b/gyp/dng_sdk.gyp @@ -0,0 +1,282 @@ +# Copyright 2016 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# The Adobe DNG SDK, an API for reading and writing DNG files. +{ +'targets': [{ + 'target_name': 'dng_sdk-selector', + 'type': 'none', + 'conditions': [ + [ 'skia_android_framework', { + 'dependencies': [ 'android_deps.gyp:dng_sdk' ], + 'export_dependent_settings': [ 'android_deps.gyp:dng_sdk' ], + }, { + 'dependencies': [ 'dng_sdk' ], + 'export_dependent_settings': [ 'dng_sdk' ], + }] + ] +},{ + 'target_name': 'dng_sdk', + 'type': 'static_library', + 'cflags_cc': [ '-fexceptions' ], + 'cflags': [ + '-fexceptions', + '-w', + # FIXME: only disable ::posix_memalign() when needed. + '-DNO_POSIX_MEMALIGN' + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'WarningLevel': '0', + }, + }, + 'xcode_settings': { + 'WARNING_CFLAGS': ['-w'], + }, + 'dependencies': [ + 'dng_dont_report_errors_flags', + 'dng_flags', + 'dng_frame_larger_than_flags', + 'dng_srcs', + 'linux_flags', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../third_party/externals/dng_sdk/source', + ], + }, +}, { + 'target_name': 'dng_srcs', + 'type': 'none', + 'variables': { + 'headers': [ + '../third_party/externals/dng_sdk/source/RawEnvironment.h', + '../third_party/externals/dng_sdk/source/dng_1d_function.h', + '../third_party/externals/dng_sdk/source/dng_1d_table.h', + '../third_party/externals/dng_sdk/source/dng_abort_sniffer.h', + '../third_party/externals/dng_sdk/source/dng_area_task.h', + '../third_party/externals/dng_sdk/source/dng_assertions.h', + '../third_party/externals/dng_sdk/source/dng_auto_ptr.h', + '../third_party/externals/dng_sdk/source/dng_bad_pixels.h', + '../third_party/externals/dng_sdk/source/dng_bottlenecks.h', + '../third_party/externals/dng_sdk/source/dng_camera_profile.h', + '../third_party/externals/dng_sdk/source/dng_classes.h', + '../third_party/externals/dng_sdk/source/dng_color_space.h', + '../third_party/externals/dng_sdk/source/dng_color_spec.h', + '../third_party/externals/dng_sdk/source/dng_date_time.h', + '../third_party/externals/dng_sdk/source/dng_errors.h', + '../third_party/externals/dng_sdk/source/dng_exceptions.h', + '../third_party/externals/dng_sdk/source/dng_exif.h', + '../third_party/externals/dng_sdk/source/dng_fast_module.h', + '../third_party/externals/dng_sdk/source/dng_file_stream.h', + '../third_party/externals/dng_sdk/source/dng_filter_task.h', + '../third_party/externals/dng_sdk/source/dng_fingerprint.h', + '../third_party/externals/dng_sdk/source/dng_flags.h', + '../third_party/externals/dng_sdk/source/dng_gain_map.h', + '../third_party/externals/dng_sdk/source/dng_globals.h', + '../third_party/externals/dng_sdk/source/dng_host.h', + '../third_party/externals/dng_sdk/source/dng_hue_sat_map.h', + '../third_party/externals/dng_sdk/source/dng_ifd.h', + '../third_party/externals/dng_sdk/source/dng_image.h', + '../third_party/externals/dng_sdk/source/dng_image_writer.h', + '../third_party/externals/dng_sdk/source/dng_info.h', + '../third_party/externals/dng_sdk/source/dng_iptc.h', + '../third_party/externals/dng_sdk/source/dng_jpeg_image.h', + '../third_party/externals/dng_sdk/source/dng_lens_correction.h', + '../third_party/externals/dng_sdk/source/dng_linearization_info.h', + '../third_party/externals/dng_sdk/source/dng_lossless_jpeg.h', + '../third_party/externals/dng_sdk/source/dng_matrix.h', + '../third_party/externals/dng_sdk/source/dng_memory.h', + '../third_party/externals/dng_sdk/source/dng_memory_stream.h', + '../third_party/externals/dng_sdk/source/dng_misc_opcodes.h', + '../third_party/externals/dng_sdk/source/dng_mosaic_info.h', + '../third_party/externals/dng_sdk/source/dng_mutex.h', + '../third_party/externals/dng_sdk/source/dng_negative.h', + '../third_party/externals/dng_sdk/source/dng_opcode_list.h', + '../third_party/externals/dng_sdk/source/dng_opcodes.h', + '../third_party/externals/dng_sdk/source/dng_orientation.h', + '../third_party/externals/dng_sdk/source/dng_parse_utils.h', + '../third_party/externals/dng_sdk/source/dng_pixel_buffer.h', + '../third_party/externals/dng_sdk/source/dng_point.h', + '../third_party/externals/dng_sdk/source/dng_preview.h', + '../third_party/externals/dng_sdk/source/dng_pthread.h', + '../third_party/externals/dng_sdk/source/dng_rational.h', + '../third_party/externals/dng_sdk/source/dng_read_image.h', + '../third_party/externals/dng_sdk/source/dng_rect.h', + '../third_party/externals/dng_sdk/source/dng_ref_counted_block.h', + '../third_party/externals/dng_sdk/source/dng_reference.h', + '../third_party/externals/dng_sdk/source/dng_render.h', + '../third_party/externals/dng_sdk/source/dng_resample.h', + '../third_party/externals/dng_sdk/source/dng_sdk_limits.h', + '../third_party/externals/dng_sdk/source/dng_shared.h', + '../third_party/externals/dng_sdk/source/dng_simple_image.h', + '../third_party/externals/dng_sdk/source/dng_spline.h', + '../third_party/externals/dng_sdk/source/dng_stream.h', + '../third_party/externals/dng_sdk/source/dng_string.h', + '../third_party/externals/dng_sdk/source/dng_string_list.h', + '../third_party/externals/dng_sdk/source/dng_tag_codes.h', + '../third_party/externals/dng_sdk/source/dng_tag_types.h', + '../third_party/externals/dng_sdk/source/dng_tag_values.h', + '../third_party/externals/dng_sdk/source/dng_temperature.h', + '../third_party/externals/dng_sdk/source/dng_tile_iterator.h', + '../third_party/externals/dng_sdk/source/dng_tone_curve.h', + '../third_party/externals/dng_sdk/source/dng_types.h', + '../third_party/externals/dng_sdk/source/dng_uncopyable.h', + '../third_party/externals/dng_sdk/source/dng_utils.h', + '../third_party/externals/dng_sdk/source/dng_xy_coord.h', + '../third_party/externals/dng_sdk/source/dng_jpeg_memory_source.h', + '../third_party/externals/dng_sdk/source/dng_jpeglib.h', + '../third_party/externals/dng_sdk/source/dng_safe_arithmetic.h', + ], + }, + 'dependencies': [ + 'libjpeg-turbo.gyp:libjpeg-turbo', + 'zlib.gyp:zlib', + ], + 'export_dependent_settings': [ + 'libjpeg-turbo.gyp:libjpeg-turbo', + 'zlib.gyp:zlib', + ], + 'direct_dependent_settings': { + 'sources': [ + '../third_party/externals/dng_sdk/source/dng_1d_function.cpp', + '../third_party/externals/dng_sdk/source/dng_1d_table.cpp', + '../third_party/externals/dng_sdk/source/dng_abort_sniffer.cpp', + '../third_party/externals/dng_sdk/source/dng_area_task.cpp', + '../third_party/externals/dng_sdk/source/dng_bad_pixels.cpp', + '../third_party/externals/dng_sdk/source/dng_bottlenecks.cpp', + '../third_party/externals/dng_sdk/source/dng_camera_profile.cpp', + '../third_party/externals/dng_sdk/source/dng_color_space.cpp', + '../third_party/externals/dng_sdk/source/dng_color_spec.cpp', + '../third_party/externals/dng_sdk/source/dng_date_time.cpp', + '../third_party/externals/dng_sdk/source/dng_exceptions.cpp', + '../third_party/externals/dng_sdk/source/dng_exif.cpp', + '../third_party/externals/dng_sdk/source/dng_file_stream.cpp', + '../third_party/externals/dng_sdk/source/dng_filter_task.cpp', + '../third_party/externals/dng_sdk/source/dng_fingerprint.cpp', + '../third_party/externals/dng_sdk/source/dng_gain_map.cpp', + '../third_party/externals/dng_sdk/source/dng_globals.cpp', + '../third_party/externals/dng_sdk/source/dng_host.cpp', + '../third_party/externals/dng_sdk/source/dng_hue_sat_map.cpp', + '../third_party/externals/dng_sdk/source/dng_ifd.cpp', + '../third_party/externals/dng_sdk/source/dng_image.cpp', + '../third_party/externals/dng_sdk/source/dng_image_writer.cpp', + '../third_party/externals/dng_sdk/source/dng_info.cpp', + '../third_party/externals/dng_sdk/source/dng_iptc.cpp', + '../third_party/externals/dng_sdk/source/dng_jpeg_image.cpp', + '../third_party/externals/dng_sdk/source/dng_lens_correction.cpp', + '../third_party/externals/dng_sdk/source/dng_linearization_info.cpp', + '../third_party/externals/dng_sdk/source/dng_lossless_jpeg.cpp', + '../third_party/externals/dng_sdk/source/dng_matrix.cpp', + '../third_party/externals/dng_sdk/source/dng_memory.cpp', + '../third_party/externals/dng_sdk/source/dng_memory_stream.cpp', + '../third_party/externals/dng_sdk/source/dng_misc_opcodes.cpp', + '../third_party/externals/dng_sdk/source/dng_mosaic_info.cpp', + '../third_party/externals/dng_sdk/source/dng_mutex.cpp', + '../third_party/externals/dng_sdk/source/dng_negative.cpp', + '../third_party/externals/dng_sdk/source/dng_opcode_list.cpp', + '../third_party/externals/dng_sdk/source/dng_opcodes.cpp', + '../third_party/externals/dng_sdk/source/dng_orientation.cpp', + '../third_party/externals/dng_sdk/source/dng_parse_utils.cpp', + '../third_party/externals/dng_sdk/source/dng_pixel_buffer.cpp', + '../third_party/externals/dng_sdk/source/dng_point.cpp', + '../third_party/externals/dng_sdk/source/dng_preview.cpp', + '../third_party/externals/dng_sdk/source/dng_pthread.cpp', + '../third_party/externals/dng_sdk/source/dng_rational.cpp', + '../third_party/externals/dng_sdk/source/dng_read_image.cpp', + '../third_party/externals/dng_sdk/source/dng_rect.cpp', + '../third_party/externals/dng_sdk/source/dng_ref_counted_block.cpp', + '../third_party/externals/dng_sdk/source/dng_reference.cpp', + '../third_party/externals/dng_sdk/source/dng_render.cpp', + '../third_party/externals/dng_sdk/source/dng_resample.cpp', + '../third_party/externals/dng_sdk/source/dng_shared.cpp', + '../third_party/externals/dng_sdk/source/dng_simple_image.cpp', + '../third_party/externals/dng_sdk/source/dng_spline.cpp', + '../third_party/externals/dng_sdk/source/dng_stream.cpp', + '../third_party/externals/dng_sdk/source/dng_string.cpp', + '../third_party/externals/dng_sdk/source/dng_string_list.cpp', + '../third_party/externals/dng_sdk/source/dng_tag_types.cpp', + '../third_party/externals/dng_sdk/source/dng_temperature.cpp', + '../third_party/externals/dng_sdk/source/dng_tile_iterator.cpp', + '../third_party/externals/dng_sdk/source/dng_tone_curve.cpp', + '../third_party/externals/dng_sdk/source/dng_utils.cpp', + '../third_party/externals/dng_sdk/source/dng_xy_coord.cpp', + '../third_party/externals/dng_sdk/source/dng_jpeg_memory_source.cpp', + '../third_party/externals/dng_sdk/source/dng_safe_arithmetic.cpp', + ], + 'include_dirs': [ + '../third_party/externals/dng_sdk/source', + '../third_party/externals/libjpeg-turbo', + ], + 'conditions': [ + ['skia_os != "linux"', { + 'sources': ['<@(headers)'], + }], + ], + }, +}, { + 'target_name': 'dng_flags', + 'type': 'none', + 'direct_dependent_settings': { + 'cflags_cc!': [ '-fno-rtti' ], + 'cflags': [ + '-DqDNGThreadSafe=1', + '-DqDNGUseLibJPEG=1', + '-DqDNGValidateTarget=1', + '-DqDNGUseXMP=0', + '-DqDNGBigEndian=0', + '-w', + '-fexceptions', + '-frtti', + ], + 'conditions': [ + ['skia_os == "ios" or skia_os == "mac"', { + 'xcode_settings': { + 'OTHER_CFLAGS': [ + '-DqDNGThreadSafe=1', + '-DqDNGUseLibJPEG=1', + '-DqDNGValidateTarget=1', + '-DqDNGUseXMP=0', + '-DqDNGBigEndian=0', + '-w', + '-fexceptions', + '-frtti', + ], + 'OTHER_CPLUSPLUSFLAGS': [ + '-DqDNGThreadSafe=1', + '-DqDNGUseLibJPEG=1', + '-DqDNGValidateTarget=1', + '-DqDNGUseXMP=0', + '-DqDNGBigEndian=0', + '-w', + '-fexceptions', + '-frtti', + ], + }, + }], + ], + }, +}, { + 'target_name': 'linux_flags', + 'type': 'none', + 'direct_dependent_settings': { + 'cflags': ['-DUNIX_ENV=1'], + }, +}, { + 'target_name': 'dng_dont_report_errors_flags', + 'type': 'none', + 'direct_dependent_settings': { + 'cflags': [ + '-DqDNGReportErrors=0', + '-DqDNGValidate=0', + ], + }, +}, { + 'target_name': 'dng_frame_larger_than_flags', + 'type': 'none', + 'direct_dependent_settings': { + 'cflags': ['-Wframe-larger-than=20000'], + }, +}], +} diff --git a/gyp/piex.gyp b/gyp/piex.gyp new file mode 100644 index 0000000000..c59dc6974c --- /dev/null +++ b/gyp/piex.gyp @@ -0,0 +1,103 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +{ +'targets': [{ + 'target_name': 'piex-selector', + 'type': 'none', + 'conditions': [ + [ 'skia_android_framework', { + 'dependencies': [ 'android_deps.gyp:piex' ], + 'export_dependent_settings': [ 'android_deps.gyp:piex' ], + }, { + 'dependencies': [ 'piex' ], + 'export_dependent_settings': [ 'piex' ], + }] + ] +},{ + 'target_name': 'piex', + 'type': 'static_library', + 'sources': [ + '../third_party/externals/piex/src/piex.cc', + '../third_party/externals/piex/src/tiff_parser.cc', + ], + 'variables': { + 'headers': [ + '../third_party/externals/piex/src/piex.h', + '../third_party/externals/piex/src/piex_types.h', + '../third_party/externals/piex/src/tiff_parser.h', + ], + }, + 'include_dirs': ['../third_party/externals/piex'], + 'cflags': [ + '-Wsign-compare', + '-w', + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'WarningLevel': '0', + }, + }, + 'xcode_settings': { + 'WARNING_CFLAGS': ['-w'], + }, + 'dependencies': [ + 'binary_parse', + 'image_type_recognition', + 'tiff_directory', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../third_party/externals/piex', + ], + }, +}, { + 'target_name': 'binary_parse', + 'type': 'static_library', + 'sources': [ + '../third_party/externals/piex/src/binary_parse/cached_paged_byte_array.cc', + '../third_party/externals/piex/src/binary_parse/range_checked_byte_ptr.cc', + ], + 'variables': { + 'headers': [ + '../third_party/externals/piex/src/binary_parse/cached_paged_byte_array.h', + '../third_party/externals/piex/src/binary_parse/range_checked_byte_ptr.h', + ], + }, + 'include_dirs': ['../third_party/externals/piex'], + 'cflags': ['-Wsign-compare'], +}, { + 'target_name': 'image_type_recognition', + 'type': 'static_library', + 'sources': [ + '../third_party/externals/piex/src/image_type_recognition/image_type_recognition_lite.cc', + ], + 'variables': { + 'headers': ['../third_party/externals/piex/src/image_type_recognition/image_type_recognition_lite.h'], + }, + 'include_dirs': ['../third_party/externals/piex'], + 'cflags': ['-Wsign-compare'], + 'dependencies': ['binary_parse'], +}, { + 'target_name': 'tiff_directory', + 'type': 'static_library', + 'sources': [ + '../third_party/externals/piex/src/tiff_directory/tiff_directory.cc', + ], + 'variables': { + 'headers': ['../third_party/externals/piex/src/tiff_directory/tiff_directory.h'], + }, + 'include_dirs': ['../third_party/externals/piex'], + 'dependencies': ['binary_parse'], +}], +} diff --git a/include/codec/SkEncodedFormat.h b/include/codec/SkEncodedFormat.h index 003159a8de..275dde608e 100644 --- a/include/codec/SkEncodedFormat.h +++ b/include/codec/SkEncodedFormat.h @@ -23,5 +23,6 @@ enum SkEncodedFormat { kPKM_SkEncodedFormat, kKTX_SkEncodedFormat, kASTC_SkEncodedFormat, + kRAW_SkEncodedFormat, }; #endif // SkEncodedFormat_DEFINED diff --git a/resources/sample_1mp.dng b/resources/sample_1mp.dng new file mode 100644 index 0000000000..c1c10787c7 Binary files /dev/null and b/resources/sample_1mp.dng differ diff --git a/src/codec/SkAndroidCodec.cpp b/src/codec/SkAndroidCodec.cpp index d309d58501..6c3113ccfc 100644 --- a/src/codec/SkAndroidCodec.cpp +++ b/src/codec/SkAndroidCodec.cpp @@ -8,6 +8,9 @@ #include "SkAndroidCodec.h" #include "SkCodec.h" #include "SkCodecPriv.h" +#ifdef SK_CODEC_DECODES_RAW +#include "SkRawAdapterCodec.h" +#endif #include "SkSampledCodec.h" #include "SkWebpAdapterCodec.h" @@ -37,6 +40,10 @@ SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader case kGIF_SkEncodedFormat: case kICO_SkEncodedFormat: return new SkSampledCodec(codec.detach()); +#ifdef SK_CODEC_DECODES_RAW + case kRAW_SkEncodedFormat: + return new SkRawAdapterCodec((SkRawCodec*)codec.detach()); +#endif default: return nullptr; } diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp index 75e5c34f53..cfeeb51d0d 100644 --- a/src/codec/SkCodec.cpp +++ b/src/codec/SkCodec.cpp @@ -15,6 +15,9 @@ #include "SkJpegCodec.h" #endif #include "SkPngCodec.h" +#ifdef SK_CODEC_DECODES_RAW +#include "SkRawCodec.h" +#endif #include "SkStream.h" #include "SkWbmpCodec.h" #include "SkWebpCodec.h" @@ -86,6 +89,11 @@ SkCodec* SkCodec::NewFromStream(SkStream* stream, return proc.NewFromStream(streamDeleter.detach()); } } + +#ifdef SK_CODEC_DECODES_RAW + // Try to treat the input as RAW if all the other checks failed. + return SkRawCodec::NewFromStream(streamDeleter.detach()); +#endif } return nullptr; diff --git a/src/codec/SkRawAdapterCodec.cpp b/src/codec/SkRawAdapterCodec.cpp new file mode 100644 index 0000000000..76cbaa1a23 --- /dev/null +++ b/src/codec/SkRawAdapterCodec.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCodec.h" +#include "SkCodecPriv.h" +#include "SkRawAdapterCodec.h" + +SkRawAdapterCodec::SkRawAdapterCodec(SkRawCodec* codec) + : INHERITED(codec) +{} + +SkISize SkRawAdapterCodec::onGetSampledDimensions(int sampleSize) const { + float scale = 1.f / static_cast(sampleSize); + return this->codec()->getScaledDimensions(scale); +} + +SkCodec::Result SkRawAdapterCodec::onGetAndroidPixels( + const SkImageInfo& info, void* pixels, size_t rowBytes, + const AndroidOptions& options) { + SkCodec::Options codecOptions; + codecOptions.fZeroInitialized = options.fZeroInitialized; + codecOptions.fSubset = options.fSubset; + return this->codec()->getPixels( + info, pixels, rowBytes, &codecOptions, options.fColorPtr, + options.fColorCount); +} diff --git a/src/codec/SkRawAdapterCodec.h b/src/codec/SkRawAdapterCodec.h new file mode 100644 index 0000000000..b552f2aaea --- /dev/null +++ b/src/codec/SkRawAdapterCodec.h @@ -0,0 +1,42 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRawAdapterCodec_DEFINED +#define SkRawAdapterCodec_DEFINED + +#include "SkAndroidCodec.h" +#include "SkCodec.h" +#include "SkEncodedFormat.h" +#include "SkRawCodec.h" +#include "SkStream.h" +#include "SkTypes.h" + +/** + * This class implements the functionality of SkAndroidCodec. It uses an + * SkRawCodec. + */ +class SkRawAdapterCodec : public SkAndroidCodec { +public: + + explicit SkRawAdapterCodec(SkRawCodec*); + + virtual ~SkRawAdapterCodec() {} + +protected: + + SkISize onGetSampledDimensions(int sampleSize) const override; + + bool onGetSupportedSubset(SkIRect* /*desiredSubset*/) const override { return false; } + + SkCodec::Result onGetAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, + const AndroidOptions& options) override; + +private: + + typedef SkAndroidCodec INHERITED; +}; +#endif // SkRawAdapterCodec_DEFINED diff --git a/src/codec/SkRawCodec.cpp b/src/codec/SkRawCodec.cpp new file mode 100644 index 0000000000..05f18ac635 --- /dev/null +++ b/src/codec/SkRawCodec.cpp @@ -0,0 +1,475 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "SkCodec.h" +#include "SkCodecPriv.h" +#include "SkColorPriv.h" +#include "SkData.h" +#if !defined(GOOGLE3) +#include "SkJpegCodec.h" +#endif +#include "SkRawCodec.h" +#include "SkRefCnt.h" +#include "SkStream.h" +#include "SkStreamPriv.h" +#include "SkSwizzler.h" +#include "SkTemplates.h" +#include "SkTypes.h" + +#include "dng_color_space.h" +#include "dng_exceptions.h" +#include "dng_host.h" +#include "dng_info.h" +#include "dng_memory.h" +#include "dng_render.h" +#include "dng_stream.h" + +#include "src/piex.h" + +#include // for std::round,floor,ceil +#include + +namespace { + +// T must be unsigned type. +template +bool safe_add_to_size_t(T arg1, T arg2, size_t* result) { + SkASSERT(arg1 >= 0); + SkASSERT(arg2 >= 0); + if (arg1 >= 0 && arg2 <= std::numeric_limits::max() - arg1) { + T sum = arg1 + arg2; + if (sum <= std::numeric_limits::max()) { + *result = static_cast(sum); + return true; + } + } + return false; +} + +class SkDngMemoryAllocator : public dng_memory_allocator { +public: + ~SkDngMemoryAllocator() override {} + + dng_memory_block* Allocate(uint32 size) override { + // To avoid arbitary allocation requests which might lead to out-of-memory, limit the + // amount of memory that can be allocated at once. The memory limit is based on experiments + // and supposed to be sufficient for all valid DNG images. + if (size > 300 * 1024 * 1024) { // 300 MB + ThrowMemoryFull(); + } + return dng_memory_allocator::Allocate(size); + } +}; + +} // namespace + +// Note: this class could throw exception if it is used as dng_stream. +class SkRawStream : public ::piex::StreamInterface { +public: + // Note that this call will take the ownership of stream. + explicit SkRawStream(SkStream* stream) + : fStream(stream), fWholeStreamRead(false) {} + + ~SkRawStream() override {} + + /* + * Creates an SkMemoryStream from the offset with size. + * Note: for performance reason, this function is destructive to the SkRawStream. One should + * abandon current object after the function call. + */ + SkMemoryStream* transferBuffer(size_t offset, size_t size) { + SkAutoTUnref data(SkData::NewUninitialized(size)); + if (offset > fStreamBuffer.bytesWritten()) { + // If the offset is not buffered, read from fStream directly and skip the buffering. + const size_t skipLength = offset - fStreamBuffer.bytesWritten(); + if (fStream->skip(skipLength) != skipLength) { + return nullptr; + } + const size_t bytesRead = fStream->read(data->writable_data(), size); + if (bytesRead < size) { + data.reset(SkData::NewSubset(data.get(), 0, bytesRead)); + } + } else { + const size_t alreadyBuffered = SkTMin(fStreamBuffer.bytesWritten() - offset, size); + if (alreadyBuffered > 0 && + !fStreamBuffer.read(data->writable_data(), offset, alreadyBuffered)) { + return nullptr; + } + + const size_t remaining = size - alreadyBuffered; + if (remaining) { + auto* dst = static_cast(data->writable_data()) + alreadyBuffered; + const size_t bytesRead = fStream->read(dst, remaining); + size_t newSize; + if (bytesRead < remaining) { + if (!safe_add_to_size_t(alreadyBuffered, bytesRead, &newSize)) { + return nullptr; + } + data.reset(SkData::NewSubset(data.get(), 0, newSize)); + } + } + } + return new SkMemoryStream(data); + } + + // For PIEX + ::piex::Error GetData(const size_t offset, const size_t length, + uint8* data) override { + if (offset == 0 && length == 0) { + return ::piex::Error::kOk; + } + size_t sum; + if (!safe_add_to_size_t(offset, length, &sum) || !this->bufferMoreData(sum)) { + return ::piex::Error::kFail; + } + if (!fStreamBuffer.read(data, offset, length)) { + return ::piex::Error::kFail; + } + return ::piex::Error::kOk; + } + + // For dng_stream + uint64 getLength() { + if (!this->bufferMoreData(kReadToEnd)) { // read whole stream + ThrowReadFile(); + } + return fStreamBuffer.bytesWritten(); + } + + // For dng_stream + void read(void* data, uint32 count, uint64 offset) { + if (count == 0 && offset == 0) { + return; + } + size_t sum; + if (!safe_add_to_size_t(static_cast(count), offset, &sum) || + !this->bufferMoreData(sum)) { + ThrowReadFile(); + } + + if (!fStreamBuffer.read(data, offset, count)) { + ThrowReadFile(); + } + } + +private: + // Note: if the newSize == kReadToEnd (0), this function will read to the end of stream. + bool bufferMoreData(size_t newSize) { + if (newSize == kReadToEnd) { + if (fWholeStreamRead) { // already read-to-end. + return true; + } + + // TODO: optimize for the special case when the input is SkMemoryStream. + return SkStreamCopy(&fStreamBuffer, fStream.get()); + } + + if (newSize <= fStreamBuffer.bytesWritten()) { // already buffered to newSize + return true; + } + if (fWholeStreamRead) { // newSize is larger than the whole stream. + return false; + } + + const size_t sizeToRead = newSize - fStreamBuffer.bytesWritten(); + SkAutoTMalloc tempBuffer(sizeToRead); + const size_t bytesRead = fStream->read(tempBuffer.get(), sizeToRead); + if (bytesRead != sizeToRead) { + return false; + } + return fStreamBuffer.write(tempBuffer.get(), bytesRead); + } + + SkAutoTDelete fStream; + bool fWholeStreamRead; + + SkDynamicMemoryWStream fStreamBuffer; + + const size_t kReadToEnd = 0; +}; + +class SkDngStream : public dng_stream { +public: + SkDngStream(SkRawStream* rawStream) : fRawStream(rawStream) {} + + uint64 DoGetLength() override { return fRawStream->getLength(); } + + void DoRead(void* data, uint32 count, uint64 offset) override { + fRawStream->read(data, count, offset); + } + +private: + SkRawStream* fRawStream; +}; + +class SkDngImage { +public: + static SkDngImage* NewFromStream(SkRawStream* stream) { + SkAutoTDelete dngImage(new SkDngImage(stream)); + if (!dngImage->readDng()) { + return nullptr; + } + + SkASSERT(dngImage->fNegative); + return dngImage.release(); + } + + /* + * Renders the DNG image to the size. The DNG SDK only allows scaling close to integer factors + * down to 80 pixels on the short edge. The rendered image will be close to the specified size, + * but there is no guarantee that any of the edges will match the requested size. E.g. + * 100% size: 4000 x 3000 + * requested size: 1600 x 1200 + * returned size could be: 2000 x 1500 + */ + dng_image* render(int width, int height) { + if (!fHost || !fInfo || !fNegative || !fDngStream) { + if (!this->readDng()) { + return nullptr; + } + } + + // render() takes ownership of fHost, fInfo, fNegative and fDngStream when available. + SkAutoTDelete host(fHost.release()); + SkAutoTDelete info(fInfo.release()); + SkAutoTDelete negative(fNegative.release()); + SkAutoTDelete dngStream(fDngStream.release()); + + // DNG SDK preserves the aspect ratio, so it only needs to know the longer dimension. + const int preferredSize = SkTMax(width, height); + try { + host->SetPreferredSize(preferredSize); + host->ValidateSizes(); + + negative->ReadStage1Image(*host, *dngStream, *info); + + if (info->fMaskIndex != -1) { + negative->ReadTransparencyMask(*host, *dngStream, *info); + } + + negative->ValidateRawImageDigest(*host); + if (negative->IsDamaged()) { + return nullptr; + } + + const int32 kMosaicPlane = -1; + negative->BuildStage2Image(*host); + negative->BuildStage3Image(*host, kMosaicPlane); + + dng_render render(*host, *negative); + render.SetFinalSpace(dng_space_sRGB::Get()); + render.SetFinalPixelType(ttByte); + + dng_point stage3_size = negative->Stage3Image()->Size(); + render.SetMaximumSize(SkTMax(stage3_size.h, stage3_size.v)); + + return render.Render(); + } catch (...) { + return nullptr; + } + } + + const SkImageInfo& getImageInfo() const { + return fImageInfo; + } + + bool isScalable() const { + return fIsScalable; + } + + bool isXtransImage() const { + return fIsXtransImage; + } + +private: + bool readDng() { + // Due to the limit of DNG SDK, we need to reset host and info. + fHost.reset(new dng_host(&fAllocator)); + fInfo.reset(new dng_info); + fDngStream.reset(new SkDngStream(fStream)); + try { + fHost->ValidateSizes(); + fInfo->Parse(*fHost, *fDngStream); + fInfo->PostParse(*fHost); + if (!fInfo->IsValidDNG()) { + return false; + } + + fNegative.reset(fHost->Make_dng_negative()); + fNegative->Parse(*fHost, *fDngStream, *fInfo); + fNegative->PostParse(*fHost, *fDngStream, *fInfo); + fNegative->SynchronizeMetadata(); + + fImageInfo = SkImageInfo::Make(fNegative->DefaultCropSizeH().As_real64(), + fNegative->DefaultCropSizeV().As_real64(), + kN32_SkColorType, kOpaque_SkAlphaType); + + // The DNG SDK scales only for at demosaicing, so only when a mosaic info + // is available also scale is available. + fIsScalable = fNegative->GetMosaicInfo() != nullptr; + fIsXtransImage = fIsScalable + ? (fNegative->GetMosaicInfo()->fCFAPatternSize.v == 6 + && fNegative->GetMosaicInfo()->fCFAPatternSize.h == 6) + : false; + return true; + } catch (...) { + fNegative.reset(nullptr); + return false; + } + } + + SkDngImage(SkRawStream* stream) + : fStream(stream) {} + + SkDngMemoryAllocator fAllocator; + SkAutoTDelete fStream; + SkAutoTDelete fHost; + SkAutoTDelete fInfo; + SkAutoTDelete fNegative; + SkAutoTDelete fDngStream; + + SkImageInfo fImageInfo; + bool fIsScalable; + bool fIsXtransImage; +}; + +/* + * Tries to handle the image with PIEX. If PIEX returns kOk and finds the preview image, create a + * SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases, + * fallback to create SkRawCodec for DNG images. + */ +SkCodec* SkRawCodec::NewFromStream(SkStream* stream) { + SkAutoTDelete rawStream(new SkRawStream(stream)); + ::piex::PreviewImageData imageData; + // FIXME: ::piex::GetPreviewImageData() calls GetData() frequently with small amounts, + // resulting in many calls to bufferMoreData(). Could we make this more efficient by grouping + // smaller requests together? + if (::piex::IsRaw(rawStream.get())) { + ::piex::Error error = ::piex::GetPreviewImageData(rawStream.get(), &imageData); + + if (error == ::piex::Error::kOk && imageData.preview_length > 0) { +#if !defined(GOOGLE3) + // transferBuffer() is destructive to the rawStream. Abandon the rawStream after this + // function call. + // FIXME: one may avoid the copy of memoryStream and use the buffered rawStream. + SkMemoryStream* memoryStream = + rawStream->transferBuffer(imageData.preview_offset, imageData.preview_length); + return memoryStream ? SkJpegCodec::NewFromStream(memoryStream) : nullptr; +#else + return nullptr; +#endif + } else if (error == ::piex::Error::kFail) { + return nullptr; + } + } + + SkAutoTDelete dngImage(SkDngImage::NewFromStream(rawStream.release())); + if (!dngImage) { + return nullptr; + } + + return new SkRawCodec(dngImage.release()); +} + +SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, + size_t dstRowBytes, const Options& options, + SkPMColor ctable[], int* ctableCount, + int* rowsDecoded) { + if (!conversion_possible(requestedInfo, this->getInfo())) { + SkCodecPrintf("Error: cannot convert input type to output type.\n"); + return kInvalidConversion; + } + + SkAutoTDelete swizzler(SkSwizzler::CreateSwizzler( + SkSwizzler::kRGB, nullptr, requestedInfo, options)); + SkASSERT(swizzler); + + const int width = requestedInfo.width(); + const int height = requestedInfo.height(); + SkAutoTDelete image(fDngImage->render(width, height)); + if (!image) { + return kInvalidInput; + } + + // Because the DNG SDK can not guarantee to render to requested size, we allow a small + // difference. Only the overlapping region will be converted. + const float maxDiffRatio = 1.03f; + const dng_point& imageSize = image->Size(); + if (imageSize.h / width > maxDiffRatio || imageSize.h < width || + imageSize.v / height > maxDiffRatio || imageSize.v < height) { + return SkCodec::kInvalidScale; + } + + void* dstRow = dst; + uint8_t srcRow[width * 3]; + + dng_pixel_buffer buffer; + buffer.fData = &srcRow[0]; + buffer.fPlane = 0; + buffer.fPlanes = 3; + buffer.fColStep = buffer.fPlanes; + buffer.fPlaneStep = 1; + buffer.fPixelType = ttByte; + buffer.fPixelSize = sizeof(uint8_t); + buffer.fRowStep = sizeof(srcRow); + + for (int i = 0; i < height; ++i) { + buffer.fArea = dng_rect(i, 0, i + 1, width); + + try { + image->Get(buffer, dng_image::edge_zero); + } catch (...) { + *rowsDecoded = i; + return kIncompleteInput; + } + + swizzler->swizzle(dstRow, &srcRow[0]); + dstRow = SkTAddOffset(dstRow, dstRowBytes); + } + return kSuccess; +} + +SkISize SkRawCodec::onGetScaledDimensions(float desiredScale) const { + SkASSERT(desiredScale <= 1.f); + const SkISize dim = this->getInfo().dimensions(); + if (!fDngImage->isScalable()) { + return dim; + } + + // Limits the minimum size to be 80 on the short edge. + const float shortEdge = SkTMin(dim.fWidth, dim.fHeight); + if (desiredScale < 80.f / shortEdge) { + desiredScale = 80.f / shortEdge; + } + + // For Xtrans images, the integer-factor scaling does not support the half-size scaling case + // (stronger downscalings are fine). In this case, returns the factor "3" scaling instead. + if (fDngImage->isXtransImage() && desiredScale > 1.f / 3.f && desiredScale < 1.f) { + desiredScale = 1.f / 3.f; + } + + // Round to integer-factors. + const float finalScale = std::floor(1.f/ desiredScale); + return SkISize::Make(std::floor(dim.fWidth / finalScale), + std::floor(dim.fHeight / finalScale)); +} + +bool SkRawCodec::onDimensionsSupported(const SkISize& dim) { + const SkISize fullDim = this->getInfo().dimensions(); + const float fullShortEdge = SkTMin(fullDim.fWidth, fullDim.fHeight); + const float shortEdge = SkTMin(dim.fWidth, dim.fHeight); + + SkISize sizeFloor = this->onGetScaledDimensions(1.f / std::floor(fullShortEdge / shortEdge)); + SkISize sizeCeil = this->onGetScaledDimensions(1.f / std::ceil(fullShortEdge / shortEdge)); + return sizeFloor == dim || sizeCeil == dim; +} + +SkRawCodec::~SkRawCodec() {} + +SkRawCodec::SkRawCodec(SkDngImage* dngImage) + : INHERITED(dngImage->getImageInfo(), nullptr) + , fDngImage(dngImage) {} diff --git a/src/codec/SkRawCodec.h b/src/codec/SkRawCodec.h new file mode 100644 index 0000000000..42755c3ef1 --- /dev/null +++ b/src/codec/SkRawCodec.h @@ -0,0 +1,60 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkRawCodec_DEFINED +#define SkRawCodec_DEFINED + +#include "SkCodec.h" +#include "SkImageInfo.h" +#include "SkTypes.h" + +class SkDngImage; +class SkStream; + +/* + * + * This class implements the decoding for RAW images + * + */ +class SkRawCodec : public SkCodec { +public: + + /* + * Creates a RAW decoder + * Takes ownership of the stream + */ + static SkCodec* NewFromStream(SkStream*); + + ~SkRawCodec() override; + +protected: + + Result onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options&, + SkPMColor*, int*, int*) override; + + SkEncodedFormat onGetEncodedFormat() const override { + return kRAW_SkEncodedFormat; + } + + SkISize onGetScaledDimensions(float desiredScale) const override; + + bool onDimensionsSupported(const SkISize&) override; + +private: + + /* + * Creates an instance of the decoder + * Called only by NewFromStream, takes ownership of dngImage. + */ + SkRawCodec(SkDngImage* dngImage); + + SkAutoTDelete fDngImage; + + typedef SkCodec INHERITED; +}; + +#endif diff --git a/tests/CodexTest.cpp b/tests/CodexTest.cpp index 2768d57cfc..5210cf4bf4 100644 --- a/tests/CodexTest.cpp +++ b/tests/CodexTest.cpp @@ -450,6 +450,9 @@ DEF_TEST(Codec, r) { check(r, "plane_interlaced.png", SkISize::Make(250, 126), true, false, false); check(r, "randPixels.png", SkISize::Make(8, 8), true, false, false); check(r, "yellow_rose.png", SkISize::Make(400, 301), true, false, false); + + // RAW + check(r, "sample_1mp.dng", SkISize::Make(600, 338), false, false, false); } // Test interlaced PNG in stripes, similar to DM's kStripe_Mode @@ -643,6 +646,8 @@ DEF_TEST(Codec_Dimensions, r) { test_dimensions(r, "1x16.png"); test_dimensions(r, "mandrill_16.png"); + // RAW + test_dimensions(r, "sample_1mp.dng"); } static void test_invalid(skiatest::Reporter* r, const char path[]) { -- cgit v1.2.3