summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Bremner <bremner@debian.org>2018-03-11 08:58:08 -0500
committerDavid Bremner <bremner@debian.org>2018-03-11 08:58:08 -0500
commit04563554d6390691619da406a745a3e20a10f090 (patch)
tree14e77441680c7e5fdf56f627d9f1786d4587742e
parent6df2d5642ef11254e6483a191fd1aed2b35ad776 (diff)
Importing darktable_2.4.1.orig.tar.xz
-rw-r--r--CMakeLists.txt2
-rw-r--r--src/external/rawspeed/.ci/Brewfile5
-rw-r--r--src/external/rawspeed/.ci/Dockerfile82
-rw-r--r--src/external/rawspeed/.ci/appveyor.yml48
-rwxr-xr-xsrc/external/rawspeed/.ci/ci-script.sh124
-rw-r--r--src/external/rawspeed/.ci/codecov.yml29
-rw-r--r--src/external/rawspeed/.ci/coverity_model.cpp25
-rw-r--r--src/external/rawspeed/.ci/sonar-project.properties29
-rw-r--r--src/external/rawspeed/.ci/wro_deploy.encbin0 -> 3248 bytes
-rwxr-xr-xsrc/external/rawspeed/.ci/www-finish.sh49
-rwxr-xr-xsrc/external/rawspeed/.ci/www-prepare.sh27
-rw-r--r--src/external/rawspeed/.clang-format18
-rw-r--r--src/external/rawspeed/.clang-tidy38
-rw-r--r--src/external/rawspeed/.mailmap19
-rw-r--r--src/external/rawspeed/.travis.yml186
-rw-r--r--src/external/rawspeed/CMakeLists.txt228
-rw-r--r--src/external/rawspeed/LICENSE502
-rw-r--r--src/external/rawspeed/README.rst90
-rw-r--r--src/external/rawspeed/bench/CMakeLists.txt1
-rw-r--r--src/external/rawspeed/bench/librawspeed/CMakeLists.txt28
-rw-r--r--src/external/rawspeed/bench/librawspeed/bench/CMakeLists.txt9
-rw-r--r--src/external/rawspeed/bench/librawspeed/bench/Common.cpp44
-rw-r--r--src/external/rawspeed/bench/librawspeed/bench/Common.h25
-rw-r--r--src/external/rawspeed/bench/librawspeed/decompressors/CMakeLists.txt9
-rw-r--r--src/external/rawspeed/bench/librawspeed/decompressors/DeflateDecompressorBenchmark.cpp145
-rw-r--r--src/external/rawspeed/bench/librawspeed/interpolators/CMakeLists.txt7
-rw-r--r--src/external/rawspeed/bench/librawspeed/interpolators/Cr2sRawInterpolatorBenchmark.cpp78
-rw-r--r--src/external/rawspeed/bench/librawspeed/io/BitStreamBenchmark.cpp145
-rw-r--r--src/external/rawspeed/bench/librawspeed/io/CMakeLists.txt7
-rw-r--r--src/external/rawspeed/cmake/Modules/CheckCXXCompilerFlagAndEnableIt.cmake24
-rw-r--r--src/external/rawspeed/cmake/Modules/CheckJPEGSymbols.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/CheckZLIB.cmake61
-rw-r--r--src/external/rawspeed/cmake/Modules/CpuMarch.cmake37
-rw-r--r--src/external/rawspeed/cmake/Modules/FindCppFilt.cmake18
-rw-r--r--src/external/rawspeed/cmake/Modules/FindDemangler.cmake33
-rw-r--r--src/external/rawspeed/cmake/Modules/FindFind.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/FindGCCAr.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/FindGCCNm.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/FindGCCRanLib.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/FindGCov.cmake16
-rw-r--r--src/external/rawspeed/cmake/Modules/FindGenHtml.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLCov.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLLVMAr.cmake11
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLLVMCXXFilt.cmake17
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLLVMClangTidy.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLLVMCov.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLLVMLLD.cmake23
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLLVMNm.cmake11
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLLVMObjCopy.cmake10
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLLVMObjDump.cmake10
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLLVMOptViewer.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLLVMProfData.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLLVMRanLib.cmake10
-rw-r--r--src/external/rawspeed/cmake/Modules/FindLibFuzzingEngine.cmake28
-rw-r--r--src/external/rawspeed/cmake/Modules/FindPugixml.cmake30
-rw-r--r--src/external/rawspeed/cmake/Modules/FindSphinx.cmake12
-rw-r--r--src/external/rawspeed/cmake/Modules/FindXMLLINT.cmake17
-rw-r--r--src/external/rawspeed/cmake/Modules/GTEST_ADD_TESTS.cmake70
-rw-r--r--src/external/rawspeed/cmake/Modules/GoogleBenchmark.cmake58
-rw-r--r--src/external/rawspeed/cmake/Modules/GoogleBenchmark.cmake.in49
-rw-r--r--src/external/rawspeed/cmake/Modules/GoogleTest.cmake67
-rw-r--r--src/external/rawspeed/cmake/Modules/GoogleTest.cmake.in50
-rw-r--r--src/external/rawspeed/cmake/Modules/LibFindMacros.cmake266
-rw-r--r--src/external/rawspeed/cmake/Modules/Pugixml.cmake60
-rw-r--r--src/external/rawspeed/cmake/Modules/Pugixml.cmake.in47
-rw-r--r--src/external/rawspeed/cmake/Modules/Zlib.cmake64
-rw-r--r--src/external/rawspeed/cmake/Modules/Zlib.cmake.in47
-rw-r--r--src/external/rawspeed/cmake/Modules/memory-align-alloc.cmake33
-rw-r--r--src/external/rawspeed/cmake/Modules/run-xmllint.cmake25
-rw-r--r--src/external/rawspeed/cmake/Modules/thread-local.cmake23
-rw-r--r--src/external/rawspeed/cmake/OpenMP.cmake23
-rw-r--r--src/external/rawspeed/cmake/build-type.cmake40
-rw-r--r--src/external/rawspeed/cmake/clang-tidy.cmake7
-rw-r--r--src/external/rawspeed/cmake/compiler-flags.cmake235
-rw-r--r--src/external/rawspeed/cmake/compiler-versions.cmake33
-rw-r--r--src/external/rawspeed/cmake/compiler-warnings-clang.cmake60
-rw-r--r--src/external/rawspeed/cmake/compiler-warnings-gcc.cmake59
-rw-r--r--src/external/rawspeed/cmake/compiler-warnings.cmake25
-rw-r--r--src/external/rawspeed/cmake/gcc-coverage.cmake33
-rw-r--r--src/external/rawspeed/cmake/gcc-gcov.cmake38
-rw-r--r--src/external/rawspeed/cmake/gcc-toolchain.cmake12
-rw-r--r--src/external/rawspeed/cmake/genhtml.cmake34
-rw-r--r--src/external/rawspeed/cmake/iwyu.cmake40
-rw-r--r--src/external/rawspeed/cmake/iwyu.imp8
-rw-r--r--src/external/rawspeed/cmake/lcov.cmake61
-rw-r--r--src/external/rawspeed/cmake/libc++.cmake13
-rw-r--r--src/external/rawspeed/cmake/llvm-cov.cmake42
-rw-r--r--src/external/rawspeed/cmake/llvm-opt-report.cmake29
-rw-r--r--src/external/rawspeed/cmake/llvm-profdata.cmake25
-rw-r--r--src/external/rawspeed/cmake/llvm-toolchain.cmake19
-rw-r--r--src/external/rawspeed/cmake/sample-based-testing.cmake67
-rw-r--r--src/external/rawspeed/cmake/src-dependencies.cmake148
-rw-r--r--src/external/rawspeed/credits.txt24
-rw-r--r--src/external/rawspeed/data/CMakeLists.txt12
-rw-r--r--src/external/rawspeed/data/README.md131
-rw-r--r--src/external/rawspeed/data/cameras.xml11226
-rw-r--r--src/external/rawspeed/data/cameras.xsd501
-rw-r--r--src/external/rawspeed/data/showcameras.xsl133
-rw-r--r--src/external/rawspeed/docs/CMakeLists.txt78
-rw-r--r--src/external/rawspeed/docs/CameraSupport.rst94
-rw-r--r--src/external/rawspeed/docs/Doxyfile.in2497
-rw-r--r--src/external/rawspeed/docs/Doxygen.rst8
-rw-r--r--src/external/rawspeed/docs/conf.py96
-rw-r--r--src/external/rawspeed/docs/index.rst23
-rw-r--r--src/external/rawspeed/docs/sphinx-pyexec.py53
-rw-r--r--src/external/rawspeed/fuzz/CMakeLists.txt73
-rw-r--r--src/external/rawspeed/fuzz/all-fuzzers.txt51
-rw-r--r--src/external/rawspeed/fuzz/common.dict136
-rw-r--r--src/external/rawspeed/fuzz/corpora/CMakeLists.txt24
-rw-r--r--src/external/rawspeed/fuzz/libFuzzer_dummy_main.cpp73
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/CMakeLists.txt6
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decoders/CMakeLists.txt1
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decoders/TiffDecoders/CMakeLists.txt40
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decoders/TiffDecoders/main.cpp84
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/CMakeLists.txt33
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/Cr2Decompressor.cpp65
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/CrwDecompressor.cpp59
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/DummyLJpegDecompressor.cpp70
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/FujiDecompressor.cpp55
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/HasselbladDecompressor.cpp56
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/HuffmanTable/CMakeLists.txt29
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/HuffmanTable/main.cpp88
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/KodakDecompressor.cpp59
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/LJpegDecompressor.cpp61
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/NikonDecompressor.cpp60
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/OlympusDecompressor.cpp56
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/PanasonicDecompressor.cpp59
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/PentaxDecompressor.cpp66
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV0Decompressor.cpp58
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV1Decompressor.cpp57
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV2Decompressor.cpp57
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/SonyArw1Decompressor.cpp56
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/decompressors/SonyArw2Decompressor.cpp56
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/fuzz/CMakeLists.txt9
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/fuzz/Common.cpp77
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/fuzz/Common.h26
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/fuzz/RawSpeed.cpp27
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/parsers/CMakeLists.txt31
-rw-r--r--src/external/rawspeed/fuzz/librawspeed/parsers/main.cpp99
-rw-r--r--src/external/rawspeed/fuzz/rawspeed/CMakeLists.txt5
-rw-r--r--src/external/rawspeed/fuzz/rawspeed/main.cpp50
-rw-r--r--src/external/rawspeed/src/CMakeLists.txt17
-rw-r--r--src/external/rawspeed/src/config.h.in93
-rw-r--r--src/external/rawspeed/src/external/ThreadSafetyAnalysis.h128
-rw-r--r--src/external/rawspeed/src/librawspeed/CMakeLists.txt10
-rw-r--r--src/external/rawspeed/src/librawspeed/README.md243
-rw-r--r--src/external/rawspeed/src/librawspeed/RawSpeed-API.h43
-rw-r--r--src/external/rawspeed/src/librawspeed/common/CMakeLists.txt28
-rw-r--r--src/external/rawspeed/src/librawspeed/common/Common.cpp62
-rw-r--r--src/external/rawspeed/src/librawspeed/common/Common.h211
-rw-r--r--src/external/rawspeed/src/librawspeed/common/Cpuid.cpp49
-rw-r--r--src/external/rawspeed/src/librawspeed/common/Cpuid.h30
-rw-r--r--src/external/rawspeed/src/librawspeed/common/DngOpcodes.cpp589
-rw-r--r--src/external/rawspeed/src/librawspeed/common/DngOpcodes.h73
-rw-r--r--src/external/rawspeed/src/librawspeed/common/ErrorLog.cpp50
-rw-r--r--src/external/rawspeed/src/librawspeed/common/ErrorLog.h41
-rw-r--r--src/external/rawspeed/src/librawspeed/common/Memory.cpp107
-rw-r--r--src/external/rawspeed/src/librawspeed/common/Memory.h100
-rw-r--r--src/external/rawspeed/src/librawspeed/common/Mutex.h97
-rw-r--r--src/external/rawspeed/src/librawspeed/common/NORangesSet.h37
-rw-r--r--src/external/rawspeed/src/librawspeed/common/Point.h210
-rw-r--r--src/external/rawspeed/src/librawspeed/common/Range.h75
-rw-r--r--src/external/rawspeed/src/librawspeed/common/RawImage.cpp626
-rw-r--r--src/external/rawspeed/src/librawspeed/common/RawImage.h322
-rw-r--r--src/external/rawspeed/src/librawspeed/common/RawImageDataFloat.cpp392
-rw-r--r--src/external/rawspeed/src/librawspeed/common/RawImageDataU16.cpp512
-rw-r--r--src/external/rawspeed/src/librawspeed/common/RawspeedException.h90
-rw-r--r--src/external/rawspeed/src/librawspeed/common/Spline.h177
-rw-r--r--src/external/rawspeed/src/librawspeed/common/TableLookUp.cpp80
-rw-r--r--src/external/rawspeed/src/librawspeed/common/TableLookUp.h40
-rw-r--r--src/external/rawspeed/src/librawspeed/common/Threading.h52
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/AbstractTiffDecoder.cpp51
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/AbstractTiffDecoder.h70
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/ArwDecoder.cpp460
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/ArwDecoder.h61
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/CMakeLists.txt53
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/Cr2Decoder.cpp322
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/Cr2Decoder.h54
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/CrwDecoder.cpp210
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/CrwDecoder.h49
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/DcrDecoder.cpp105
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/DcrDecoder.h51
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/DcsDecoder.cpp77
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/DcsDecoder.h51
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/DngDecoder.cpp767
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/DngDecoder.h62
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/ErfDecoder.cpp77
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/ErfDecoder.h51
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/IiqDecoder.cpp384
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/IiqDecoder.h82
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/KdcDecoder.cpp135
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/KdcDecoder.h50
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/MefDecoder.cpp59
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/MefDecoder.h50
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/MosDecoder.cpp181
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/MosDecoder.h51
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/MrwDecoder.cpp204
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/MrwDecoder.h57
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/NakedDecoder.cpp109
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/NakedDecoder.h59
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/NefDecoder.cpp752
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/NefDecoder.h75
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/OrfDecoder.cpp228
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/OrfDecoder.h55
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/PefDecoder.cpp128
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/PefDecoder.h48
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/RafDecoder.cpp349
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/RafDecoder.h56
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/RawDecoder.cpp312
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/RawDecoder.h166
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/RawDecoderException.h39
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/Rw2Decoder.cpp249
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/Rw2Decoder.h57
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/SimpleTiffDecoder.cpp56
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/SimpleTiffDecoder.h51
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/SrwDecoder.cpp178
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/SrwDecoder.h51
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/ThreefrDecoder.cpp91
-rw-r--r--src/external/rawspeed/src/librawspeed/decoders/ThreefrDecoder.h49
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/AbstractDecompressor.h27
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/AbstractDngDecompressor.cpp169
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/AbstractDngDecompressor.h64
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/AbstractLJpegDecompressor.cpp264
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/AbstractLJpegDecompressor.h202
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/AbstractParallelizedDecompressor.cpp125
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/AbstractParallelizedDecompressor.h87
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/AbstractSamsungDecompressor.h36
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/CMakeLists.txt51
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/Cr2Decompressor.cpp225
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/Cr2Decompressor.h47
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/CrwDecompressor.cpp330
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/CrwDecompressor.h59
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/DeflateDecompressor.cpp260
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/DeflateDecompressor.h59
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/FujiDecompressor.cpp825
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/FujiDecompressor.h213
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/HasselbladDecompressor.cpp106
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/HasselbladDecompressor.h47
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/HuffmanTable.h366
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/JpegDecompressor.cpp168
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/JpegDecompressor.h58
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/KodakDecompressor.cpp139
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/KodakDecompressor.h50
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/LJpegDecompressor.cpp158
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/LJpegDecompressor.h51
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp220
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.h55
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/OlympusDecompressor.cpp220
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/OlympusDecompressor.h39
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/PanasonicDecompressor.cpp167
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/PanasonicDecompressor.h53
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/PentaxDecompressor.cpp176
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/PentaxDecompressor.h52
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/SamsungV0Decompressor.cpp225
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/SamsungV0Decompressor.h52
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/SamsungV1Decompressor.cpp126
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/SamsungV1Decompressor.h48
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/SamsungV2Decompressor.cpp342
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/SamsungV2Decompressor.h55
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/SonyArw1Decompressor.cpp89
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/SonyArw1Decompressor.h39
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/SonyArw2Decompressor.cpp100
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/SonyArw2Decompressor.h39
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/UncompressedDecompressor.cpp380
-rw-r--r--src/external/rawspeed/src/librawspeed/decompressors/UncompressedDecompressor.h134
-rw-r--r--src/external/rawspeed/src/librawspeed/interpolators/CMakeLists.txt8
-rw-r--r--src/external/rawspeed/src/librawspeed/interpolators/Cr2sRawInterpolator.cpp522
-rw-r--r--src/external/rawspeed/src/librawspeed/interpolators/Cr2sRawInterpolator.h57
-rw-r--r--src/external/rawspeed/src/librawspeed/io/BitPumpJPEG.h84
-rw-r--r--src/external/rawspeed/src/librawspeed/io/BitPumpLSB.h51
-rw-r--r--src/external/rawspeed/src/librawspeed/io/BitPumpMSB.h45
-rw-r--r--src/external/rawspeed/src/librawspeed/io/BitPumpMSB16.h47
-rw-r--r--src/external/rawspeed/src/librawspeed/io/BitPumpMSB32.h45
-rw-r--r--src/external/rawspeed/src/librawspeed/io/BitStream.h203
-rw-r--r--src/external/rawspeed/src/librawspeed/io/Buffer.cpp129
-rw-r--r--src/external/rawspeed/src/librawspeed/io/Buffer.h212
-rw-r--r--src/external/rawspeed/src/librawspeed/io/ByteStream.h245
-rw-r--r--src/external/rawspeed/src/librawspeed/io/CMakeLists.txt23
-rw-r--r--src/external/rawspeed/src/librawspeed/io/Endianness.h125
-rw-r--r--src/external/rawspeed/src/librawspeed/io/FileIO.h56
-rw-r--r--src/external/rawspeed/src/librawspeed/io/FileIOException.h39
-rw-r--r--src/external/rawspeed/src/librawspeed/io/FileReader.cpp117
-rw-r--r--src/external/rawspeed/src/librawspeed/io/FileReader.h39
-rw-r--r--src/external/rawspeed/src/librawspeed/io/FileWriter.cpp77
-rw-r--r--src/external/rawspeed/src/librawspeed/io/FileWriter.h42
-rw-r--r--src/external/rawspeed/src/librawspeed/io/IOException.h37
-rw-r--r--src/external/rawspeed/src/librawspeed/metadata/BlackArea.h36
-rw-r--r--src/external/rawspeed/src/librawspeed/metadata/CMakeLists.txt16
-rw-r--r--src/external/rawspeed/src/librawspeed/metadata/Camera.cpp335
-rw-r--r--src/external/rawspeed/src/librawspeed/metadata/Camera.h121
-rw-r--r--src/external/rawspeed/src/librawspeed/metadata/CameraMetaData.cpp161
-rw-r--r--src/external/rawspeed/src/librawspeed/metadata/CameraMetaData.h75
-rw-r--r--src/external/rawspeed/src/librawspeed/metadata/CameraMetadataException.h39
-rw-r--r--src/external/rawspeed/src/librawspeed/metadata/CameraSensorInfo.cpp43
-rw-r--r--src/external/rawspeed/src/librawspeed/metadata/CameraSensorInfo.h40
-rw-r--r--src/external/rawspeed/src/librawspeed/metadata/ColorFilterArray.cpp225
-rw-r--r--src/external/rawspeed/src/librawspeed/metadata/ColorFilterArray.h78
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/CMakeLists.txt18
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/CiffParser.cpp76
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/CiffParser.h48
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/CiffParserException.h41
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/FiffParser.cpp138
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/FiffParser.h46
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/FiffParserException.h39
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/RawParser.cpp94
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/RawParser.h45
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/RawParserException.h38
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/TiffParser.cpp147
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/TiffParser.h60
-rw-r--r--src/external/rawspeed/src/librawspeed/parsers/TiffParserException.h40
-rw-r--r--src/external/rawspeed/src/librawspeed/tiff/CMakeLists.txt16
-rw-r--r--src/external/rawspeed/src/librawspeed/tiff/CiffEntry.cpp167
-rw-r--r--src/external/rawspeed/src/librawspeed/tiff/CiffEntry.h77
-rw-r--r--src/external/rawspeed/src/librawspeed/tiff/CiffIFD.cpp230
-rw-r--r--src/external/rawspeed/src/librawspeed/tiff/CiffIFD.h79
-rw-r--r--src/external/rawspeed/src/librawspeed/tiff/CiffTag.h39
-rw-r--r--src/external/rawspeed/src/librawspeed/tiff/TiffEntry.cpp237
-rw-r--r--src/external/rawspeed/src/librawspeed/tiff/TiffEntry.h118
-rw-r--r--src/external/rawspeed/src/librawspeed/tiff/TiffIFD.cpp310
-rw-r--r--src/external/rawspeed/src/librawspeed/tiff/TiffIFD.h121
-rw-r--r--src/external/rawspeed/src/librawspeed/tiff/TiffTag.h355
-rw-r--r--src/external/rawspeed/src/utilities/CMakeLists.txt9
-rw-r--r--src/external/rawspeed/src/utilities/identify/CMakeLists.txt21
-rw-r--r--src/external/rawspeed/src/utilities/identify/rawspeed-identify.cpp318
-rw-r--r--src/external/rawspeed/src/utilities/rsbench/CMakeLists.txt10
-rw-r--r--src/external/rawspeed/src/utilities/rsbench/main.cpp196
-rw-r--r--src/external/rawspeed/src/utilities/rstest/CMakeLists.txt47
-rw-r--r--src/external/rawspeed/src/utilities/rstest/MD5Benchmark.cpp53
-rw-r--r--src/external/rawspeed/src/utilities/rstest/MD5Test.cpp82
-rw-r--r--src/external/rawspeed/src/utilities/rstest/md5.cpp210
-rw-r--r--src/external/rawspeed/src/utilities/rstest/md5.h56
-rw-r--r--src/external/rawspeed/src/utilities/rstest/rstest.cpp568
-rw-r--r--src/external/rawspeed/test/CMakeLists.txt30
-rw-r--r--src/external/rawspeed/test/librawspeed/CMakeLists.txt36
-rw-r--r--src/external/rawspeed/test/librawspeed/common/CMakeLists.txt14
-rw-r--r--src/external/rawspeed/test/librawspeed/common/CommonTest.cpp449
-rw-r--r--src/external/rawspeed/test/librawspeed/common/CpuidTest.cpp49
-rw-r--r--src/external/rawspeed/test/librawspeed/common/MemoryTest.cpp276
-rw-r--r--src/external/rawspeed/test/librawspeed/common/NORangesSetTest.cpp85
-rw-r--r--src/external/rawspeed/test/librawspeed/common/PointTest.cpp787
-rw-r--r--src/external/rawspeed/test/librawspeed/common/RangeTest.cpp127
-rw-r--r--src/external/rawspeed/test/librawspeed/common/RangeTest.h142
-rw-r--r--src/external/rawspeed/test/librawspeed/common/SplineTest.cpp512
-rw-r--r--src/external/rawspeed/test/librawspeed/common/ThreadingTest.cpp157
-rw-r--r--src/external/rawspeed/test/librawspeed/io/CMakeLists.txt7
-rw-r--r--src/external/rawspeed/test/librawspeed/io/EndiannessTest.cpp372
-rw-r--r--src/external/rawspeed/test/librawspeed/io/EndiannessTest.h500
-rw-r--r--src/external/rawspeed/test/librawspeed/metadata/BlackAreaTest.cpp204
-rw-r--r--src/external/rawspeed/test/librawspeed/metadata/CMakeLists.txt11
-rw-r--r--src/external/rawspeed/test/librawspeed/metadata/CameraMetaDataTest.cpp83
-rw-r--r--src/external/rawspeed/test/librawspeed/metadata/CameraSensorInfoTest.cpp320
-rw-r--r--src/external/rawspeed/test/librawspeed/metadata/CameraTest.cpp157
-rw-r--r--src/external/rawspeed/test/librawspeed/metadata/ColorFilterArrayTest.cpp309
-rw-r--r--src/external/rawspeed/test/librawspeed/test/CMakeLists.txt15
-rw-r--r--src/external/rawspeed/test/librawspeed/test/ExceptionsTest.cpp209
-rw-r--r--src/external/rawspeed/test/librawspeed/test/RawSpeed.cpp36
-rw-r--r--src/version_gen.c10
357 files changed, 51972 insertions, 6 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 52c572199..98f7339a2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -214,7 +214,7 @@ else(DEFINED PROJECT_VERSION)
else(NOT SOURCE_PACKAGE)
if(NOT EXISTS ${CMAKE_SOURCE_DIR}/src/version_gen.c)
# should be expanded by git archive due to export-subst in .gitattributes
- set(PROJECT_VERSION "archive-674e15b31d2670473ea5798678908e34b91ccede")
+ set(PROJECT_VERSION "archive-f69904f996c4ce87e5976fdee96f005e58dfbe2a")
# but was it expanded?
if(PROJECT_VERSION MATCHES Format)
set(PROJECT_VERSION "unknown-version")
diff --git a/src/external/rawspeed/.ci/Brewfile b/src/external/rawspeed/.ci/Brewfile
new file mode 100644
index 000000000..1880a0bae
--- /dev/null
+++ b/src/external/rawspeed/.ci/Brewfile
@@ -0,0 +1,5 @@
+brew 'cmake'
+brew 'git'
+brew 'jpeg'
+brew 'ninja'
+brew 'pugixml'
diff --git a/src/external/rawspeed/.ci/Dockerfile b/src/external/rawspeed/.ci/Dockerfile
new file mode 100644
index 000000000..146ddae72
--- /dev/null
+++ b/src/external/rawspeed/.ci/Dockerfile
@@ -0,0 +1,82 @@
+# docker build -t darktable/rawspeed .
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# !!! hub.docker.com will not auto-rebuild the image !!!
+# !!! after making changes here, or if you just want to manually refresh !!!
+# !!! the image, you need to go to: !!!
+# https://hub.docker.com/r/darktable/rawspeed/~/settings/automated-builds/ !!!
+# !!! and press the "Trigger" button. !!!
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+FROM debian:testing
+MAINTAINER Roman Lebedev <lebedev.ri@gmail.com>
+
+# needed at least for python-based jsonschema :(
+# see https://github.com/Julian/jsonschema/issues/299
+# and https://github.com/docker-library/python/issues/13
+ENV LANG C.UTF-8
+ENV LC_ALL C.UTF-8
+ENV LC_MESSAGES C.UTF-8
+ENV LANGUAGE C.UTF-8
+
+ENV DEBIAN_FRONTEND noninteractive
+
+# Paper over occasional network flakiness of some mirrors.
+RUN echo 'Acquire::Retries "10";' > /etc/apt/apt.conf.d/80retry
+
+# Do not install recommended packages
+RUN echo 'APT::Install-Recommends "false";' > /etc/apt/apt.conf.d/80recommends
+
+# Do not install suggested packages
+RUN echo 'APT::Install-Suggests "false";' > /etc/apt/apt.conf.d/80suggests
+
+# Assume yes
+RUN echo 'APT::Get::Assume-Yes "true";' > /etc/apt/apt.conf.d/80forceyes
+
+# Fix broken packages
+RUN echo 'APT::Get::Fix-Missing "true";' > /etc/apt/apt.conf.d/80fixmissin
+
+ENV GCC_VER=7
+ENV LLVM_VER=5.0
+
+# pls keep sorted :)
+RUN rm -rf /var/lib/apt/lists/* && apt-get update && \
+ apt-get install \
+ clang++-$LLVM_VER clang-tidy-$LLVM_VER clang-tools-$LLVM_VER \
+ cmake curl default-jdk-headless default-jre-headless dirmngr doxygen \
+ g++-$GCC_VER git gnupg googletest graphviz libjpeg-dev libpugixml-dev \
+ libxml2-utils make ninja-build python3-sphinx python3-sphinx-rtd-theme \
+ unzip zlib1g-dev && apt-get clean && rm -rf /var/lib/apt/lists/*
+
+# sonarqube support.
+
+ENV SONAR_SCANNER_CLI_VERSION=3.0.3.778-linux \
+ SONARQUBE_HOME=/opt/sonarqube
+
+RUN set -x \
+
+ # pub 2048R/D26468DE 2015-05-25
+ # Key fingerprint = F118 2E81 C792 9289 21DB CAB4 CFCA 4A29 D264 68DE
+ # uid sonarsource_deployer (Sonarsource Deployer) <infra@sonarsource.com>
+ # sub 2048R/06855C1D 2015-05-25
+ && gpg --keyserver keys.gnupg.net --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE \
+ && cd /opt \
+ && curl -o sonar-scanner-cli.zip -fSL https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_CLI_VERSION.zip \
+ && curl -o sonar-scanner-cli.zip.asc -fSL https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$SONAR_SCANNER_CLI_VERSION.zip.asc \
+ && gpg --batch --verify sonar-scanner-cli.zip.asc sonar-scanner-cli.zip \
+ && unzip sonar-scanner-cli.zip \
+ && mv sonar-scanner-$SONAR_SCANNER_CLI_VERSION $SONARQUBE_HOME \
+ && rm sonar-scanner-cli.zip* \
+ && curl -o build-wrapper.zip -fSL https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip \
+ && unzip build-wrapper.zip \
+ && mv build-wrapper-linux-x86/* $SONARQUBE_HOME/bin \
+ && rm build-wrapper.zip* \
+ && rmdir build-wrapper-linux-x86
+
+ENV PATH=$SONARQUBE_HOME/bin:$PATH
+
+# i'd like to explicitly use ld.gold
+# while it may be just immeasurably faster, it is known to cause more issues
+# than traditional ld.bfd; plus, at this time, ld.gold seems like the future.
+RUN dpkg-divert --add --rename --divert /usr/bin/ld.original /usr/bin/ld && \
+ ln -s /usr/bin/ld.gold /usr/bin/ld
diff --git a/src/external/rawspeed/.ci/appveyor.yml b/src/external/rawspeed/.ci/appveyor.yml
new file mode 100644
index 000000000..b5d81381e
--- /dev/null
+++ b/src/external/rawspeed/.ci/appveyor.yml
@@ -0,0 +1,48 @@
+install:
+ - SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%"
+ - C:\msys64\usr\bin\pacman --noconfirm -Syyuu
+ - C:\msys64\usr\bin\pacman -S --noconfirm mingw-w64-x86_64-{toolchain,gcc,clang,cmake,ninja,libxml2,pugixml,libjpeg-turbo,zlib}
+
+environment:
+ CFLAGS: "-pipe"
+ CXXFLAGS: "-pipe"
+ ECO: "-DALLOW_DOWNLOADING_GOOGLETEST=ON"
+ TARGET: build
+ matrix:
+ - CC: cc
+ CXX: c++
+ - CC: clang
+ CXX: clang++
+ - CC: cc
+ CXX: c++
+ FLAVOR: Coverage
+
+# clang Coverage build fails with some llvm linking issues
+
+matrix:
+ fast_finish: true
+
+build_script:
+ - SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%"
+ - C:\msys64\usr\bin\bash --login -c "
+ export PATH=/c/msys64/mingw64/bin:/c/msys64/usr/bin:$PATH;
+ export SRC_DIR=\"${APPVEYOR_BUILD_FOLDER}\";
+ export BUILD_DIR=\"$SRC_DIR/build\";
+ export INSTALL_PREFIX=\"$SRC_DIR/install\";
+ mkdir \"${BUILD_DIR}\";
+ mkdir \"${INSTALL_PREFIX}\";
+ $(cygpath ${APPVEYOR_BUILD_FOLDER})/.ci/ci-script.sh;"
+
+on_success:
+ - SET "PATH=C:\msys64\mingw64\bin;C:\msys64\usr\bin;%PATH%"
+ - C:\msys64\usr\bin\bash --login -c "
+ if [[ "$FLAVOR" != "Coverage" ]]; then
+ exit;
+ fi;
+ export PATH=/c/msys64/mingw64/bin:/c/msys64/usr/bin:$PATH;
+ export PLATFORM=windows;
+ export CXX=GCC;
+ cd \"${APPVEYOR_BUILD_FOLDER}\";
+ curl -s https://codecov.io/bash > codecov;
+ chmod +x codecov;
+ ./codecov -e PLATFORM,CXX -F unittests -X gcov -s \"build/gcov-reports-unittest\" -Z;"
diff --git a/src/external/rawspeed/.ci/ci-script.sh b/src/external/rawspeed/.ci/ci-script.sh
new file mode 100755
index 000000000..5444261a5
--- /dev/null
+++ b/src/external/rawspeed/.ci/ci-script.sh
@@ -0,0 +1,124 @@
+#!/bin/sh
+
+# it is supposed to be run by travis-ci
+# expects a few env variables to be set:
+# BUILD_DIR - the working directory, where to build
+# INSTALL_DIR - the installation prefix.
+# SRC_DIR - read-only directory with git checkout to compile
+# CC, CXX, CFLAGS, CXXFLAGS are not required, should make sense too
+# TARGET - either build or usermanual
+# ECO - some other flags for cmake
+
+set -ex
+
+CMAKE_BUILD_TYPE="RelWithDebInfo"
+GENERATOR="Ninja"
+VERBOSE="-v"
+KEEPGOING="-k0"
+
+case "$FLAVOR" in
+ "Coverage")
+ CMAKE_BUILD_TYPE="Coverage"
+ G="Unix Makefiles"
+ ;;
+ *)
+ ;;
+esac
+
+case "$TARGET" in
+ "WWW")
+ G="Unix Makefiles"
+ ECO="${ECO} -DBUILD_DOCS=ON"
+ ;;
+ *)
+ ;;
+esac
+
+if [ ! -z "${G+x}" ];
+then
+ GENERATOR="$G"
+fi
+
+if [ "$GENERATOR" = "Unix Makefiles" ];
+then
+ VERBOSE="VERBOSE=1";
+ KEEPGOING="-k"
+fi;
+
+if [ -z "${MAKEFLAGS+x}" ];
+then
+ MAKEFLAGS="-j2 $VERBOSE"
+fi
+
+target_build()
+{
+ # to get as much of the issues into the log as possible
+ cmake --build "$BUILD_DIR" -- $MAKEFLAGS || cmake --build "$BUILD_DIR" -- -j1 $VERBOSE $KEEPGOING
+
+ ctest --output-on-failure || ctest --rerun-failed -V -VV
+
+ # and now check that it installs where told and only there.
+ cmake --build "$BUILD_DIR" --target install -- $MAKEFLAGS || cmake --build "$BUILD_DIR" --target install -- -j1 $VERBOSE $KEEPGOING
+}
+
+target_www()
+{
+ cmake --build "$BUILD_DIR" -- $VERBOSE docs
+}
+
+handle_coverage_data()
+{
+ cmake --build "$BUILD_DIR" --target gcov
+ mkdir "$BUILD_DIR/gcov-reports-unittest"
+ find "$BUILD_DIR" -maxdepth 1 -iname '*.gcov' -exec mv "{}" "$BUILD_DIR/gcov-reports-unittest" \;
+}
+
+handle_sample_coverage_data()
+{
+ cmake --build "$BUILD_DIR" --target gcov-clean
+ cmake --build "$BUILD_DIR" --target rstest-check
+ cmake --build "$BUILD_DIR" --target gcov
+ mkdir "$BUILD_DIR/gcov-reports-rsa"
+ find "$BUILD_DIR" -maxdepth 1 -iname '*.gcov' -exec mv "{}" "$BUILD_DIR/gcov-reports-rsa" \;
+}
+
+diskspace()
+{
+ df
+ du -hcs "$SRC_DIR"
+ du -hcs "$BUILD_DIR"
+ du -hcs "$INSTALL_PREFIX"
+}
+
+diskspace
+
+cd "$BUILD_DIR"
+cmake -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" -G"$GENERATOR" -DCMAKE_BUILD_TYPE="$CMAKE_BUILD_TYPE" $ECO "$SRC_DIR" || (cat "$BUILD_DIR"/CMakeFiles/CMakeOutput.log; cat "$BUILD_DIR"/CMakeFiles/CMakeError.log)
+
+case "$TARGET" in
+ "build")
+ target_build
+ ;;
+ "WWW")
+ target_www
+ ;;
+ *)
+ exit 1
+ ;;
+esac
+
+case "$FLAVOR" in
+ "Coverage")
+ handle_coverage_data
+
+ substring="ENABLE_SAMPLEBASED_TESTING"
+ if [ "${ECO#*$substring}" != "$ECO" ];
+ then
+ handle_sample_coverage_data
+ fi
+ ;;
+ *)
+ ;;
+esac
+
+diskspace
diff --git a/src/external/rawspeed/.ci/codecov.yml b/src/external/rawspeed/.ci/codecov.yml
new file mode 100644
index 000000000..4c7ea6417
--- /dev/null
+++ b/src/external/rawspeed/.ci/codecov.yml
@@ -0,0 +1,29 @@
+codecov:
+ notify:
+ require_ci_to_pass: true
+coverage:
+ precision: 2
+ range: "0...100"
+ round: down
+ status:
+ changes: false
+ patch: false
+ project: false
+ ignore:
+ - test/.*
+ notify:
+ irc:
+ default:
+ server: "chat.freenode.net"
+ channel: "#rawspeed"
+parsers:
+ gcov:
+ branch_detection:
+ conditional: true
+ loop: true
+ macro: false
+ method: false
+comment:
+ behavior: default
+ layout: header, diff
+ require_changes: false
diff --git a/src/external/rawspeed/.ci/coverity_model.cpp b/src/external/rawspeed/.ci/coverity_model.cpp
new file mode 100644
index 000000000..f271303bb
--- /dev/null
+++ b/src/external/rawspeed/.ci/coverity_model.cpp
@@ -0,0 +1,25 @@
+/* Coverity Scan model
+ *
+ * This is a modeling file for Coverity Scan. Modeling helps to avoid false
+ * positives.
+ *
+ * - A model file can't import any header files.
+ * - Therefore only some built-in primitives like int, char and void are
+ * available but not wchar_t, NULL etc.
+ * - Modeling doesn't need full structs and typedefs. Rudimentary structs
+ * and similar types are sufficient.
+ * - An uninitialized local pointer is not an error. It signifies that the
+ * variable could be either NULL or have some data.
+ *
+ * Coverity Scan doesn't pick up modifications automatically. The model file
+ * must be uploaded by an admin in the analysis settings of
+ * https://scan.coverity.com/projects/darktable-org-rawspeed
+ */
+
+int rand(void) { /* ignore */
+}
+
+namespace std {
+int rand(void) { /* ignore */
+}
+} // namespace std
diff --git a/src/external/rawspeed/.ci/sonar-project.properties b/src/external/rawspeed/.ci/sonar-project.properties
new file mode 100644
index 000000000..d2ea04418
--- /dev/null
+++ b/src/external/rawspeed/.ci/sonar-project.properties
@@ -0,0 +1,29 @@
+sonar.projectKey=rawspeed
+
+sonar.projectName=RawSpeed
+sonar.projectDescription=fast raw decoding library
+sonar.links.homepage=https://github.com/darktable-org/rawspeed
+sonar.links.ci=https://travis-ci.org/darktable-org/rawspeed
+sonar.links.issue=https://github.com/darktable-org/rawspeed/issues
+sonar.links.scm=https://github.com/darktable-org/rawspeed.git
+
+sonar.sources=src
+sonar.scm.provider=git
+sonar.scm.forceReloadAll=true
+
+sonar.sourceEncoding=UTF-8
+sonar.lang.patterns.c=**/*.c
+sonar.lang.patterns.cpp=**/*.cpp,**/*.cc,**/*.cxx,**/*.c++,**/*.h,**/*.hpp,**/*.hh,**/*.hxx,**/*.h++
+
+sonar.working.directory=build/sonar-workdir
+sonar.cfamily.build-wrapper-output=build/bw-output
+
+# it expects cppunit xml format. googletest format is uncompatible.
+# sonar.cfamily.cppunit.reportsPath=build/unittest-reports
+
+sonar.cfamily.gcov.reportsPath=build
+
+sonar.host.url=https://sonarcloud.io
+sonar.organization=darktable-org
+
+sonar.test.inclusions=**/test/**/*
diff --git a/src/external/rawspeed/.ci/wro_deploy.enc b/src/external/rawspeed/.ci/wro_deploy.enc
new file mode 100644
index 000000000..32eb9e811
--- /dev/null
+++ b/src/external/rawspeed/.ci/wro_deploy.enc
Binary files differ
diff --git a/src/external/rawspeed/.ci/www-finish.sh b/src/external/rawspeed/.ci/www-finish.sh
new file mode 100755
index 000000000..e1c6efd75
--- /dev/null
+++ b/src/external/rawspeed/.ci/www-finish.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+set -e # Exit with nonzero exit code if anything fails
+
+SOURCE_BRANCH="develop"
+TARGET_BRANCH="gh-pages"
+
+# Pull requests and commits to other branches shouldn't try to deploy
+if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "$SOURCE_BRANCH" ]; then
+ exit 1
+fi
+
+# Save some useful information
+REPO="https://github.com/LebedevRI/www.rawspeed.org.git"
+SSH_REPO="git@github.com:LebedevRI/www.rawspeed.org.git"
+
+# Now let's go have some fun with the cloned repo
+cd "$TRAVIS_BUILD_DIR/build/docs/html"
+git config user.name "Travis CI"
+git config user.email "travis@travis-ci.org"
+
+date > .timestamp
+echo "rawspeed.org" > CNAME
+
+# # If there are no changes (e.g. this is a README update) then just bail.
+# if [[ -z `git diff --exit-code` ]]; then
+# echo "No changes to the spec on this push; exiting."
+# exit 0
+# fi
+
+# Commit the "changes", i.e. the new version.
+# The delta will show diffs between new and old versions.
+git add .
+git commit --quiet -m "Deploy to GitHub Pages: ${TRAVIS_COMMIT}"
+
+ENCRYPTION_LABEL="459909475b8a"
+
+# Get the deploy key by using Travis's stored variables to decrypt wro_deploy.enc
+ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key"
+ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv"
+ENCRYPTED_KEY=${!ENCRYPTED_KEY_VAR}
+ENCRYPTED_IV=${!ENCRYPTED_IV_VAR}
+openssl aes-256-cbc -K $ENCRYPTED_KEY -iv $ENCRYPTED_IV -in "$TRAVIS_BUILD_DIR/.ci/wro_deploy.enc" -out "$TRAVIS_BUILD_DIR/.ci/wro_deploy" -d
+chmod 600 "$TRAVIS_BUILD_DIR/.ci/wro_deploy"
+eval `ssh-agent -s`
+ssh-add "$TRAVIS_BUILD_DIR/.ci/wro_deploy"
+
+# Now that we're all set up, we can push.
+git push -f $SSH_REPO $TARGET_BRANCH
diff --git a/src/external/rawspeed/.ci/www-prepare.sh b/src/external/rawspeed/.ci/www-prepare.sh
new file mode 100755
index 000000000..273935af4
--- /dev/null
+++ b/src/external/rawspeed/.ci/www-prepare.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+set -e # Exit with nonzero exit code if anything fails
+
+SOURCE_BRANCH="develop"
+TARGET_BRANCH="gh-pages"
+
+# Pull requests and commits to other branches shouldn't try to deploy
+if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "$SOURCE_BRANCH" ]; then
+ exit 1
+fi
+
+# Save some useful information
+REPO="https://github.com/LebedevRI/www.rawspeed.org.git"
+
+mkdir -p "$TRAVIS_BUILD_DIR/build/docs/"
+cd "$TRAVIS_BUILD_DIR/build/docs/"
+
+# Clone the existing gh-pages for this repo into out/
+# Create a new empty branch if gh-pages doesn't exist yet (should only happen on first deply)
+git clone --depth 1 $REPO html
+cd html
+git checkout $TARGET_BRANCH || git checkout --orphan $TARGET_BRANCH
+cd ..
+
+# Clean out existing contents
+rm -rf html/**/* || exit 0
diff --git a/src/external/rawspeed/.clang-format b/src/external/rawspeed/.clang-format
new file mode 100644
index 000000000..54cb014e8
--- /dev/null
+++ b/src/external/rawspeed/.clang-format
@@ -0,0 +1,18 @@
+---
+Language: Cpp
+BasedOnStyle: LLVM
+Standard: Cpp11
+# Force pointers to the type for C++.
+DerivePointerAlignment: false
+PointerAlignment: Left
+IncludeCategories:
+ - Regex: '^(<|"rawspeedconfig\.h"|>)$'
+ Priority: -2
+ - Regex: '^(<|"RawSpeed-API\.h"|>)$'
+ Priority: -1
+ - Regex: '^(<|"(gtest|gmock)/)'
+ Priority: 2
+ - Regex: '.*'
+ Priority: 1
+IncludeIsMainRegex: ''
+...
diff --git a/src/external/rawspeed/.clang-tidy b/src/external/rawspeed/.clang-tidy
new file mode 100644
index 000000000..a2b115342
--- /dev/null
+++ b/src/external/rawspeed/.clang-tidy
@@ -0,0 +1,38 @@
+---
+Checks: '*,-clang-analyzer-*,-clang-diagnostic-*,-cert-dcl50-cpp,-cert-env33-c,-cert-err58-cpp,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-member-init,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-google-default-arguments,-google-readability-todo,-google-runtime-int,-hicpp-member-init,-hicpp-special-member-functions,-llvm-header-guard,-llvm-include-order,-misc-unused-parameters,-readability-implicit-bool-cast,-readability-inconsistent-declaration-parameter-name,-android-*,-hicpp-braces-around-statements,-hicpp-function-size,-google-readability-braces-around-statements,-google-readability-function-size,-readability-implicit-bool-conversion,-hicpp-signed-bitwise,-hicpp-no-array-decay,-hicpp-vararg,-cppcoreguidelines-owning-memory,-fuchsia-*'
+WarningsAsErrors: '*'
+HeaderFilterRegex: '.*'
+AnalyzeTemporaryDtors: false
+User: lebedevri
+CheckOptions:
+ - key: readability-braces-around-statements.ShortStatementLines
+ value: '3'
+ - key: readability-function-size.BranchThreshold
+ value: '26'
+ - key: readability-function-size.LineThreshold
+ value: '160'
+ - key: readability-function-size.StatementThreshold
+ value: '135'
+ - key: readability-function-size.ParameterThreshold
+ value: '7'
+ - key: readability-function-size.NestingThreshold
+ value: '6'
+ - key: readability-simplify-boolean-expr.ChainedConditionalAssignment
+ value: '1'
+ - key: readability-simplify-boolean-expr.ChainedConditionalReturn
+ value: '1'
+ - key: performance-for-range-copy.WarnOnAllAutoCopies
+ value: '1'
+ - key: google-build-namespaces.HeaderFileExtensions
+ value: 'h,hh,hpp,hxx,'
+ - key: google-global-names-in-headers.HeaderFileExtensions
+ value: 'h,hh,hpp,hxx,'
+ - key: misc-definitions-in-headers.HeaderFileExtensions
+ value: 'h,hh,hpp,hxx,'
+ - key: misc-definitions-in-headers.UseHeaderFileExtension
+ value: '1'
+ - key: readability-identifier-naming.NamespaceCase
+ value: lower_case
+ - key: google-runtime-references.WhiteListTypes
+ value: 'benchmark::State'
+...
diff --git a/src/external/rawspeed/.mailmap b/src/external/rawspeed/.mailmap
new file mode 100644
index 000000000..10506e1b3
--- /dev/null
+++ b/src/external/rawspeed/.mailmap
@@ -0,0 +1,19 @@
+Klaus Post <klauspost@gmail.com>
+Klaus Post <klauspost@gmail.com> post <post@ec705bc8-faf6-4f9b-9aff-b4916e9bedc3>
+
+Anders Brander <anders@brander.dk>
+Anders Brander <anders@brander.dk> abrander <abrander@ec705bc8-faf6-4f9b-9aff-b4916e9bedc3>
+
+Stefan Schöfegger <memo5@gmx.at>
+
+Roman Lebedev <lebedev.ri@gmail.com>
+
+Axel Waggershauser <awagger@gmail.com>
+Axel Waggershauser <awagger@gmail.com> axxel <awagger@web.de>
+
+Peter Budai <peterbudai@hotmail.com>
+Peter Budai <peterbudai@hotmail.com> peterbud <peterbudai@hotmail.com>
+
+Matthieu Volat <mazhe@alkumuna.eu>
+Matthieu Volat <mazhe@alkumuna.eu> Matthieu <mazhe@alkumuna.eu>
+Matthieu Volat <mazhe@alkumuna.eu> Matthieu Volat <matthieu.volat@ujf-grenoble.fr>
diff --git a/src/external/rawspeed/.travis.yml b/src/external/rawspeed/.travis.yml
new file mode 100644
index 000000000..cc1f32686
--- /dev/null
+++ b/src/external/rawspeed/.travis.yml
@@ -0,0 +1,186 @@
+notifications:
+ irc:
+ channels:
+# - "chat.freenode.net#darktable"
+ - secure: "Sl/eC6JEqTMm82H4TANoyngf2oq+TfZ7oiqh3iDqmq0+yNxhnmWGlg+NwhfwpBOoh6eDICoq0CpxOLhXEbNGnILYeHlTbycf41qOS5zP0fquVIgfQJOs6ZNNQWxRO8G1ydkpIl4nMuzix+Uxb09LKN4Ymf2ifLh892yYqwJpwnzyhDZamDa0dNKJuu5r1pzsfAKrLrrd8NnUO6EqUzFz5NjexCZ+wRMKdvkHSGSpQwQ52KonvjnqvFPy11D0f/fZdtNpP9qcalLFXduH0IEafDP82526ri6qcIekJQjgz3eWcrTTuFWI1NOUozIs/maOsLf8NYi8Ql17sw1WorlHZ4Ma48rTUPBEot+lzRk03K+vQaBmFccB9ys0wTVZa4wmmM1051tqsGH7S2ezx8rnULClrMvOLadHiG8JYKwfO5ZjrLRRMndbXH7mSJDKUPrUIMAEvGRDoMP1uqaFf6MFe3mtXv5ZUcaj2GrxF3OIxZtvFFhGZ8HlYInXTGCV2Yaf0NtODWPUKqOYRGzeqPmO6mPVPNcSAyt7YrAT2N4vXUg/+hIAmBfjq+78PpbCZZsZTh12YDbzHmj2TS8ZflciCAhfABxwV1LlVMXXEB3fEpfRsB7Ee1jSd6lrVGy3BAx4GST8NDdI5GVVNKUMtguA8nzDd9iZoq966NlWxYlROlI="
+ skip_join: true
+ template:
+ - "%{repository}#%{build_number} (\x037%{branch}\x03 - \x02%{commit}\x02 : \x033%{author}\x03): \x1f\x02%{message}\x02\x1f"
+ - "Build details : <%{build_url}>"
+ email:
+ recipients:
+# - darktable-ci@lists.darktable.org
+ - secure: "21/+N6QLMqeNojQjOQSooUi6bnHfy4doVO5xefDbpaaX/leFxP6PLv2yNL7d2lk0iwGRCitfbUqF0czmToTvZcE60EGttst5MnHUOyM8d9NR+dOZlVc8fsloIkiCC0nN575xSg5gwGFZmtG94wI0DQBiPQ4UDDPEDcim3c1OjQWn6o8Q4RmLSd65WJxioQRnNqOY0L+TN0T/Re7uIdri2swzNKC+bfdvpOV5Gef0yUPtzTF/0idq8pwwTJ0y8TGhIRDsNlyNdX3SI/TJiUFQDrwxPM1VidwK2FrST+HIYKC4O53KK2XbTN7+3jB0Wv7hdqZ6rzEanmPNRUmzOpbxqcDi8Kb/KJnBm9DkwaXJ1I1jEWdPOEYmoc4FUaA/7QZWtiQvIa1oDRHAQfEDjHJK1mm8z1esYDBrVHvx291DbKHv2AMzfqxrVG0DKG4piXNJMwDummU6SpekbbB5gXJ81dsQPJwOIpNUGax3aFq12sYHG6JSOdMAnzTvOL+WuHCsVnu2sR7LC8Y6kW03A+U/NP4kbbu4QQr4MLJRiE/t1Y14UiMuvz1K7X52V560oauWoGppB8/64EMm4P9SDxm0fosMaqCRmJduKU8pQlsNOnacQ10JlQkVYksXgnEWwrRYEtLSk3PVUf6awkRLES3UZDLSoepmVGRsttJnCAXZR3g="
+ on_success: always
+ on_failure: always
+
+language: generic
+
+before_install:
+ - if [[ "$TARGET" == "SONARQUBE" && ("$TRAVIS_PULL_REQUEST" != "false" || "$TRAVIS_SECURE_ENV_VARS" != "true" || ("$TRAVIS_BRANCH" != "develop" && "$TRAVIS_BRANCH" != "master")) ]]; then
+ exit;
+ fi;
+ - if [[ "$TARGET" == "WWW" && ("$TRAVIS_PULL_REQUEST" != "false" || "$TRAVIS_SECURE_ENV_VARS" != "true" || "$TRAVIS_BRANCH" != "develop") ]]; then
+ exit;
+ fi;
+
+install:
+ - if [[ "$TRAVIS_OS_NAME" == "linux" && "$EXTRA" == "NODOCKER" ]]; then
+ echo "oracle-java8-installer hold" | sudo dpkg --set-selections;
+ echo "oracle-java9-installer hold" | sudo dpkg --set-selections;
+ travis_retry sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y;
+ travis_retry sudo apt-get update -q;
+ travis_retry sudo apt-get install -y -q -f --fix-missing cmake g++-5 git libjpeg-dev libpugixml-dev libxml2-utils make ninja-build zlib1g-dev;
+ fi;
+ - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+ travis_retry brew update > /dev/null && brew tap Homebrew/bundle && cd .ci && brew bundle --verbose;
+ fi;
+ - if [[ "$TRAVIS_OS_NAME" == "linux" && "$FLAVOR" == "Coverage" ]]; then
+ travis_retry sudo apt-get install -y -q -f --fix-missing rsync;
+ fi;
+ - if [[ "$TRAVIS_OS_NAME" == "linux" && "$EXTRA" != "NODOCKER" ]]; then
+ travis_retry docker pull darktable/rawspeed;
+ fi;
+
+before_script:
+ - if [[ "$TRAVIS_OS_NAME" == "linux" && "$FLAVOR" == "Coverage" ]]; then
+ travis_retry rsync -vvrLtW --preallocate --delete --compress --compress-level=1 --stats --progress rsync://raw.pixls.us/data-unique/ $HOME/$RPUU_DST && cd $HOME/$RPUU_DST && sha1sum -c --strict filelist.sha1;
+ fi;
+
+env:
+ global:
+ # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created
+ # via the "travis encrypt" command using the project repo's public key
+ - secure: "rKETh/WScyiRebr6/7ex3FbMqgSL4gucYPj5Z0+F2UkOC+399MFuxHrZ744NwEPGjVvkL39btDVrViwmjp1BJraslQnuPJ8LS7DaVIQQJKnh/pLF8/BclcbGecXrIbSSAtgy3hwKp8N08DXpmyiyaLXsDrPE3/0Oz8JqT9n8b2nzkLDscJSjX73Gp+4DZiUsVzGYYsHq+1k7YbG0xEFrC0OVU3EyHN/bkOepLYUkEKuPj5yi/nRnHLt/1lVdHWBmvELezXnGfuDeGZGb8TbKDTCsv0sscKFDEzK2kzwpAIZbksBHVIcQS8cqcpx48LkvybXOc0vlrS+jMvSUDKAY62+JDZHZd3hCjSIMFVL9bf9b+7gMeevTMKJfLEe9Ro8bHITrKmy0S1Z+mozxdAkESjmFklKgkHBW72T8ttfz33R30Fr87dP9cRwlX2tiU06o8N13228Mh4vr4Cy1S342OOpnf+aw5pq0EydT1eVhjB+B6kmpGinTWbDNtInir2H0w0GlW1VHDZGWqEIB66Nq9aV7ugOBE6b2nsDmBgLS8Xk9OELnRLq2y51Z9nsVq0EnH4td+ciSDPulY9TuUbvBSioMTs8igArM10NFX3+NE13Nla0QiEp1sCKNgxouh5pfkTgmdRL4sQ0MWDPa/c85BaPBF+3xazbI8jZkB19QHKc="
+ - SRC_DIR=/build/rawspeed
+ - BUILD_DIR=/build/rawspeed-build
+ - INSTALL_PREFIX=/build/rawspeed-install
+ - CFLAGS="-pipe" CXXFLAGS="-pipe"
+ - TARGET=build
+ - RPUU_DST="raw-camera-samples/raw.pixls.us-unique/"
+ - DOCKER_RPUU="--volume $HOME/$RPUU_DST:/root/$RPUU_DST:ro"
+
+jobs:
+ fast_finish: true
+ include:
+ - stage: test
+ os: linux
+ dist: trusty
+ sudo: required
+ services:
+ - docker
+ env: CC=gcc-7 CXX=g++-7
+ - os: linux
+ dist: trusty
+ sudo: required
+ services:
+ - docker
+ env: CC=gcc-7 CXX=g++-7 GCOV=gcov-7 FLAVOR=Coverage ECO="-DENABLE_SAMPLEBASED_TESTING=ON" EXTRA_OPTS="$DOCKER_RPUU"
+ cache:
+ directories:
+ - '$HOME/$RPUU_DST'
+ #- os: osx
+ # env: CC=cc CXX=c++
+ #- os: osx
+ # env: CC=cc CXX=c++ FLAVOR=Coverage
+ - os: linux
+ dist: trusty
+ sudo: required
+ services:
+ - docker
+ env: CC=clang-5.0 CXX=clang++-5.0 TARGET=STATICANALYSIS
+ - os: linux
+ dist: trusty
+ sudo: required
+ services:
+ - docker
+ env: CC=clang-5.0 CXX=clang++-5.0 ECO="-DWITH_PTHREADS=OFF"
+ - os: linux
+ dist: trusty
+ sudo: required
+ env: CC=gcc-5 CXX=g++-5 EXTRA=NODOCKER
+ - stage: deploy
+ os: linux
+ dist: trusty
+ sudo: required
+ services:
+ - docker
+ env: CC=gcc-7 CXX=g++-7 GCOV=gcov-7 TARGET=SONARQUBE FLAVOR=Coverage ECO="-DENABLE_SAMPLEBASED_TESTING=ON" EXTRA_OPTS="--tmpfs /root/.sonar --volume $HOME/.sonar/cache:/root/.sonar/cache $DOCKER_RPUU"
+ git:
+ depth: 9999999
+ cache:
+ directories:
+ - '$HOME/$RPUU_DST'
+ - '$HOME/.sonar/cache'
+ - os: linux
+ dist: trusty
+ sudo: required
+ services:
+ - docker
+ env: CC=clang-5.0 CXX=clang++-5.0 TARGET=WWW
+
+# linux clang Coverage build OOM's in gcov during final codecov report collection
+# OSX gcc Coverage build produces invalid .gcno files
+
+script:
+ - set -e
+ - if [[ ("$TRAVIS_OS_NAME" == "linux" && "$EXTRA" == "NODOCKER") || "$TRAVIS_OS_NAME" == "osx" ]]; then
+ export SRC_DIR="$TRAVIS_BUILD_DIR";
+ export BUILD_DIR="$SRC_DIR/build";
+ export INSTALL_PREFIX="$SRC_DIR/install";
+ export ECO="$ECO -DALLOW_DOWNLOADING_GOOGLETEST=ON";
+ mkdir "$BUILD_DIR";
+ mkdir "$INSTALL_PREFIX";
+ "$SRC_DIR/.ci/ci-script.sh";
+ fi;
+ - if [[ "$TRAVIS_OS_NAME" == "linux" && "$EXTRA" != "NODOCKER" ]]; then
+ mkdir "$TRAVIS_BUILD_DIR/build";
+ if [[ "$TARGET" == "SONARQUBE" || "$TARGET" == "WWW" ]]; then
+ export BUILD_DIR="$SRC_DIR/build";
+ fi;
+ if [[ "$TARGET" == "WWW" && "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_SECURE_ENV_VARS" == "true" && "$TRAVIS_BRANCH" == "develop" ]]; then
+ "$TRAVIS_BUILD_DIR/.ci/www-prepare.sh";
+ fi;
+
+ export TARGET2="$TARGET";
+ export CMD="$SRC_DIR/.ci/ci-script.sh";
+ if [[ "$TARGET" == "STATICANALYSIS" ]]; then
+ export TARGET="build";
+ export CMD="scan-build-5.0 --use-cc=\"$CC\" --use-c++=\"$CXX\" --force-analyze-debug-code --status-bugs -disable-checker deadcode.DeadStores $CMD";
+ fi;
+ if [[ "$TARGET" == "SONARQUBE" ]]; then
+ export TARGET="build";
+ export CMD="build-wrapper-linux-x86-64 --out-dir \"$BUILD_DIR/bw-output/\" $CMD";
+ fi;
+
+ docker run --read-only --tmpfs /tmp --volume $TRAVIS_BUILD_DIR:$SRC_DIR:ro --volume "$TRAVIS_BUILD_DIR/build":$BUILD_DIR --workdir $BUILD_DIR --tmpfs $INSTALL_PREFIX $EXTRA_TMPFS $EXTRA_OPTS --env CC --env CXX --env GCOV --env CFLAGS --env CXXFLAGS --env SRC_DIR --env BUILD_DIR --env INSTALL_PREFIX --env TARGET --env FLAVOR --env ECO darktable/rawspeed sh -c "$CMD";
+
+ if [[ "$TARGET2" == "SONARQUBE" ]]; then
+ export CMD="sonar-scanner -X -Dproject.settings=\"$SRC_DIR/.ci/sonar-project.properties\" -Dsonar.login=\"$SONAR_TOKEN\" -Dsonar.branch=\"$TRAVIS_BRANCH\" -Dsonar.projectVersion=\"$TRAVIS_COMMIT\"";
+ docker run --read-only --tmpfs /tmp --volume $TRAVIS_BUILD_DIR:$SRC_DIR:ro --volume "$TRAVIS_BUILD_DIR/build":$BUILD_DIR --workdir $SRC_DIR --tmpfs $INSTALL_PREFIX $EXTRA_TMPFS $EXTRA_OPTS --env CC --env CXX --env GCOV --env CFLAGS --env CXXFLAGS --env SRC_DIR --env BUILD_DIR --env INSTALL_PREFIX --env TARGET --env FLAVOR --env ECO darktable/rawspeed sh -c "$CMD";
+ fi;
+
+ export TARGET="$TARGET2";
+ fi;
+
+after_success:
+ - if [[ "$FLAVOR" == "Coverage" && "$TARGET" != "SONARQUBE" ]]; then
+ cd "$TRAVIS_BUILD_DIR";
+ curl -s https://codecov.io/bash > codecov;
+ chmod +x codecov;
+ export PLATFORM="$TRAVIS_OS_NAME";
+ if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
+ if [[ "$CC" == "cc" ]]; then
+ export CXX=GCC;
+ fi;
+ elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
+ export CXX=AppleClang;
+ fi;
+ ./codecov -e PLATFORM,CXX -F unittests -X gcov -s "$TRAVIS_BUILD_DIR/build/gcov-reports-unittest" -Z;
+ if [[ "$TRAVIS_OS_NAME" == "linux" && "$FLAVOR" == "Coverage" ]]; then
+ ./codecov -e PLATFORM,CXX -F integration,rpu_u -X gcov -s "$TRAVIS_BUILD_DIR/build/gcov-reports-rsa" -Z;
+ fi;
+ fi;
+ - if [[ "$TRAVIS_OS_NAME" == "linux" && "$TARGET" == "WWW" && "$TRAVIS_PULL_REQUEST" == "false" && "$TRAVIS_SECURE_ENV_VARS" == "true" && "$TRAVIS_BRANCH" == "develop" ]]; then
+ "$TRAVIS_BUILD_DIR/.ci/www-finish.sh";
+ fi;
diff --git a/src/external/rawspeed/CMakeLists.txt b/src/external/rawspeed/CMakeLists.txt
new file mode 100644
index 000000000..931dab1c4
--- /dev/null
+++ b/src/external/rawspeed/CMakeLists.txt
@@ -0,0 +1,228 @@
+cmake_minimum_required(VERSION 3.1)
+
+cmake_policy(SET CMP0011 NEW)
+cmake_policy(SET CMP0025 NEW)
+
+# Avoid source tree pollution
+set(CMAKE_DISABLE_SOURCE_CHANGES ON)
+set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
+
+If(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
+ message(FATAL_ERROR "In-source builds are not permitted. Make a separate folder for building:\nmkdir build; cd build; cmake ..\nBefore that, remove the files already created:\nrm -rf CMakeCache.txt CMakeFiles")
+endif(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
+
+# if rawspeed is added as a submodule to another build,
+# this CMakeLists.txt should be added via add_subdirectory().
+if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(RAWSPEED_SOURCE_DIR "${CMAKE_SOURCE_DIR}" CACHE PATH "" FORCE)
+ set(RAWSPEED_STANDALONE_BUILD TRUE CACHE BOOL "" FORCE)
+else()
+ set(RAWSPEED_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE PATH "" FORCE)
+ set(RAWSPEED_STANDALONE_BUILD FALSE CACHE BOOL "" FORCE)
+endif()
+
+include(GNUInstallDirs)
+include(FeatureSummary)
+
+if(NOT (CMAKE_VERSION VERSION_LESS 3.4.0-rc1))
+ project(rawspeed CXX)
+else()
+ # FindThreads.cmake issue
+ project(rawspeed CXX C)
+endif()
+
+set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/Modules/" ${CMAKE_MODULE_PATH})
+set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/" ${CMAKE_MODULE_PATH})
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+set(CMAKE_POSITION_INDEPENDENT_CODE ON)
+
+option(BINARY_PACKAGE_BUILD "Sets march optimization to generic" OFF)
+option(WITH_SSE2 "If SSE2 support is avaliable, do build SSE2 codepaths" ON)
+if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ option(RAWSPEED_USE_LIBCXX "(Clang only) Build using libc++ as the standard library." OFF)
+
+ # when OSX_DEPLOYMENT_TARGET is 10.9 and newer, the default is libc++,
+ # but for no reason let's always specify/use libc++ for apple.
+ if(APPLE)
+ set(RAWSPEED_USE_LIBCXX ON)
+ endif()
+else()
+ set(RAWSPEED_USE_LIBCXX OFF CACHE BOOL "(Clang only) Build using libc++ as the standard library." FORCE)
+endif()
+option(WITH_PTHREADS "Enable threading support through pthread. Highly recommended" ON)
+option(WITH_OPENMP "Enable OpenMP support. Only used for tools, not the library itself." ON)
+option(WITH_PUGIXML "Enable XML support for cameras.xml reading" ON)
+if(WITH_PUGIXML)
+ option(USE_BUNDLED_PUGIXML "Build and use pugixml in-tree" OFF)
+else()
+ set(USE_BUNDLED_PUGIXML OFF CACHE BOOL "Build and use pugixml in-tree" FORCE)
+endif()
+if(WITH_PUGIXML AND USE_BUNDLED_PUGIXML)
+ option(ALLOW_DOWNLOADING_PUGIXML "If pugixml src tree is not found in location specified by PUGIXML_PATH, do fetch the archive from internet" OFF)
+else()
+ set(ALLOW_DOWNLOADING_PUGIXML OFF CACHE BOOL "If pugixml src tree is not found in location specified by PUGIXML_PATH, do fetch the archive from internet" FORCE)
+endif()
+option(WITH_JPEG "Enable JPEG support for DNG Lossy JPEG support" ON)
+option(WITH_ZLIB "Enable ZLIB support for DNG deflate support" ON)
+if(WITH_ZLIB)
+ option(USE_BUNDLED_ZLIB "Build and use zlib in-tree" OFF)
+else()
+ set(USE_BUNDLED_ZLIB OFF CACHE BOOL "Build and use zlib in-tree" FORCE)
+endif()
+if(WITH_ZLIB AND USE_BUNDLED_ZLIB)
+ option(ALLOW_DOWNLOADING_ZLIB "If ZLIB src tree is not found in location specified by ZLIB_PATH, do fetch the archive from internet" OFF)
+else()
+ set(ALLOW_DOWNLOADING_ZLIB OFF CACHE BOOL "If ZLIB src tree is not found in location specified by ZLIB_PATH, do fetch the archive from internet" FORCE)
+endif()
+option(USE_XMLLINT "Run xmllint to test if data/cameras.xml is valid" ON)
+option(USE_IWYU "Run iwyu tool when compiling sources" OFF)
+option(USE_CLANG_TIDY "Run clang-tidy tool when compiling sources" OFF)
+option(BUILD_TESTING "Build the testing tree." ON)
+if(BUILD_TESTING)
+ option(ALLOW_DOWNLOADING_GOOGLETEST "If googletest src tree is not found in location specified by GOOGLETEST_PATH, do fetch the archive from internet" OFF)
+else()
+ set(ALLOW_DOWNLOADING_GOOGLETEST OFF CACHE BOOL "If googletest src tree is not found in location specified by GOOGLETEST_PATH, do fetch the archive from internet" FORCE)
+endif()
+option(BUILD_TOOLS "Build some tools (identify, rstest)." ON)
+option(BUILD_BENCHMARKING "Build some benchmarks." OFF)
+if(BUILD_BENCHMARKING)
+ option(ALLOW_DOWNLOADING_GOOGLEBENCHMARK "If googlebenchmark src tree is not found in location specified by GOOGLEBENCHMARK_PATH, do fetch the archive from internet" OFF)
+else()
+ set(ALLOW_DOWNLOADING_GOOGLEBENCHMARK OFF CACHE BOOL "If googlebenchmark src tree is not found in location specified by GOOGLEBENCHMARK_PATH, do fetch the archive from internet" FORCE)
+endif()
+option(BUILD_DOCS "Build the documentation (Sphinx+Doxygen)." OFF)
+option(BUILD_FUZZERS "Build the fuzzing tree." ON)
+if(BUILD_TOOLS AND BUILD_TESTING)
+ option(ENABLE_SAMPLEBASED_TESTING "If enabled, allows to use rstest to check the samples specified by REFERENCE_SAMPLE_ARCHIVE" OFF)
+else()
+ set(ENABLE_SAMPLEBASED_TESTING OFF CACHE BOOL "If enabled, allows to use rstest to check the samples specified by REFERENCE_SAMPLE_ARCHIVE" FORCE)
+endif()
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ option(USE_LLVM_OPT_REPORT "(Clang only) Save compiler optimizations records and show them" OFF)
+else()
+ set(USE_LLVM_OPT_REPORT OFF CACHE BOOL "(Clang only) Save compiler optimizations records and show them" FORCE)
+endif()
+
+set(GOOGLETEST_PATH "/usr/src/googletest" CACHE PATH
+ "Path to the googletest root tree. Should contain googletest and googlemock subdirs. And CMakeLists.txt in root, and in both of these subdirs")
+
+set(PUGIXML_PATH "/usr/src/pugixml" CACHE PATH "Path to the pugixml root tree.")
+
+set(ZLIB_PATH "/usr/src/zlib" CACHE PATH "Path to the zlib root tree.")
+
+set(GOOGLEBENCHMARK_PATH "/usr/src/googlebenchmark" CACHE PATH
+ "Path to the googlebenchmark root tree.")
+
+set(LIB_FUZZING_ENGINE "OFF" CACHE STRING "Either OFF, or overrides location of prebuilt fuzzing engine library (e.g. libFuzzer) that needs to be linked with all fuzz targets.")
+
+set(REFERENCE_SAMPLE_ARCHIVE "~/raw-camera-samples/raw.pixls.us-unique" CACHE PATH "The location of the reference sample set to use. Should contain filelist.sha1 and timestamp.txt")
+
+option(RAWSPEED_ENABLE_LTO "Add appropriate flag to the compile and link command lines, enabling link-time optimization." OFF)
+
+if(CMAKE_MAKE_PROGRAM MATCHES "ninja")
+ set(RAWSPEED_PARALLEL_LINK_JOBS "" CACHE STRING
+ "Define the maximum number of concurrent link jobs.")
+
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND
+ RAWSPEED_ENABLE_LTO AND NOT RAWSPEED_PARALLEL_LINK_JOBS)
+ message(STATUS "Clang's ThinLTO provides its own parallel linking - limiting parallel link jobs to 2.")
+ set(RAWSPEED_PARALLEL_LINK_JOBS "2")
+ endif()
+
+ if(RAWSPEED_PARALLEL_LINK_JOBS)
+ set_property(GLOBAL APPEND PROPERTY
+ JOB_POOLS link_job_pool=${RAWSPEED_PARALLEL_LINK_JOBS})
+ set(CMAKE_JOB_POOL_LINK link_job_pool)
+ endif()
+else()
+ set(RAWSPEED_PARALLEL_LINK_JOBS "" CACHE STRING
+ "(Ninja-only) Define the maximum number of concurrent link jobs." FORCE)
+
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND RAWSPEED_ENABLE_LTO)
+ message(WARNING "RAWSPEED_ENABLE_LTO is enabled but RAWSPEED_PARALLEL_LINK_JOBS is only supported for Ninja.\nConsider using Ninja Generator!")
+ endif()
+endif()
+
+include(build-type)
+
+if(RAWSPEED_USE_LIBCXX)
+ include(libc++)
+endif()
+
+if(USE_IWYU)
+ include(iwyu)
+endif()
+
+if(USE_LLVM_OPT_REPORT)
+ include(llvm-opt-report)
+endif()
+
+if((UNIX OR APPLE) AND USE_CLANG_TIDY)
+ include(clang-tidy)
+endif()
+
+if(BUILD_TESTING)
+ enable_testing()
+endif()
+
+include(compiler-versions)
+include(compiler-flags)
+
+add_custom_target(check ALL)
+add_custom_target(dependencies ALL)
+add_custom_target(tests ALL)
+
+include(compiler-warnings)
+set_directory_properties(PROPERTIES COMPILE_OPTIONS "-Werror")
+
+if(BUILD_BENCHMARKING)
+ add_custom_target(benchmarks ALL)
+endif()
+
+add_subdirectory(src)
+
+include(OpenMP)
+
+if(BUILD_TESTING)
+ add_subdirectory(test)
+endif()
+
+if(BUILD_BENCHMARKING)
+ add_subdirectory(bench)
+endif()
+
+if(BUILD_FUZZERS)
+ add_subdirectory(fuzz)
+endif()
+
+add_subdirectory(data)
+
+if(BUILD_DOCS)
+ add_subdirectory(docs)
+endif()
+
+if(BUILD_TESTING AND CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ include(llvm-profdata)
+ include(llvm-cov)
+ elseif(CMAKE_COMPILER_IS_GNUCXX OR
+ CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+ include(gcc-gcov)
+
+ find_package(LCov)
+ find_package(GenHtml)
+
+ if(LCov_FOUND AND GenHtml_FOUND)
+ include(lcov)
+ include(genhtml)
+ include(gcc-coverage)
+ else()
+ message(WARNING "Did not find lcov and genhtml."
+ "Will not be able to generate HTML reports")
+ endif()
+ endif()
+endif()
+
+feature_summary(WHAT ALL)
diff --git a/src/external/rawspeed/LICENSE b/src/external/rawspeed/LICENSE
new file mode 100644
index 000000000..e5ab03e12
--- /dev/null
+++ b/src/external/rawspeed/LICENSE
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/src/external/rawspeed/README.rst b/src/external/rawspeed/README.rst
new file mode 100644
index 000000000..535697015
--- /dev/null
+++ b/src/external/rawspeed/README.rst
@@ -0,0 +1,90 @@
+rawspeed |travis-ci| |appveyor-ci| OBS_ |codecov| |coverity status|
+
+.. |travis-ci| image:: https://travis-ci.org/darktable-org/rawspeed.svg?branch=develop
+ :target: https://travis-ci.org/darktable-org/rawspeed
+
+.. |appveyor-ci| image:: https://ci.appveyor.com/api/projects/status/7pqy0gdr9mp16xu2/branch/develop?svg=true
+ :target: https://ci.appveyor.com/project/LebedevRI/rawspeed/branch/develop
+
+.. _OBS: https://build.opensuse.org/project/monitor/graphics:darktable:master
+
+.. |codecov| image:: https://codecov.io/gh/darktable-org/rawspeed/branch/develop/graph/badge.svg
+ :target: https://codecov.io/gh/darktable-org/rawspeed
+
+.. |coverity status| image:: https://scan.coverity.com/projects/11256/badge.svg
+ :target: https://scan.coverity.com/projects/darktable-org-rawspeed
+
+================================================================================
+RawSpeed Developer Information
+================================================================================
+What is RawSpeed?
+--------------------------------------------------------------------------------
+
+RawSpeed…
+
+- is capable of decoding various images in RAW file format.
+- is intended to provide the fastest decoding speed possible.
+- supports the most common DSLR and similar class brands.
+- supplies unmodified RAW data, optionally scaled to 16 bit, or normalized to 0->1 float point data.
+- supplies CFA layout for all known cameras.
+- provides automatic black level calculation for cameras having such information.
+- optionally crops off “junk” areas of images, containing no valid image information.
+- can add support for new cameras by adding definitions to an xml file.
+- decodes images from memory, not a file stream.
+- is being continuously fuzzed as part of the `oss-fuzz`_ project.
+- is currently tested on |rpu-button-cameras| unique cameras, on |rpu-button-samples| unique samples.
+ **Please read** `this <rpu-post_>`_ **for more info on how to contribute samples!**
+- open source under the `LGPL v2`_ license.
+
+.. _oss-fuzz: https://github.com/google/oss-fuzz
+
+.. |rpu-button-cameras| image:: https://raw.pixls.us/button-cameras.svg
+ :target: https://raw.pixls.us/
+
+.. |rpu-button-samples| image:: https://raw.pixls.us/button-samples.svg
+ :target: https://raw.pixls.us/
+
+.. _rpu-post: https://discuss.pixls.us/t/raw-samples-wanted/5420?u=lebedevri
+
+.. _LGPL v2: https://choosealicense.com/licenses/lgpl-2.1/
+
+RawSpeed does **NOT**…
+
+- read metadata information, beside whitebalance information.
+- do any color correction or whitebalance correction.
+- de-mosaic the image.
+- supply a viewable image or thumbnail.
+- crop the image to the same sizes as manufactures, but supplies biggest possible images.
+
+So RawSpeed is not intended to be a complete RAW file display library, but only act as the first stage decoding, delivering the RAW data to your application.
+
+Version 2, new cameras and features
+--------------------------------------------------------------------------------
+- Support for Sigma foveon cameras.
+- Support for Fuji cameras.
+- Support old Minolta, Panasonic, Sony cameras (contributed by Pedro Côrte-Real)
+- Arbitrary CFA definition sizes.
+- Use pugixml_ for xml parsing to avoid depending on libxml.
+
+.. _pugixml: http://pugixml.org/
+
+Getting Source Code
+--------------------------------------------------------------------------------
+You can get access to the lastest version using `from here <rawspeed_>`_. You will need to include the “RawSpeed” and “data” folder in your own project.
+
+CMake-based build system is provided.
+
+Background of RawSpeed
+----------------------
+The main objectives were to make a very fast loader that worked for 75% of the cameras out there, and was able to decode a RAW file at close to the optimal speed. The last 25% of the cameras out there could be serviced by a more generic loader, or convert their images to DNG – which as a sidenote usually compresses better than your camera.
+
+RawSpeed is not at the moment a separate library, so you have to include it in your project directly.
+
+Please see <http://rawspeed.org/> for documentation.
+Doxygen-generated documentation is avaliable at <http://rawspeed.org/doxygen>
+
+Submitting Requests and Patches
+--------------------------------------------------------------------------------
+Please go to the `github page <rawspeed_>`_ and submit your (pull)requests and issues there.
+
+.. _rawspeed: https://github.com/darktable-org/rawspeed
diff --git a/src/external/rawspeed/bench/CMakeLists.txt b/src/external/rawspeed/bench/CMakeLists.txt
new file mode 100644
index 000000000..9df71e0d1
--- /dev/null
+++ b/src/external/rawspeed/bench/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(librawspeed)
diff --git a/src/external/rawspeed/bench/librawspeed/CMakeLists.txt b/src/external/rawspeed/bench/librawspeed/CMakeLists.txt
new file mode 100644
index 000000000..b7c1c3f35
--- /dev/null
+++ b/src/external/rawspeed/bench/librawspeed/CMakeLists.txt
@@ -0,0 +1,28 @@
+if(CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
+ # want all the symbols.
+ add_library(rawspeed_bench SHARED)
+else()
+ add_library(rawspeed_bench STATIC)
+endif()
+
+target_link_libraries(rawspeed_bench PUBLIC rawspeed)
+target_link_libraries(rawspeed_bench PUBLIC benchmark)
+target_include_directories(rawspeed_bench PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
+
+if(WITH_OPENMP AND OPENMP_FOUND AND TARGET OpenMP::OpenMP)
+ target_link_libraries(rawspeed_bench PUBLIC OpenMP::OpenMP)
+endif()
+
+function(add_rs_bench src)
+ get_filename_component(BENCHNAME ${src} NAME_WE)
+ add_executable(${BENCHNAME} ${src})
+ target_link_libraries(${BENCHNAME} PUBLIC rawspeed)
+ target_link_libraries(${BENCHNAME} PUBLIC rawspeed_bench)
+
+ add_dependencies(benchmarks ${BENCHNAME})
+endfunction()
+
+add_subdirectory(bench)
+add_subdirectory(decompressors)
+add_subdirectory(interpolators)
+add_subdirectory(io)
diff --git a/src/external/rawspeed/bench/librawspeed/bench/CMakeLists.txt b/src/external/rawspeed/bench/librawspeed/bench/CMakeLists.txt
new file mode 100644
index 000000000..36311c7fd
--- /dev/null
+++ b/src/external/rawspeed/bench/librawspeed/bench/CMakeLists.txt
@@ -0,0 +1,9 @@
+FILE(GLOB RAWSPEED_BENCH_SOURCES
+ "${CMAKE_SOURCE_DIR}/test/librawspeed/test/RawSpeed.cpp"
+ "Common.cpp"
+ "Common.h"
+)
+
+target_sources(rawspeed_bench PRIVATE
+ ${RAWSPEED_BENCH_SOURCES}
+)
diff --git a/src/external/rawspeed/bench/librawspeed/bench/Common.cpp b/src/external/rawspeed/bench/librawspeed/bench/Common.cpp
new file mode 100644
index 000000000..ca2871bca
--- /dev/null
+++ b/src/external/rawspeed/bench/librawspeed/bench/Common.cpp
@@ -0,0 +1,44 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "bench/Common.h"
+#include "common/Common.h" // for roundUp
+#include "common/Point.h" // for iPoint2D
+#include <cassert> // for assert
+#include <cmath> // for ceil, sqrt
+
+using rawspeed::iPoint2D;
+using rawspeed::roundUp;
+using std::sqrt;
+
+iPoint2D __attribute__((const)) areaToRectangle(size_t area, iPoint2D aspect) {
+ double sqSide = sqrt(area);
+ double sqARatio =
+ sqrt(static_cast<double>(aspect.x) / static_cast<double>(aspect.y));
+
+ iPoint2D dim(ceil(sqSide * sqARatio), ceil(sqSide / sqARatio));
+
+ dim.x = roundUp(dim.x, aspect.x);
+ dim.y = roundUp(dim.y, aspect.y);
+
+ assert(dim.area() >= area);
+
+ return dim;
+}
diff --git a/src/external/rawspeed/bench/librawspeed/bench/Common.h b/src/external/rawspeed/bench/librawspeed/bench/Common.h
new file mode 100644
index 000000000..7b4f99282
--- /dev/null
+++ b/src/external/rawspeed/bench/librawspeed/bench/Common.h
@@ -0,0 +1,25 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Point.h" // for iPoint2D
+#include <cstddef> // for size_t
+
+rawspeed::iPoint2D __attribute__((const))
+areaToRectangle(size_t area, rawspeed::iPoint2D aspect = {2, 2});
diff --git a/src/external/rawspeed/bench/librawspeed/decompressors/CMakeLists.txt b/src/external/rawspeed/bench/librawspeed/decompressors/CMakeLists.txt
new file mode 100644
index 000000000..24a05f0b9
--- /dev/null
+++ b/src/external/rawspeed/bench/librawspeed/decompressors/CMakeLists.txt
@@ -0,0 +1,9 @@
+if(HAVE_ZLIB)
+ FILE(GLOB RAWSPEED_BENCHS_SOURCES
+ "DeflateDecompressorBenchmark.cpp"
+ )
+
+ foreach(IN ${RAWSPEED_BENCHS_SOURCES})
+ add_rs_bench(${IN})
+ endforeach()
+endif()
diff --git a/src/external/rawspeed/bench/librawspeed/decompressors/DeflateDecompressorBenchmark.cpp b/src/external/rawspeed/bench/librawspeed/decompressors/DeflateDecompressorBenchmark.cpp
new file mode 100644
index 000000000..f238c0b77
--- /dev/null
+++ b/src/external/rawspeed/bench/librawspeed/decompressors/DeflateDecompressorBenchmark.cpp
@@ -0,0 +1,145 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/DeflateDecompressor.h" // for DeflateDecompressor
+#include "bench/Common.h" // for areaToRectangle
+#include "common/Common.h" // for isAligned, isPowerOfTwo
+#include "common/Memory.h" // for alignedFree
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include <algorithm> // for move
+#include <benchmark/benchmark.h> // for Benchmark, BENCHMARK_...
+#include <cassert> // for assert
+#include <cstddef> // for size_t
+#include <memory> // for unique_ptr
+#include <type_traits> // for integral_constant
+#include <zlib.h>
+
+#ifndef NDEBUG
+#include <limits> // for numeric_limits
+#endif
+
+using rawspeed::Buffer;
+using rawspeed::DeflateDecompressor;
+
+template <size_t N> using BPS = std::integral_constant<size_t, N>;
+template <int N> using Pf = std::integral_constant<int, N>;
+
+template <typename BPS>
+static std::unique_ptr<rawspeed::uchar8, decltype(&rawspeed::alignedFree)>
+compressChunk(const rawspeed::RawImage& mRaw, uLong* bufSize) {
+ static_assert(BPS::value > 0, "bad bps");
+ static_assert(rawspeed::isAligned(BPS::value, 8), "not byte count");
+
+ const uLong uncompressedLength = BPS::value * mRaw->dim.x * mRaw->dim.y / 8UL;
+ assert(uncompressedLength > 0);
+ assert(uncompressedLength <= std::numeric_limits<Buffer::size_type>::max());
+
+ *bufSize = compressBound(uncompressedLength);
+ assert(*bufSize > 0);
+ assert(*bufSize <= std::numeric_limits<Buffer::size_type>::max());
+
+ // will contain some random garbage
+ auto uBuf = Buffer::Create(uncompressedLength);
+ assert(uBuf != nullptr);
+
+ auto cBuf = Buffer::Create(*bufSize);
+ assert(cBuf != nullptr);
+
+ const int err = compress(cBuf.get(), bufSize, uBuf.get(), uncompressedLength);
+ if (err != Z_OK)
+ throw;
+
+ assert(compressBound(uncompressedLength) >= *bufSize);
+
+ return cBuf;
+}
+
+template <typename BPS, typename Pf>
+static inline void BM_DeflateDecompressor(benchmark::State& state) {
+ static_assert(BPS::value > 0, "bad bps");
+ static_assert(rawspeed::isAligned(BPS::value, 8), "not byte count");
+
+ const auto dim = areaToRectangle(state.range(0));
+ auto mRaw = rawspeed::RawImage::create(dim, rawspeed::TYPE_FLOAT32, 1);
+
+ uLong cBufSize;
+ auto cBuf = compressChunk<BPS>(mRaw, &cBufSize);
+ assert(cBuf != nullptr);
+ assert(cBufSize > 0);
+
+ Buffer buf(std::move(cBuf), cBufSize);
+ assert(buf.getSize() == cBufSize);
+
+ int predictor = 0;
+ switch (Pf::value) {
+ case 0:
+ predictor = 0;
+ break;
+ case 1:
+ predictor = 3;
+ break;
+ case 2:
+ predictor = 34894;
+ break;
+ case 4:
+ predictor = 34895;
+ break;
+ default:
+ __builtin_unreachable();
+ break;
+ }
+
+ std::unique_ptr<unsigned char[]> uBuffer;
+
+ const rawspeed::ByteStream bs(buf, 0, buf.getSize());
+
+ for (auto _ : state) {
+ DeflateDecompressor d(bs, mRaw, predictor, BPS::value);
+
+ d.decode(&uBuffer, mRaw->dim.x, mRaw->dim.y, 0, 0);
+ }
+
+ state.SetComplexityN(dim.area());
+ state.SetItemsProcessed(state.complexity_length_n() * state.iterations());
+ state.SetBytesProcessed(BPS::value * state.items_processed() / 8);
+}
+
+static inline void CustomArgs(benchmark::internal::Benchmark* b) {
+ b->RangeMultiplier(2);
+// FIXME: appears to not like 1GPix+ buffers
+#if 1
+ b->Arg(128 << 20);
+#else
+ b->Range(1, 1023 << 20)->Complexity(benchmark::oN);
+#endif
+ b->Unit(benchmark::kMillisecond);
+}
+
+#define GEN_E(s, f) \
+ BENCHMARK_TEMPLATE(BM_DeflateDecompressor, BPS<s>, Pf<f>)->Apply(CustomArgs);
+#define GEN_PFS(s) GEN_E(s, 0) GEN_E(s, 1) GEN_E(s, 2) GEN_E(s, 4)
+#define GEN_PSS() GEN_PFS(16) GEN_PFS(24) GEN_PFS(32)
+
+GEN_PSS()
+
+BENCHMARK_MAIN();
diff --git a/src/external/rawspeed/bench/librawspeed/interpolators/CMakeLists.txt b/src/external/rawspeed/bench/librawspeed/interpolators/CMakeLists.txt
new file mode 100644
index 000000000..5b5cc7fef
--- /dev/null
+++ b/src/external/rawspeed/bench/librawspeed/interpolators/CMakeLists.txt
@@ -0,0 +1,7 @@
+FILE(GLOB RAWSPEED_BENCHS_SOURCES
+ "Cr2sRawInterpolatorBenchmark.cpp"
+)
+
+foreach(IN ${RAWSPEED_BENCHS_SOURCES})
+ add_rs_bench(${IN})
+endforeach()
diff --git a/src/external/rawspeed/bench/librawspeed/interpolators/Cr2sRawInterpolatorBenchmark.cpp b/src/external/rawspeed/bench/librawspeed/interpolators/Cr2sRawInterpolatorBenchmark.cpp
new file mode 100644
index 000000000..afef1354c
--- /dev/null
+++ b/src/external/rawspeed/bench/librawspeed/interpolators/Cr2sRawInterpolatorBenchmark.cpp
@@ -0,0 +1,78 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "interpolators/Cr2sRawInterpolator.h" // for Cr2sRawInterpolator
+#include "bench/Common.h" // for areaToRectangle
+#include "common/Common.h" // for roundUp, ushort16
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, ImageMetaData
+#include <array> // for array
+#include <benchmark/benchmark.h> // for Benchmark, State, BEN...
+#include <type_traits> // for integral_constant
+
+using rawspeed::Cr2sRawInterpolator;
+using rawspeed::iPoint2D;
+using rawspeed::RawImage;
+using rawspeed::TYPE_USHORT16;
+using rawspeed::ushort16;
+using std::array;
+using std::integral_constant;
+
+template <int N> using v = integral_constant<int, N>;
+
+template <const iPoint2D& subsampling, typename version>
+static inline void BM_Cr2sRawInterpolator(benchmark::State& state) {
+ static const array<int, 3> sraw_coeffs = {{999, 1000, 1001}};
+ static const int hue = 1269;
+
+ const auto dim = areaToRectangle(state.range(0));
+ RawImage mRaw = RawImage::create(dim, TYPE_USHORT16, 3);
+ mRaw->metadata.subsampling = subsampling;
+
+ Cr2sRawInterpolator i(mRaw, sraw_coeffs, hue);
+
+ for (auto _ : state)
+ i.interpolate(version::value);
+
+ state.SetComplexityN(dim.area());
+ state.SetItemsProcessed(state.complexity_length_n() * state.iterations());
+ state.SetBytesProcessed(3UL * sizeof(ushort16) * state.items_processed());
+}
+
+static inline void CustomArguments(benchmark::internal::Benchmark* b) {
+ b->RangeMultiplier(2);
+#if 1
+ b->Arg(256 << 20);
+#else
+ b->Range(1, 1024 << 20)->Complexity(benchmark::oN);
+#endif
+ b->Unit(benchmark::kMillisecond);
+}
+
+static constexpr const iPoint2D S422(2, 1);
+BENCHMARK_TEMPLATE(BM_Cr2sRawInterpolator, S422, v<0>)->Apply(CustomArguments);
+BENCHMARK_TEMPLATE(BM_Cr2sRawInterpolator, S422, v<1>)->Apply(CustomArguments);
+BENCHMARK_TEMPLATE(BM_Cr2sRawInterpolator, S422, v<2>)->Apply(CustomArguments);
+
+static constexpr const iPoint2D S420(2, 2);
+BENCHMARK_TEMPLATE(BM_Cr2sRawInterpolator, S420, v<1>)->Apply(CustomArguments);
+BENCHMARK_TEMPLATE(BM_Cr2sRawInterpolator, S420, v<2>)->Apply(CustomArguments);
+
+BENCHMARK_MAIN();
diff --git a/src/external/rawspeed/bench/librawspeed/io/BitStreamBenchmark.cpp b/src/external/rawspeed/bench/librawspeed/io/BitStreamBenchmark.cpp
new file mode 100644
index 000000000..9d47475fd
--- /dev/null
+++ b/src/external/rawspeed/bench/librawspeed/io/BitStreamBenchmark.cpp
@@ -0,0 +1,145 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Common.h" // for roundUp
+#include "io/BitPumpJPEG.h" // for BitPumpJPEG
+#include "io/BitPumpLSB.h" // for BitPumpLSB, BitStream<>::fillCache
+#include "io/BitPumpMSB.h" // for BitPumpMSB
+#include "io/BitPumpMSB16.h" // for BitPumpMSB16
+#include "io/BitPumpMSB32.h" // for BitPumpMSB32
+#include "io/Buffer.h" // for Buffer, Buffer::size_type, Data...
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::big, Endian...
+#include <benchmark/benchmark.h> // for State, Benchmark, Initialize
+#include <cassert> // for assert
+#include <cstddef> // for size_t
+#include <limits> // for numeric_limits
+#include <string> // for string, to_string
+#include <type_traits> // for integral_constant
+
+using rawspeed::BitPumpJPEG;
+using rawspeed::BitPumpLSB;
+using rawspeed::BitPumpMSB;
+using rawspeed::BitPumpMSB16;
+using rawspeed::BitPumpMSB32;
+using rawspeed::Endianness;
+
+static constexpr const size_t STEP_MAX = 32;
+
+template <typename Pump>
+static inline void BM_BitStream(benchmark::State& state, Endianness endianness,
+ unsigned int fillSize, unsigned int Step) {
+ assert(state.range(0) > 0);
+ assert((size_t)state.range(0) <=
+ std::numeric_limits<rawspeed::Buffer::size_type>::max());
+
+ assert(fillSize > 0);
+ assert(fillSize <= STEP_MAX);
+
+ assert(Step > 0);
+ assert(Step <= STEP_MAX);
+
+ assert(Step <= fillSize);
+
+ assert((Step == 1) || rawspeed::isAligned(Step, 2));
+ assert((fillSize == 1) || rawspeed::isAligned(fillSize, 2));
+
+ const rawspeed::Buffer b(state.range(0));
+ assert(b.getSize() > 0);
+ assert(b.getSize() == (size_t)state.range(0));
+
+ const rawspeed::DataBuffer db(b, endianness);
+ const rawspeed::ByteStream bs(db);
+
+ Pump pump(bs);
+
+ size_t processedBits = 0;
+ for (auto _ : state) {
+ pump.resetBufferPosition();
+
+ for (processedBits = 0; processedBits <= 8 * b.getSize();) {
+ pump.fill(fillSize);
+
+ // NOTE: you may want to change the callee here
+ for (auto i = 0U; i < fillSize; i += Step)
+ pump.skipBitsNoFill(Step);
+
+ processedBits += fillSize;
+ }
+ }
+
+ assert(processedBits > fillSize);
+ processedBits -= fillSize;
+
+ assert(rawspeed::roundUp(8 * b.getSize(), fillSize) == processedBits);
+
+ state.SetComplexityN(processedBits / 8);
+ state.SetItemsProcessed(processedBits * state.iterations());
+ state.SetBytesProcessed(state.items_processed() / 8);
+}
+
+static inline void CustomArguments(benchmark::internal::Benchmark* b) {
+ b->RangeMultiplier(2);
+#if 1
+ b->Arg(256 << 20);
+#else
+ b->Range(1, 1024 << 20);
+ b->Complexity(benchmark::oN);
+#endif
+ b->Unit(benchmark::kMillisecond);
+}
+
+using Big = std::integral_constant<Endianness, Endianness::big>;
+using Little = std::integral_constant<Endianness, Endianness::little>;
+
+template <typename BO, typename PUMP>
+void registerPump(const char* byteOrder, const char* pumpName) {
+ for (size_t i = 1; i <= STEP_MAX; i *= 2) {
+ for (size_t j = 1; j <= i && j <= STEP_MAX; j *= 2) {
+ std::string name("BM_BitStream<ByteOrder<");
+ name += byteOrder;
+ name += ">, Spec<";
+ name += pumpName;
+ name += ">, Fill<";
+ name += std::to_string(i);
+ name += ">, Step<";
+ name += std::to_string(j);
+ name += ">>";
+
+ const auto Fn = BM_BitStream<PUMP>;
+ auto* b = benchmark::RegisterBenchmark(name.c_str(), Fn, BO::value, i, j);
+ b->Apply(CustomArguments);
+ }
+ }
+}
+
+#define REG_PUMP_2(BO, PUMP) registerPump<BO, PUMP>(#BO, #PUMP);
+#define REGISTER_PUMP(PUMP) REG_PUMP_2(Big, PUMP) REG_PUMP_2(Little, PUMP)
+
+int main(int argc, char** argv) {
+ REGISTER_PUMP(BitPumpLSB);
+ REGISTER_PUMP(BitPumpMSB);
+ REGISTER_PUMP(BitPumpMSB16);
+ REGISTER_PUMP(BitPumpMSB32);
+ REGISTER_PUMP(BitPumpJPEG);
+
+ benchmark::Initialize(&argc, argv);
+ benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/src/external/rawspeed/bench/librawspeed/io/CMakeLists.txt b/src/external/rawspeed/bench/librawspeed/io/CMakeLists.txt
new file mode 100644
index 000000000..1e491bf0f
--- /dev/null
+++ b/src/external/rawspeed/bench/librawspeed/io/CMakeLists.txt
@@ -0,0 +1,7 @@
+FILE(GLOB RAWSPEED_BENCHS_SOURCES
+ "BitStreamBenchmark.cpp"
+)
+
+foreach(IN ${RAWSPEED_BENCHS_SOURCES})
+ add_rs_bench(${IN})
+endforeach()
diff --git a/src/external/rawspeed/cmake/Modules/CheckCXXCompilerFlagAndEnableIt.cmake b/src/external/rawspeed/cmake/Modules/CheckCXXCompilerFlagAndEnableIt.cmake
new file mode 100644
index 000000000..d93f089ec
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/CheckCXXCompilerFlagAndEnableIt.cmake
@@ -0,0 +1,24 @@
+include(CheckCXXCompilerFlag)
+
+function(mangle_flag_name PREFIX FLAG OUTPUT)
+ string(TOUPPER "${PREFIX}_${FLAG}" MANGLED_FLAG)
+ string(REPLACE "+" "X" MANGLED_FLAG ${MANGLED_FLAG})
+ string(REGEX REPLACE "[^A-Za-z_0-9]" "_" MANGLED_FLAG ${MANGLED_FLAG})
+ string(REGEX REPLACE "_+" "_" MANGLED_FLAG ${MANGLED_FLAG})
+ set(${OUTPUT} "${MANGLED_FLAG}" PARENT_SCOPE)
+endfunction()
+
+macro (CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT _FLAG)
+ mangle_flag_name("RAWSPEED_HAVE_CXX_FLAG" "${_FLAG}" _RESULT)
+
+ set(CMAKE_REQUIRED_FLAGS_ORIG "${CMAKE_REQUIRED_FLAGS}")
+ set(CMAKE_REQUIRED_FLAGS "${CMAKE_CXX_FLAGS}")
+
+ CHECK_CXX_COMPILER_FLAG("${_FLAG}" ${_RESULT})
+
+ if(${${_RESULT}})
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_FLAG}")
+ endif()
+
+ set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_ORIG}")
+endmacro ()
diff --git a/src/external/rawspeed/cmake/Modules/CheckJPEGSymbols.cmake b/src/external/rawspeed/cmake/Modules/CheckJPEGSymbols.cmake
new file mode 100644
index 000000000..6843d7282
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/CheckJPEGSymbols.cmake
@@ -0,0 +1,12 @@
+include(CheckCXXSymbolExists)
+
+set(CMAKE_REQUIRED_INCLUDES_SAVE "${CMAKE_REQUIRED_INCLUDES}")
+set(CMAKE_REQUIRED_LIBRARIES_SAVE "${CMAKE_REQUIRED_LIBRARIES}")
+
+set(CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES_SAVE};${JPEG_INCLUDE_DIRS}")
+set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_SAVE};${JPEG_LIBRARIES}")
+
+CHECK_CXX_SYMBOL_EXISTS(jpeg_mem_src "cstdio;jpeglib.h" HAVE_JPEG_MEM_SRC)
+
+set(CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES_SAVE}")
+set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_SAVE}")
diff --git a/src/external/rawspeed/cmake/Modules/CheckZLIB.cmake b/src/external/rawspeed/cmake/Modules/CheckZLIB.cmake
new file mode 100644
index 000000000..413b550ca
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/CheckZLIB.cmake
@@ -0,0 +1,61 @@
+include(CheckIncludeFileCXX)
+include(CheckTypeSize)
+include(CheckPrototypeDefinition)
+include(CheckCXXSymbolExists)
+
+set(CMAKE_REQUIRED_INCLUDES_SAVE "${CMAKE_REQUIRED_INCLUDES}")
+set(CMAKE_EXTRA_INCLUDE_FILES_SAVE "${CMAKE_EXTRA_INCLUDE_FILES}")
+set(CMAKE_REQUIRED_LIBRARIES_SAVE "${CMAKE_REQUIRED_LIBRARIES}")
+
+set(CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES_SAVE};${ZLIB_INCLUDE_DIRS}")
+
+CHECK_INCLUDE_FILE_CXX("zlib.h" HAVE_ZLIB_H)
+if(NOT HAVE_ZLIB_H)
+ message(SEND_ERROR "Did not find <zlib.h> header")
+endif()
+
+set(CMAKE_EXTRA_INCLUDE_FILES "zlib.h")
+
+CHECK_TYPE_SIZE(uLongf HAVE_ZLIB_ULONGF)
+if(NOT HAVE_ZLIB_ULONGF)
+ message(SEND_ERROR "Did not find uLongf type in <zlib.h>")
+endif()
+
+CHECK_CXX_SYMBOL_EXISTS(Z_OK "zlib.h" HAVE_ZLIB_Z_OK)
+if(NOT HAVE_ZLIB_Z_OK)
+ message(SEND_ERROR "Did not find Z_OK macro in <zlib.h>")
+endif()
+
+CHECK_PROTOTYPE_DEFINITION(uncompress
+ "int uncompress(unsigned char* dest, uLongf* destLen, const unsigned char* source, unsigned long sourceLen)"
+ "Z_OK"
+ "zlib.h"
+ HAVE_ZLIB_UNCOMPRESS_PROTOTYPE)
+if(NOT HAVE_ZLIB_UNCOMPRESS_PROTOTYPE)
+ message(SEND_ERROR "Found unexpected prototype for uncompress() in <zlib.h>")
+endif()
+
+CHECK_PROTOTYPE_DEFINITION(zError
+ "const char* zError(int zErrorCode)"
+ "NULL"
+ "zlib.h"
+ HAVE_ZLIB_ZERROR_PROTOTYPE)
+if(NOT HAVE_ZLIB_ZERROR_PROTOTYPE)
+ message(SEND_ERROR "Found unexpected prototype for zError() in <zlib.h>")
+endif()
+
+set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_SAVE};${ZLIB_LIBRARIES}")
+
+CHECK_CXX_SYMBOL_EXISTS(uncompress "zlib.h" HAVE_ZLIB_UNCOMPRESS)
+if(NOT HAVE_ZLIB_UNCOMPRESS)
+ message(SEND_ERROR "Did not find uncompress() function in ZLIB")
+endif()
+
+CHECK_CXX_SYMBOL_EXISTS(zError "zlib.h" HAVE_ZLIB_ZERROR)
+if(NOT HAVE_ZLIB_ZERROR)
+ message(SEND_ERROR "Did not find zError() function in ZLIB")
+endif()
+
+set(CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES_SAVE}")
+set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_SAVE}")
+set(CMAKE_EXTRA_INCLUDE_FILES "${CMAKE_EXTRA_INCLUDE_FILES_SAVE}")
diff --git a/src/external/rawspeed/cmake/Modules/CpuMarch.cmake b/src/external/rawspeed/cmake/Modules/CpuMarch.cmake
new file mode 100644
index 000000000..747e9f1fe
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/CpuMarch.cmake
@@ -0,0 +1,37 @@
+include(CheckCXXCompilerFlag)
+
+if(NOT BINARY_PACKAGE_BUILD)
+ message(STATUS "Checking for -march=native support")
+ CHECK_CXX_COMPILER_FLAG("-march=native" MARCHNATIVE)
+ if(MARCHNATIVE)
+ message(STATUS "Checking for -march=native support - works")
+ set(MARCH "-march=native")
+ else()
+ message(STATUS "Checking for -mtune=native support")
+ CHECK_CXX_COMPILER_FLAG("-mtune=native" MTUNENATIVE)
+ if(MTUNENATIVE)
+ message(STATUS "Checking for -mtune=native support - works")
+ set(MARCH "-mtune=native")
+ else()
+ message(STATUS "Checking for -mtune=generic support")
+ CHECK_CXX_COMPILER_FLAG("-mtune=generic" MTUNEGENERIC)
+ if(MTUNEGENERIC)
+ message(STATUS "Checking for -mtune=generic support - works")
+ set(MARCH "-mtune=generic")
+ else()
+ message(WARNING "Do not know which -march/-mtune to pass! Resulting binaries may be broken!")
+ endif()
+ endif()
+ endif()
+else()
+ message(STATUS "Checking for -mtune=generic support")
+ CHECK_CXX_COMPILER_FLAG("-mtune=generic" MTUNEGENERIC)
+ if(MTUNEGENERIC)
+ message(STATUS "Checking for -mtune=generic support - works")
+ set(MARCH "-mtune=generic")
+ else()
+ message(WARNING "Do not know which -march/-mtune to pass! Resulting binaries may be broken!")
+ endif()
+endif()
+
+ADD_DEFINITIONS(${MARCH})
diff --git a/src/external/rawspeed/cmake/Modules/FindCppFilt.cmake b/src/external/rawspeed/cmake/Modules/FindCppFilt.cmake
new file mode 100644
index 000000000..02d90451d
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindCppFilt.cmake
@@ -0,0 +1,18 @@
+find_program(CPPFILT_EXECUTABLE
+ NAMES c++filt
+ DOC "The c++filt executable"
+ )
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(CppFilt
+ DEFAULT_MSG
+ CPPFILT_EXECUTABLE)
+
+add_executable(c++filt IMPORTED GLOBAL)
+set_property(TARGET c++filt PROPERTY IMPORTED_LOCATION "${CPPFILT_EXECUTABLE}")
+
+SET_PACKAGE_PROPERTIES(CppFilt PROPERTIES
+ URL https://sourceware.org/binutils/docs/binutils/c_002b_002bfilt.html
+ DESCRIPTION "Demangler for C++ symbols"
+ PURPOSE "Used for demangling of symbols in llvm-cov reports"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindDemangler.cmake b/src/external/rawspeed/cmake/Modules/FindDemangler.cmake
new file mode 100644
index 000000000..7612c460b
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindDemangler.cmake
@@ -0,0 +1,33 @@
+set(_demangler "NOTFOUND")
+
+function(findDemangler package target)
+ if(_demangler)
+ return()
+ endif()
+
+ find_package(${package})
+
+ if(NOT DEFINED ${package}_FOUND OR NOT ${package}_FOUND OR NOT TARGET ${target})
+ return()
+ endif()
+
+ set_package_properties(Demangler PROPERTIES
+ DESCRIPTION "Just an alias for ${package}")
+
+ get_property(_demangler TARGET ${target} PROPERTY IMPORTED_LOCATION)
+ set_package_properties(${package} PROPERTIES
+ TYPE REQUIRED)
+
+ set(_demangler "${_demangler}" PARENT_SCOPE)
+endfunction()
+
+findDemangler(LLVMCXXFilt llvm-cxxfilt)
+findDemangler(CppFilt c++filt)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Demangler
+ DEFAULT_MSG
+ _demangler)
+
+add_executable(demangler IMPORTED GLOBAL)
+set_property(TARGET demangler PROPERTY IMPORTED_LOCATION "${_demangler}")
diff --git a/src/external/rawspeed/cmake/Modules/FindFind.cmake b/src/external/rawspeed/cmake/Modules/FindFind.cmake
new file mode 100644
index 000000000..ad988c61e
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindFind.cmake
@@ -0,0 +1,12 @@
+find_program(FIND_PATH NAMES find)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Find
+ DEFAULT_MSG
+ FIND_PATH)
+
+SET_PACKAGE_PROPERTIES(Find PROPERTIES
+ URL https://www.gnu.org/software/findutils/
+ DESCRIPTION "Search for files in a directory hierarchy"
+ PURPOSE "Used to find specific files at cmake build execution time"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindGCCAr.cmake b/src/external/rawspeed/cmake/Modules/FindGCCAr.cmake
new file mode 100644
index 000000000..7ccae98ee
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindGCCAr.cmake
@@ -0,0 +1,12 @@
+find_program(GCCAR_EXECUTABLE NAMES gcc-ar)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GCCAr
+ DEFAULT_MSG
+ GCCAR_EXECUTABLE)
+
+SET_PACKAGE_PROPERTIES(GCCAr PROPERTIES
+ URL https://sourceware.org/binutils/docs/binutils/ar.html
+ DESCRIPTION "create, modify, and extract from archives"
+ PURPOSE "A wrapper around ar adding the --plugin option"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindGCCNm.cmake b/src/external/rawspeed/cmake/Modules/FindGCCNm.cmake
new file mode 100644
index 000000000..c373547d9
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindGCCNm.cmake
@@ -0,0 +1,12 @@
+find_program(GCCNM_EXECUTABLE NAMES gcc-nm)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GCCNm
+ DEFAULT_MSG
+ GCCNM_EXECUTABLE)
+
+SET_PACKAGE_PROPERTIES(GCCNm PROPERTIES
+ URL https://sourceware.org/binutils/docs/binutils/nm.html
+ DESCRIPTION "list GCC bitcode and object file’s symbol table"
+ PURPOSE "A wrapper around ar adding the --plugin option"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindGCCRanLib.cmake b/src/external/rawspeed/cmake/Modules/FindGCCRanLib.cmake
new file mode 100644
index 000000000..b13a88a6f
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindGCCRanLib.cmake
@@ -0,0 +1,12 @@
+find_program(GCCRANLIB_EXECUTABLE NAMES gcc-ranlib)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GCCRanLib
+ DEFAULT_MSG
+ GCCRANLIB_EXECUTABLE)
+
+SET_PACKAGE_PROPERTIES(GCCRanLib PROPERTIES
+ URL https://sourceware.org/binutils/docs/binutils/ranlib.html
+ DESCRIPTION "generate index for GCC archive"
+ PURPOSE "A wrapper around ar adding the --plugin option"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindGCov.cmake b/src/external/rawspeed/cmake/Modules/FindGCov.cmake
new file mode 100644
index 000000000..29c08be29
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindGCov.cmake
@@ -0,0 +1,16 @@
+if(DEFINED ENV{GCOV})
+ find_program(GCOV_PATH NAMES "$ENV{GCOV}")
+else()
+ find_program(GCOV_PATH NAMES gcov)
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GCov
+ DEFAULT_MSG
+ GCOV_PATH)
+
+SET_PACKAGE_PROPERTIES(GCov PROPERTIES
+ URL https://gcc.gnu.org/onlinedocs/gcc/Gcov.html
+ DESCRIPTION "Coverage testing tool"
+ PURPOSE "Used for preprocessing *.gcno files into *.gcov"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindGenHtml.cmake b/src/external/rawspeed/cmake/Modules/FindGenHtml.cmake
new file mode 100644
index 000000000..134ef0b7e
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindGenHtml.cmake
@@ -0,0 +1,12 @@
+find_program(GENHTML_PATH NAMES genhtml)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(GenHtml
+ DEFAULT_MSG
+ GENHTML_PATH)
+
+SET_PACKAGE_PROPERTIES(GenHtml PROPERTIES
+ URL http://ltp.sourceforge.net/coverage/lcov/genhtml.1.php
+ DESCRIPTION " Generates HTML view from LCOV coverage data files"
+ PURPOSE "Used for final rendering coverage reports into HTML"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLCov.cmake b/src/external/rawspeed/cmake/Modules/FindLCov.cmake
new file mode 100644
index 000000000..b3e04af55
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLCov.cmake
@@ -0,0 +1,12 @@
+find_program(LCOV_PATH NAMES lcov)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LCov
+ DEFAULT_MSG
+ LCOV_PATH)
+
+SET_PACKAGE_PROPERTIES(LCov PROPERTIES
+ URL http://ltp.sourceforge.net/coverage/lcov.php
+ DESCRIPTION "A graphical GCOV front-end"
+ PURPOSE "Used for collection of line coverage info"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLLVMAr.cmake b/src/external/rawspeed/cmake/Modules/FindLLVMAr.cmake
new file mode 100644
index 000000000..aca7db536
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLLVMAr.cmake
@@ -0,0 +1,11 @@
+find_program(LLVMAR_EXECUTABLE NAMES llvm-ar llvm-ar-6.0 llvm-ar-5.0 llvm-ar-4.0)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LLVMAr
+ DEFAULT_MSG
+ LLVMAR_EXECUTABLE)
+
+SET_PACKAGE_PROPERTIES(LLVMAr PROPERTIES
+ URL https://llvm.org/docs/CommandGuide/llvm-ar.html
+ DESCRIPTION "create, modify, and extract from archives"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLLVMCXXFilt.cmake b/src/external/rawspeed/cmake/Modules/FindLLVMCXXFilt.cmake
new file mode 100644
index 000000000..4cc093f09
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLLVMCXXFilt.cmake
@@ -0,0 +1,17 @@
+find_program(LLVMCXXFilt_EXECUTABLE
+ NAMES llvm-cxxfilt llvm-cxxfilt-6.0 llvm-cxxfilt-5.0 llvm-cxxfilt-4.0
+ DOC "The llvm-cxxfilt executable"
+ )
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LLVMCXXFilt
+ DEFAULT_MSG
+ LLVMCXXFilt_EXECUTABLE)
+
+add_executable(llvm-cxxfilt IMPORTED GLOBAL)
+set_property(TARGET llvm-cxxfilt PROPERTY IMPORTED_LOCATION "${LLVMCXXFilt_EXECUTABLE}")
+
+SET_PACKAGE_PROPERTIES(LLVMCXXFilt PROPERTIES
+ DESCRIPTION "LLVM demangler for C++ symbols"
+ PURPOSE "Used for demangling of symbols in llvm-cov reports"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLLVMClangTidy.cmake b/src/external/rawspeed/cmake/Modules/FindLLVMClangTidy.cmake
new file mode 100644
index 000000000..311226fc8
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLLVMClangTidy.cmake
@@ -0,0 +1,12 @@
+find_program(CLANGTIDY_PATH NAMES clang-tidy clang-tidy-5.0 clang-tidy-4.0)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LLVMClangTidy
+ DEFAULT_MSG
+ CLANGTIDY_PATH)
+
+SET_PACKAGE_PROPERTIES(LLVMClangTidy PROPERTIES
+ URL https://clang.llvm.org/extra/clang-tidy/
+ DESCRIPTION "a clang-based C++ “linter” tool"
+ PURPOSE "Used for enforcing some quality level for the source code"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLLVMCov.cmake b/src/external/rawspeed/cmake/Modules/FindLLVMCov.cmake
new file mode 100644
index 000000000..f8104959e
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLLVMCov.cmake
@@ -0,0 +1,12 @@
+find_program(LLVMCOV_PATH NAMES llvm-cov)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LLVMCov
+ DEFAULT_MSG
+ LLVMCOV_PATH)
+
+SET_PACKAGE_PROPERTIES(LLVMCov PROPERTIES
+ URL https://llvm.org/docs/CommandGuide/llvm-cov.html
+ DESCRIPTION "Tool to show code coverage information"
+ PURPOSE "Used for rendering *.profdata into HTML coverage report"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLLVMLLD.cmake b/src/external/rawspeed/cmake/Modules/FindLLVMLLD.cmake
new file mode 100644
index 000000000..6e8574dfd
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLLVMLLD.cmake
@@ -0,0 +1,23 @@
+find_program(LLVMLLD_EXECUTABLE NAMES ld.lld lld lld-6.0 lld-5.0)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LLVMLLD
+ DEFAULT_MSG
+ LLVMLLD_EXECUTABLE)
+
+SET_PACKAGE_PROPERTIES(LLVMLLD PROPERTIES
+ URL https://lld.llvm.org/
+ DESCRIPTION "the LLVM Linker"
+)
+
+set(LLVMLLD_INCREMENTAL_CACHE_PATH "${CMAKE_BINARY_DIR}/clang-thinlto-cache"
+ CACHE PATH "The location of clang's ThinLTO Incremental cache." FORCE)
+
+# For unoptimized {A+UB}SAN build with all debug info - fresh cache is ~492Mb.
+# For -O3 + {A+UB}SAN build with all debug info - fresh cache is ~320Mb.
+set(LLVMLLD_INCREMENTAL_CACHE_CACHE_SIZE_BYTES "1g"
+ CACHE STRING "The maximum size for the ThinLTO Incremental cache directory, X{,k,m,g} bytes" FORCE)
+
+set(LLVMLLD_INCREMENTAL_LDFLAGS
+ "-Wl,--thinlto-cache-dir=\"${LLVMLLD_INCREMENTAL_CACHE_PATH}\" -Wl,--thinlto-cache-policy,cache_size_bytes=${LLVMLLD_INCREMENTAL_CACHE_CACHE_SIZE_BYTES}"
+ CACHE STRING "(Clang only) Add -flto=thin flag to the compile and link command lines, enabling link-time optimization." FORCE)
diff --git a/src/external/rawspeed/cmake/Modules/FindLLVMNm.cmake b/src/external/rawspeed/cmake/Modules/FindLLVMNm.cmake
new file mode 100644
index 000000000..2872424e0
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLLVMNm.cmake
@@ -0,0 +1,11 @@
+find_program(LLVMNM_EXECUTABLE NAMES llvm-nm llvm-nm-6.0 llvm-nm-5.0 llvm-nm-4.0)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LLVMNm
+ DEFAULT_MSG
+ LLVMNM_EXECUTABLE)
+
+SET_PACKAGE_PROPERTIES(LLVMNm PROPERTIES
+ URL https://llvm.org/docs/CommandGuide/llvm-nm.html
+ DESCRIPTION "list LLVM bitcode and object file’s symbol table"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLLVMObjCopy.cmake b/src/external/rawspeed/cmake/Modules/FindLLVMObjCopy.cmake
new file mode 100644
index 000000000..1eab8fd4e
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLLVMObjCopy.cmake
@@ -0,0 +1,10 @@
+find_program(LLVMOBJCOPY_EXECUTABLE NAMES llvm-objcopy llvm-objcopy-6.0)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LLVMObjCopy
+ DEFAULT_MSG
+ LLVMOBJCOPY_EXECUTABLE)
+
+SET_PACKAGE_PROPERTIES(LLVMObjCopy PROPERTIES
+ DESCRIPTION "llvm objcopy utility"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLLVMObjDump.cmake b/src/external/rawspeed/cmake/Modules/FindLLVMObjDump.cmake
new file mode 100644
index 000000000..59abf7f25
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLLVMObjDump.cmake
@@ -0,0 +1,10 @@
+find_program(LLVMOBJDUMP_EXECUTABLE NAMES llvm-objdump llvm-objdump-6.0 llvm-objdump-5.0 llvm-objdump-4.0)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LLVMObjDump
+ DEFAULT_MSG
+ LLVMOBJDUMP_EXECUTABLE)
+
+SET_PACKAGE_PROPERTIES(LLVMObjDump PROPERTIES
+ DESCRIPTION "llvm object file dumper"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLLVMOptViewer.cmake b/src/external/rawspeed/cmake/Modules/FindLLVMOptViewer.cmake
new file mode 100644
index 000000000..cac92afe3
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLLVMOptViewer.cmake
@@ -0,0 +1,12 @@
+find_program(LLVMOPTVIEWER_PATH NAMES opt-viewer.py)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LLVMOptViewer
+ DEFAULT_MSG
+ LLVMOPTVIEWER_PATH)
+
+SET_PACKAGE_PROPERTIES(LLVMOptViewer PROPERTIES
+ URL https://llvm.org/
+ DESCRIPTION "Tool to visualize optimization records"
+ PURPOSE "Used for rendering *.opt.yaml optimization records into HTML report"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLLVMProfData.cmake b/src/external/rawspeed/cmake/Modules/FindLLVMProfData.cmake
new file mode 100644
index 000000000..72ca5a861
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLLVMProfData.cmake
@@ -0,0 +1,12 @@
+find_program(LLVMPROFDATA_PATH NAMES llvm-profdata)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LLVMProfData
+ DEFAULT_MSG
+ LLVMPROFDATA_PATH)
+
+SET_PACKAGE_PROPERTIES(LLVMProfData PROPERTIES
+ URL https://llvm.org/docs/CommandGuide/llvm-profdata.html
+ DESCRIPTION "Profile data tool"
+ PURPOSE "Used for preprocessing *.profraw files into *.profdata"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLLVMRanLib.cmake b/src/external/rawspeed/cmake/Modules/FindLLVMRanLib.cmake
new file mode 100644
index 000000000..5db031194
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLLVMRanLib.cmake
@@ -0,0 +1,10 @@
+find_program(LLVMRANLIB_EXECUTABLE NAMES llvm-ranlib llvm-ranlib-6.0 llvm-ranlib-5.0 llvm-ranlib-4.0)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(LLVMRanLib
+ DEFAULT_MSG
+ LLVMRANLIB_EXECUTABLE)
+
+SET_PACKAGE_PROPERTIES(LLVMRanLib PROPERTIES
+ DESCRIPTION "generate index for LLVM archive"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindLibFuzzingEngine.cmake b/src/external/rawspeed/cmake/Modules/FindLibFuzzingEngine.cmake
new file mode 100644
index 000000000..b9a9ba393
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindLibFuzzingEngine.cmake
@@ -0,0 +1,28 @@
+# - Try to find LibFuzzingEngine
+# Once done, this will define
+#
+# LibFuzzingEngine_FOUND - system has LibFuzzingEngine
+# LibFuzzingEngine_LIBRARIES - link these to use LibFuzzingEngine
+
+include(LibFindMacros)
+
+if(EXISTS "${LIB_FUZZING_ENGINE}")
+ set(LibFuzzingEngine_LIBRARY "${LIB_FUZZING_ENGINE}")
+else()
+ set(LibFuzzingEngine_LIBRARY "LibFuzzingEngine_LIBRARY-NOTFOUND")
+endif()
+
+# Set the include dir variables and the libraries and let libfind_process do the rest.
+# NOTE: Singular variables for this library, plural for libraries this this lib depends on.
+set(LibFuzzingEngine_PROCESS_LIBS LibFuzzingEngine_LIBRARY)
+libfind_process(LibFuzzingEngine)
+
+if(LibFuzzingEngine_FOUND)
+ add_library(LibFuzzingEngine INTERFACE IMPORTED)
+ set_property(TARGET LibFuzzingEngine PROPERTY INTERFACE_LINK_LIBRARIES "${LibFuzzingEngine_LIBRARIES}")
+endif()
+
+set_package_properties(LibFuzzingEngine PROPERTIES
+ TYPE REQUIRED
+ DESCRIPTION "A prebuilt fuzzing engine library (e.g. libFuzzer) that needs to be linked with all fuzz target"
+ PURPOSE "Used to actually drive the fuzz targets")
diff --git a/src/external/rawspeed/cmake/Modules/FindPugixml.cmake b/src/external/rawspeed/cmake/Modules/FindPugixml.cmake
new file mode 100644
index 000000000..012a89c18
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindPugixml.cmake
@@ -0,0 +1,30 @@
+# - Try to find Pugixml
+# Once done, this will define
+#
+# Pugixml_FOUND - system has Pugixml
+# Pugixml_INCLUDE_DIRS - the Pugixml include directories
+# Pugixml_LIBRARIES - link these to use Pugixml
+
+include(LibFindMacros)
+
+libfind_pkg_detect(Pugixml pugixml
+ FIND_PATH pugixml.hpp
+ FIND_LIBRARY pugixml
+)
+
+if (Pugixml_PKGCONF_VERSION)
+ set(Pugixml_VERSION "${Pugixml_PKGCONF_VERSION}")
+elseif(Pugixml_INCLUDE_DIR)
+ # no .pc file, look for version manually.
+ # yes, libfind_version_header() does not work here.
+
+ file(READ "${Pugixml_INCLUDE_DIR}/pugixml.hpp" Pugixml_VERSION_CONTENT)
+ string(REGEX MATCH "PUGIXML_VERSION *([0-9])([0-9][0-9])" _dummy "${Pugixml_VERSION_CONTENT}")
+ set(Pugixml_VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}")
+endif()
+
+# Set the include dir variables and the libraries and let libfind_process do the rest.
+# NOTE: Singular variables for this library, plural for libraries this this lib depends on.
+set(Pugixml_PROCESS_INCLUDES Pugixml_INCLUDE_DIR)
+set(Pugixml_PROCESS_LIBS Pugixml_LIBRARY)
+libfind_process(Pugixml)
diff --git a/src/external/rawspeed/cmake/Modules/FindSphinx.cmake b/src/external/rawspeed/cmake/Modules/FindSphinx.cmake
new file mode 100644
index 000000000..f2e028860
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindSphinx.cmake
@@ -0,0 +1,12 @@
+find_program(SPHINX_BUILD_PATH NAMES sphinx-build)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Sphinx
+ DEFAULT_MSG
+ SPHINX_BUILD_PATH)
+
+SET_PACKAGE_PROPERTIES(Sphinx PROPERTIES
+ URL http://www.sphinx-doc.org/
+ DESCRIPTION "Documentation generator"
+ PURPOSE "Used for generating the textual documentation, used on web-site"
+)
diff --git a/src/external/rawspeed/cmake/Modules/FindXMLLINT.cmake b/src/external/rawspeed/cmake/Modules/FindXMLLINT.cmake
new file mode 100644
index 000000000..dbb34bdd8
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/FindXMLLINT.cmake
@@ -0,0 +1,17 @@
+find_program(XMLLINT_EXECUTABLE
+ NAMES xmllint
+ DOC "The xmllint executable")
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(XMLLINT
+ DEFAULT_MSG
+ XMLLINT_EXECUTABLE)
+
+add_executable(xmllint IMPORTED GLOBAL)
+set_property(TARGET xmllint PROPERTY IMPORTED_LOCATION "${XMLLINT_EXECUTABLE}")
+
+SET_PACKAGE_PROPERTIES(XMLLINT PROPERTIES
+ URL http://xmlsoft.org/
+ DESCRIPTION "command line XML tool"
+ PURPOSE "Used for validation of data/cameras.xml"
+)
diff --git a/src/external/rawspeed/cmake/Modules/GTEST_ADD_TESTS.cmake b/src/external/rawspeed/cmake/Modules/GTEST_ADD_TESTS.cmake
new file mode 100644
index 000000000..5e06659d2
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/GTEST_ADD_TESTS.cmake
@@ -0,0 +1,70 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#.rst:
+# FindGTest
+# ---------
+#
+# Locate the Google C++ Testing Framework.
+#
+# Deeper integration with CTest
+# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+#
+# If you would like each Google test to show up in CTest as a test you
+# may use the following macro::
+#
+# GTEST_ADD_TESTS(executable extra_args files...)
+#
+# ``executable``
+# the path to the test executable
+# ``extra_args``
+# a list of extra arguments to be passed to executable enclosed in
+# quotes (or ``""`` for none)
+# ``files...``
+# a list of source files to search for tests and test fixtures. Or
+# ``AUTO`` to find them from executable target
+#
+# However, note that this macro will slow down your tests by running
+# an executable for each test and test fixture.
+#
+# Example usage::
+#
+# set(FooTestArgs --foo 1 --bar 2)
+# add_executable(FooTest FooUnitTest.cc)
+# GTEST_ADD_TESTS(FooTest "${FooTestArgs}" AUTO)
+
+#
+# Thanks to Daniel Blezek <blezek@gmail.com> for the GTEST_ADD_TESTS code
+
+function(GTEST_ADD_TESTS executable extra_args)
+ if(NOT ARGN)
+ message(FATAL_ERROR "Missing ARGN: Read the documentation for GTEST_ADD_TESTS")
+ endif()
+ if(ARGN STREQUAL "AUTO")
+ # obtain sources used for building that executable
+ get_property(ARGN TARGET ${executable} PROPERTY SOURCES)
+ endif()
+ set(gtest_case_name_regex ".*\\( *([A-Za-z_0-9]+) *, *([A-Za-z_0-9]+) *\\).*")
+ set(gtest_test_type_regex "(TYPED_TEST|TEST_?[FP]?)")
+ foreach(source ${ARGN})
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${source})
+ file(READ "${source}" contents)
+ string(REGEX MATCHALL "${gtest_test_type_regex} *\\(([A-Za-z_0-9 ,]+)\\)" found_tests ${contents})
+ foreach(hit ${found_tests})
+ string(REGEX MATCH "${gtest_test_type_regex}" test_type ${hit})
+
+ # Parameterized tests have a different signature for the filter
+ if("x${test_type}" STREQUAL "xTEST_P")
+ string(REGEX REPLACE ${gtest_case_name_regex} "*/\\1.\\2/*" test_name ${hit})
+ elseif("x${test_type}" STREQUAL "xTEST_F" OR "x${test_type}" STREQUAL "xTEST")
+ string(REGEX REPLACE ${gtest_case_name_regex} "\\1.\\2" test_name ${hit})
+ elseif("x${test_type}" STREQUAL "xTYPED_TEST")
+ string(REGEX REPLACE ${gtest_case_name_regex} "\\1/*.\\2" test_name ${hit})
+ else()
+ message(WARNING "Could not parse GTest ${hit} for adding to CTest.")
+ continue()
+ endif()
+ add_test(NAME ${test_name} COMMAND ${executable} --gtest_filter=${test_name} ${extra_args})
+ endforeach()
+ endforeach()
+endfunction()
diff --git a/src/external/rawspeed/cmake/Modules/GoogleBenchmark.cmake b/src/external/rawspeed/cmake/Modules/GoogleBenchmark.cmake
new file mode 100644
index 000000000..15d4d004e
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/GoogleBenchmark.cmake
@@ -0,0 +1,58 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(googlebenchmark NONE)
+
+# Download and unpack googlebenchmark at configure time
+configure_file(${RAWSPEED_SOURCE_DIR}/cmake/Modules/GoogleBenchmark.cmake.in ${CMAKE_BINARY_DIR}/googlebenchmark/CMakeLists.txt @ONLY)
+
+execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"
+ -DALLOW_DOWNLOADING_GOOGLEBENCHMARK=${ALLOW_DOWNLOADING_GOOGLEBENCHMARK} -DGOOGLEBENCHMARK_PATH:PATH=${GOOGLEBENCHMARK_PATH} .
+ RESULT_VARIABLE result
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googlebenchmark
+)
+
+if(result)
+ message(FATAL_ERROR "CMake step for googlebenchmark failed: ${result}")
+endif()
+
+execute_process(
+ COMMAND ${CMAKE_COMMAND} --build .
+ RESULT_VARIABLE result
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googlebenchmark
+)
+
+if(result)
+ message(FATAL_ERROR "Build step for googlebenchmark failed: ${result}")
+endif()
+
+# shared googlebenchmark exibits varous spririous failures.
+# let's insist on static library.
+set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
+
+# not interested
+set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
+
+set(CMAKE_C_FLAGS_SAVE "${CMAKE_C_FLAGS}")
+set(CMAKE_CXX_FLAGS_SAVE "${CMAKE_CXX_FLAGS}")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
+
+set(CMAKE_CXX_CLANG_TIDY_SAVE "${CMAKE_CXX_CLANG_TIDY}")
+set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE_SAVE "${CMAKE_CXX_INCLUDE_WHAT_YOU_USE}")
+
+unset(CMAKE_CXX_CLANG_TIDY)
+unset(CMAKE_CXX_INCLUDE_WHAT_YOU_USE)
+
+# Add googlebenchmark directly to our build. This defines the benchmark target.
+add_subdirectory(${CMAKE_BINARY_DIR}/googlebenchmark/googlebenchmark-src
+ ${CMAKE_BINARY_DIR}/googlebenchmark/googlebenchmark-build
+ EXCLUDE_FROM_ALL)
+
+set_target_properties(benchmark PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:benchmark,INTERFACE_INCLUDE_DIRECTORIES>)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_SAVE}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_SAVE}")
+
+set(CMAKE_CXX_CLANG_TIDY "${CMAKE_CXX_CLANG_TIDY_SAVE}")
+set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${CMAKE_CXX_INCLUDE_WHAT_YOU_USE_SAVE}")
diff --git a/src/external/rawspeed/cmake/Modules/GoogleBenchmark.cmake.in b/src/external/rawspeed/cmake/Modules/GoogleBenchmark.cmake.in
new file mode 100644
index 000000000..ee18edc2c
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/GoogleBenchmark.cmake.in
@@ -0,0 +1,49 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(googlebenchmark-download NONE)
+
+# Enable ExternalProject CMake module
+include(ExternalProject)
+
+option(ALLOW_DOWNLOADING_GOOGLEBENCHMARK "If GOOGLEBENCHMARK src tree is not found in location specified by GOOGLEBENCHMARK_PATH, do fetch the archive from internet" OFF)
+set(GOOGLEBENCHMARK_PATH "/usr/src/googlebenchmark" CACHE PATH "Path to the googlebenchmark root tree.")
+
+# Download and install GOOGLEBENCHMARK
+
+message(STATUS "Looking for GOOGLEBENCHMARK sources")
+message(STATUS "Looking for GOOGLEBENCHMARK sources in ${GOOGLEBENCHMARK_PATH}")
+if(EXISTS "${GOOGLEBENCHMARK_PATH}" AND IS_DIRECTORY "${GOOGLEBENCHMARK_PATH}" AND EXISTS "${GOOGLEBENCHMARK_PATH}/CMakeLists.txt")
+ message(STATUS "Found GOOGLEBENCHMARK in ${GOOGLEBENCHMARK_PATH}")
+
+ ExternalProject_Add(
+ googlebenchmark
+ URL "${GOOGLEBENCHMARK_PATH}"
+ PREFIX "${CMAKE_BINARY_DIR}/googlebenchmark"
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/googlebenchmark-src"
+ BINARY_DIR "${CMAKE_BINARY_DIR}/googlebenchmark-build"
+ # PATCH_COMMAND patch -p1 -i "@rawspeed_SOURCE_DIR@/cmake/Modules/GoogleBenchmark-fixes.patch"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+else()
+ if(NOT ALLOW_DOWNLOADING_GOOGLEBENCHMARK)
+ message(SEND_ERROR "Did not find GOOGLEBENCHMARK sources! Either pass correct path in GOOGLEBENCHMARK_PATH, or enable ALLOW_DOWNLOADING_GOOGLEBENCHMARK, or disable BUILD_BENCHMARKING.")
+ else()
+ message(WARNING "Did not find GOOGLEBENCHMARK sources! Fetching from web...")
+ ExternalProject_Add(
+ googlebenchmark
+ URL https://github.com/google/benchmark/archive/v1.3.0.tar.gz
+ URL_HASH SHA512=272775e4dbd0ecc65a2a3a64f24e79682b630929dea3af47349329ac8b796341f1197458a67c9aac0e514857ebe7cbc191d18f6fd2c0aea3242562e69d8a6849
+ PREFIX "${CMAKE_BINARY_DIR}/googlebenchmark"
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/googlebenchmark-src"
+ BINARY_DIR "${CMAKE_BINARY_DIR}/googlebenchmark-build"
+ # PATCH_COMMAND patch -p1 -i "@rawspeed_SOURCE_DIR@/cmake/Modules/GoogleBenchmark-fixes.patch"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+ endif()
+endif()
diff --git a/src/external/rawspeed/cmake/Modules/GoogleTest.cmake b/src/external/rawspeed/cmake/Modules/GoogleTest.cmake
new file mode 100644
index 000000000..2676db6e9
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/GoogleTest.cmake
@@ -0,0 +1,67 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(googletest NONE)
+
+# Download and unpack googletest at configure time
+configure_file(${RAWSPEED_SOURCE_DIR}/cmake/Modules/GoogleTest.cmake.in ${CMAKE_BINARY_DIR}/googletest/CMakeLists.txt @ONLY)
+
+execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"
+ -DALLOW_DOWNLOADING_GOOGLETEST=${ALLOW_DOWNLOADING_GOOGLETEST} -DGOOGLETEST_PATH:PATH=${GOOGLETEST_PATH} .
+ RESULT_VARIABLE result
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest
+)
+
+if(result)
+ message(FATAL_ERROR "CMake step for googletest failed: ${result}")
+endif()
+
+execute_process(
+ COMMAND ${CMAKE_COMMAND} --build .
+ RESULT_VARIABLE result
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest
+)
+
+if(result)
+ message(FATAL_ERROR "Build step for googletest failed: ${result}")
+endif()
+
+# shared googletest exibits varous spririous failures.
+# let's insist on static library.
+set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
+
+# Prevent overriding the parent project's compiler/linker
+# settings on Windows
+set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
+
+if(NOT (UNIX OR APPLE))
+ set(gtest_disable_pthreads ON CACHE BOOL "" FORCE)
+endif()
+
+set(CMAKE_C_FLAGS_SAVE "${CMAKE_C_FLAGS}")
+set(CMAKE_CXX_FLAGS_SAVE "${CMAKE_CXX_FLAGS}")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
+
+set(CMAKE_CXX_CLANG_TIDY_SAVE "${CMAKE_CXX_CLANG_TIDY}")
+set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE_SAVE "${CMAKE_CXX_INCLUDE_WHAT_YOU_USE}")
+
+unset(CMAKE_CXX_CLANG_TIDY)
+unset(CMAKE_CXX_INCLUDE_WHAT_YOU_USE)
+
+# Add googletest directly to our build. This defines
+# the gtest and gtest_main targets.
+add_subdirectory(${CMAKE_BINARY_DIR}/googletest/googletest-src
+ ${CMAKE_BINARY_DIR}/googletest/googletest-build
+ EXCLUDE_FROM_ALL)
+
+set_target_properties(gtest PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:gtest,INTERFACE_INCLUDE_DIRECTORIES>)
+set_target_properties(gtest_main PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:gtest_main,INTERFACE_INCLUDE_DIRECTORIES>)
+set_target_properties(gmock PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:gmock,INTERFACE_INCLUDE_DIRECTORIES>)
+set_target_properties(gmock_main PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:gmock_main,INTERFACE_INCLUDE_DIRECTORIES>)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_SAVE}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_SAVE}")
+
+set(CMAKE_CXX_CLANG_TIDY "${CMAKE_CXX_CLANG_TIDY_SAVE}")
+set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${CMAKE_CXX_INCLUDE_WHAT_YOU_USE_SAVE}")
diff --git a/src/external/rawspeed/cmake/Modules/GoogleTest.cmake.in b/src/external/rawspeed/cmake/Modules/GoogleTest.cmake.in
new file mode 100644
index 000000000..ca876c4e9
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/GoogleTest.cmake.in
@@ -0,0 +1,50 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(googletest-download NONE)
+
+# Enable ExternalProject CMake module
+include(ExternalProject)
+
+option(ALLOW_DOWNLOADING_GOOGLETEST "If googletest src tree is not found in location specified by GOOGLETEST_PATH, do fetch the archive from internet" OFF)
+set(GOOGLETEST_PATH "/usr/src/googletest" CACHE PATH
+ "Path to the googletest root tree. Should contain googletest and googlemock subdirs. And CMakeLists.txt in root, and in both of these subdirs")
+
+# Download and install GoogleTest
+
+message(STATUS "Looking for Google Test sources")
+message(STATUS "Looking for Google Test sources in ${GOOGLETEST_PATH}")
+if(EXISTS "${GOOGLETEST_PATH}" AND IS_DIRECTORY "${GOOGLETEST_PATH}" AND EXISTS "${GOOGLETEST_PATH}/CMakeLists.txt" AND
+ EXISTS "${GOOGLETEST_PATH}/googletest" AND IS_DIRECTORY "${GOOGLETEST_PATH}/googletest" AND EXISTS "${GOOGLETEST_PATH}/googletest/CMakeLists.txt" AND
+ EXISTS "${GOOGLETEST_PATH}/googlemock" AND IS_DIRECTORY "${GOOGLETEST_PATH}/googlemock" AND EXISTS "${GOOGLETEST_PATH}/googlemock/CMakeLists.txt")
+ message(STATUS "Found Google Test in ${GOOGLETEST_PATH}")
+
+ ExternalProject_Add(
+ googletest
+ URL "${GOOGLETEST_PATH}"
+ PREFIX "${CMAKE_BINARY_DIR}/googletest"
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
+ BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+else()
+ if(NOT ALLOW_DOWNLOADING_GOOGLETEST)
+ message(SEND_ERROR "Did not find Google Test sources! Either pass correct path in GOOGLETEST_PATH, or enable ALLOW_DOWNLOADING_GOOGLETEST, or disable BUILD_TESTING.")
+ else()
+ message(WARNING "Did not find Google Test sources! Fetching from web...")
+ ExternalProject_Add(
+ googletest
+ URL https://github.com/google/googletest/archive/release-1.8.0.tar.gz
+ URL_HASH SHA512=1dbece324473e53a83a60601b02c92c089f5d314761351974e097b2cf4d24af4296f9eb8653b6b03b1e363d9c5f793897acae1f0c7ac40149216035c4d395d9d
+ PREFIX "${CMAKE_BINARY_DIR}/googletest"
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
+ BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+ endif()
+endif()
diff --git a/src/external/rawspeed/cmake/Modules/LibFindMacros.cmake b/src/external/rawspeed/cmake/Modules/LibFindMacros.cmake
new file mode 100644
index 000000000..3ef5844dd
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/LibFindMacros.cmake
@@ -0,0 +1,266 @@
+# Version 2.2
+# Public Domain, originally written by Lasse Kärkkäinen <tronic>
+# Maintained at https://github.com/Tronic/cmake-modules
+# Please send your improvements as pull requests on Github.
+
+# Find another package and make it a dependency of the current package.
+# This also automatically forwards the "REQUIRED" argument.
+# Usage: libfind_package(<prefix> <another package> [extra args to find_package])
+macro (libfind_package PREFIX PKG)
+ set(${PREFIX}_args ${PKG} ${ARGN})
+ if (${PREFIX}_FIND_REQUIRED)
+ set(${PREFIX}_args ${${PREFIX}_args} REQUIRED)
+ endif()
+ find_package(${${PREFIX}_args})
+ set(${PREFIX}_DEPENDENCIES ${${PREFIX}_DEPENDENCIES};${PKG})
+ unset(${PREFIX}_args)
+endmacro()
+
+# A simple wrapper to make pkg-config searches a bit easier.
+# Works the same as CMake's internal pkg_check_modules but is always quiet.
+macro (libfind_pkg_check_modules)
+ find_package(PkgConfig QUIET)
+ if (PKG_CONFIG_FOUND)
+ pkg_check_modules(${ARGN} QUIET)
+ endif()
+endmacro()
+
+# Avoid useless copy&pasta by doing what most simple libraries do anyway:
+# pkg-config, find headers, find library.
+# Usage: libfind_pkg_detect(<prefix> <pkg-config args> FIND_PATH <name> [other args] FIND_LIBRARY <name> [other args])
+# E.g. libfind_pkg_detect(SDL2 sdl2 FIND_PATH SDL.h PATH_SUFFIXES SDL2 FIND_LIBRARY SDL2)
+function (libfind_pkg_detect PREFIX)
+ # Parse arguments
+ set(argname pkgargs)
+ foreach (i ${ARGN})
+ if ("${i}" STREQUAL "FIND_PATH")
+ set(argname pathargs)
+ elseif ("${i}" STREQUAL "FIND_LIBRARY")
+ set(argname libraryargs)
+ else()
+ set(${argname} ${${argname}} ${i})
+ endif()
+ endforeach()
+ if (NOT pkgargs)
+ message(FATAL_ERROR "libfind_pkg_detect requires at least a pkg_config package name to be passed.")
+ endif()
+ # Find library
+ libfind_pkg_check_modules(${PREFIX}_PKGCONF ${pkgargs})
+ if (pathargs)
+ find_path(${PREFIX}_INCLUDE_DIR NAMES ${pathargs} HINTS ${${PREFIX}_PKGCONF_INCLUDE_DIRS})
+ endif()
+ if (libraryargs)
+ find_library(${PREFIX}_LIBRARY NAMES ${libraryargs} HINTS ${${PREFIX}_PKGCONF_LIBRARY_DIRS})
+ endif()
+endfunction()
+
+# Extracts a version #define from a version.h file, output stored to <PREFIX>_VERSION.
+# Usage: libfind_version_header(Foobar foobar/version.h FOOBAR_VERSION_STR)
+# Fourth argument "QUIET" may be used for silently testing different define names.
+# This function does nothing if the version variable is already defined.
+function (libfind_version_header PREFIX VERSION_H DEFINE_NAME)
+ # Skip processing if we already have a version or if the include dir was not found
+ if (${PREFIX}_VERSION OR NOT ${PREFIX}_INCLUDE_DIR)
+ return()
+ endif()
+ set(quiet ${${PREFIX}_FIND_QUIETLY})
+ # Process optional arguments
+ foreach(arg ${ARGN})
+ if (arg STREQUAL "QUIET")
+ set(quiet TRUE)
+ else()
+ message(AUTHOR_WARNING "Unknown argument ${arg} to libfind_version_header ignored.")
+ endif()
+ endforeach()
+ # Read the header and parse for version number
+ set(filename "${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+ if (NOT EXISTS ${filename})
+ if (NOT quiet)
+ message(AUTHOR_WARNING "Unable to find ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+ endif()
+ return()
+ endif()
+ file(READ "${filename}" header)
+ string(REGEX REPLACE ".*#[ \t]*define[ \t]*${DEFINE_NAME}[ \t]*\"([^\n]*)\".*" "\\1" match "${header}")
+ # No regex match?
+ if (match STREQUAL header)
+ if (NOT quiet)
+ message(AUTHOR_WARNING "Unable to find \#define ${DEFINE_NAME} \"<version>\" from ${${PREFIX}_INCLUDE_DIR}/${VERSION_H}")
+ endif()
+ return()
+ endif()
+ # Export the version string
+ set(${PREFIX}_VERSION "${match}" PARENT_SCOPE)
+endfunction()
+
+# Do the final processing once the paths have been detected.
+# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
+# all the variables, each of which contain one include directory.
+# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
+# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
+# Also handles errors in case library detection was required, etc.
+function (libfind_process PREFIX)
+ # Skip processing if already processed during this configuration run
+ if (${PREFIX}_FOUND)
+ return()
+ endif()
+
+ set(found TRUE) # Start with the assumption that the package was found
+
+ # Did we find any files? Did we miss includes? These are for formatting better error messages.
+ set(some_files FALSE)
+ set(missing_headers FALSE)
+
+ # Shorthands for some variables that we need often
+ set(quiet ${${PREFIX}_FIND_QUIETLY})
+ set(required ${${PREFIX}_FIND_REQUIRED})
+ set(exactver ${${PREFIX}_FIND_VERSION_EXACT})
+ set(findver "${${PREFIX}_FIND_VERSION}")
+ set(version "${${PREFIX}_VERSION}")
+
+ # Lists of config option names (all, includes, libs)
+ unset(configopts)
+ set(includeopts ${${PREFIX}_PROCESS_INCLUDES})
+ set(libraryopts ${${PREFIX}_PROCESS_LIBS})
+
+ # Process deps to add to
+ foreach (i ${PREFIX} ${${PREFIX}_DEPENDENCIES})
+ if (DEFINED ${i}_INCLUDE_OPTS OR DEFINED ${i}_LIBRARY_OPTS)
+ # The package seems to export option lists that we can use, woohoo!
+ list(APPEND includeopts ${${i}_INCLUDE_OPTS})
+ list(APPEND libraryopts ${${i}_LIBRARY_OPTS})
+ else()
+ # If plural forms don't exist or they equal singular forms
+ if ((NOT DEFINED ${i}_INCLUDE_DIRS AND NOT DEFINED ${i}_LIBRARIES) OR
+ ({i}_INCLUDE_DIR STREQUAL ${i}_INCLUDE_DIRS AND ${i}_LIBRARY STREQUAL ${i}_LIBRARIES))
+ # Singular forms can be used
+ if (DEFINED ${i}_INCLUDE_DIR)
+ list(APPEND includeopts ${i}_INCLUDE_DIR)
+ endif()
+ if (DEFINED ${i}_LIBRARY)
+ list(APPEND libraryopts ${i}_LIBRARY)
+ endif()
+ else()
+ # Oh no, we don't know the option names
+ message(FATAL_ERROR "We couldn't determine config variable names for ${i} includes and libs. Aieeh!")
+ endif()
+ endif()
+ endforeach()
+
+ if (includeopts)
+ list(REMOVE_DUPLICATES includeopts)
+ endif()
+
+ if (libraryopts)
+ list(REMOVE_DUPLICATES libraryopts)
+ endif()
+
+ string(REGEX REPLACE ".*[ ;]([^ ;]*(_INCLUDE_DIRS|_LIBRARIES))" "\\1" tmp "${includeopts} ${libraryopts}")
+ if (NOT tmp STREQUAL "${includeopts} ${libraryopts}")
+ message(AUTHOR_WARNING "Plural form ${tmp} found in config options of ${PREFIX}. This works as before but is now deprecated. Please only use singular forms INCLUDE_DIR and LIBRARY, and update your find scripts for LibFindMacros > 2.0 automatic dependency system (most often you can simply remove the PROCESS variables entirely).")
+ endif()
+
+ # Include/library names separated by spaces (notice: not CMake lists)
+ unset(includes)
+ unset(libs)
+
+ # Process all includes and set found false if any are missing
+ foreach (i ${includeopts})
+ list(APPEND configopts ${i})
+ if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
+ list(APPEND includes "${${i}}")
+ else()
+ set(found FALSE)
+ set(missing_headers TRUE)
+ endif()
+ endforeach()
+
+ # Process all libraries and set found false if any are missing
+ foreach (i ${libraryopts})
+ list(APPEND configopts ${i})
+ if (NOT "${${i}}" STREQUAL "${i}-NOTFOUND")
+ list(APPEND libs "${${i}}")
+ else()
+ set (found FALSE)
+ endif()
+ endforeach()
+
+ # Version checks
+ if (found AND findver)
+ if (NOT version)
+ message(WARNING "The find module for ${PREFIX} does not provide version information, so we'll just assume that it is OK. Please fix the module or remove package version requirements to get rid of this warning.")
+ elseif (version VERSION_LESS findver OR (exactver AND NOT version VERSION_EQUAL findver))
+ set(found FALSE)
+ set(version_unsuitable TRUE)
+ endif()
+ endif()
+
+ # If all-OK, hide all config options, export variables, print status and exit
+ if (found)
+ foreach (i ${configopts})
+ mark_as_advanced(${i})
+ endforeach()
+ if (NOT quiet)
+ message(STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
+ if (LIBFIND_DEBUG)
+ message(STATUS " ${PREFIX}_DEPENDENCIES=${${PREFIX}_DEPENDENCIES}")
+ message(STATUS " ${PREFIX}_INCLUDE_OPTS=${includeopts}")
+ message(STATUS " ${PREFIX}_INCLUDE_DIRS=${includes}")
+ message(STATUS " ${PREFIX}_LIBRARY_OPTS=${libraryopts}")
+ message(STATUS " ${PREFIX}_LIBRARIES=${libs}")
+ endif()
+ set (${PREFIX}_INCLUDE_OPTS ${includeopts} PARENT_SCOPE)
+ set (${PREFIX}_LIBRARY_OPTS ${libraryopts} PARENT_SCOPE)
+ set (${PREFIX}_INCLUDE_DIRS ${includes} PARENT_SCOPE)
+ set (${PREFIX}_LIBRARIES ${libs} PARENT_SCOPE)
+ set (${PREFIX}_FOUND TRUE PARENT_SCOPE)
+ endif()
+ return()
+ endif()
+
+ # Format messages for debug info and the type of error
+ set(vars "Relevant CMake configuration variables:\n")
+ foreach (i ${configopts})
+ mark_as_advanced(CLEAR ${i})
+ set(val ${${i}})
+ if ("${val}" STREQUAL "${i}-NOTFOUND")
+ set (val "<not found>")
+ elseif (val AND NOT EXISTS ${val})
+ set (val "${val} (does not exist)")
+ else()
+ set(some_files TRUE)
+ endif()
+ set(vars "${vars} ${i}=${val}\n")
+ endforeach()
+ set(vars "${vars}You may use CMake GUI, cmake -D or ccmake to modify the values. Delete CMakeCache.txt to discard all values and force full re-detection if necessary.\n")
+ if (version_unsuitable)
+ set(msg "${PREFIX} ${${PREFIX}_VERSION} was found but")
+ if (exactver)
+ set(msg "${msg} only version ${findver} is acceptable.")
+ else()
+ set(msg "${msg} version ${findver} is the minimum requirement.")
+ endif()
+ else()
+ if (missing_headers)
+ set(msg "We could not find development headers for ${PREFIX}. Do you have the necessary dev package installed?")
+ elseif (some_files)
+ set(msg "We only found some files of ${PREFIX}, not all of them. Perhaps your installation is incomplete or maybe we just didn't look in the right place?")
+ if(findver)
+ set(msg "${msg} This could also be caused by incompatible version (if it helps, at least ${PREFIX} ${findver} should work).")
+ endif()
+ else()
+ set(msg "We were unable to find package ${PREFIX}.")
+ endif()
+ endif()
+
+ # Fatal error out if REQUIRED
+ if (required)
+ set(msg "REQUIRED PACKAGE NOT FOUND\n${msg} This package is REQUIRED and you need to install it or adjust CMake configuration in order to continue building ${CMAKE_PROJECT_NAME}.")
+ message(FATAL_ERROR "${msg}\n${vars}")
+ endif()
+ # Otherwise just print a nasty warning
+ if (NOT quiet)
+ message(WARNING "WARNING: MISSING PACKAGE\n${msg} This package is NOT REQUIRED and you may ignore this warning but by doing so you may miss some functionality of ${CMAKE_PROJECT_NAME}. \n${vars}")
+ endif()
+endfunction()
+
diff --git a/src/external/rawspeed/cmake/Modules/Pugixml.cmake b/src/external/rawspeed/cmake/Modules/Pugixml.cmake
new file mode 100644
index 000000000..752ceb7d6
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/Pugixml.cmake
@@ -0,0 +1,60 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(pugixml NONE)
+
+# Download and unpack pugixml at configure time
+configure_file(${RAWSPEED_SOURCE_DIR}/cmake/Modules/Pugixml.cmake.in ${CMAKE_BINARY_DIR}/pugixml/CMakeLists.txt @ONLY)
+
+execute_process(
+ COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"
+ -DALLOW_DOWNLOADING_PUGIXML=${ALLOW_DOWNLOADING_PUGIXML} -DPUGIXML_PATH:PATH=${PUGIXML_PATH} .
+ RESULT_VARIABLE result
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/pugixml
+)
+
+if(result)
+ message(FATAL_ERROR "CMake step for pugixml failed: ${result}")
+endif()
+
+execute_process(
+ COMMAND ${CMAKE_COMMAND} --build .
+ RESULT_VARIABLE result
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/pugixml
+)
+
+if(result)
+ message(FATAL_ERROR "Build step for pugixml failed: ${result}")
+endif()
+
+set(Pugixml_FOUND 1)
+
+# want static pugixml?
+set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
+
+set(CMAKE_C_FLAGS_SAVE "${CMAKE_C_FLAGS}")
+set(CMAKE_CXX_FLAGS_SAVE "${CMAKE_CXX_FLAGS}")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
+
+set(CMAKE_CXX_CLANG_TIDY_SAVE "${CMAKE_CXX_CLANG_TIDY}")
+set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE_SAVE "${CMAKE_CXX_INCLUDE_WHAT_YOU_USE}")
+
+unset(CMAKE_CXX_CLANG_TIDY)
+unset(CMAKE_CXX_INCLUDE_WHAT_YOU_USE)
+
+# Add pugixml directly to our build. This defines
+# the gtest and gtest_main targets.
+add_subdirectory(${CMAKE_BINARY_DIR}/pugixml/pugixml-src
+ ${CMAKE_BINARY_DIR}/pugixml/pugixml-build)
+
+set_target_properties(pugixml PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:pugixml,INTERFACE_INCLUDE_DIRECTORIES>)
+
+set(Pugixml_LIBRARIES pugixml)
+set(Pugixml_INCLUDE_DIRS "$<TARGET_PROPERTY:pugixml,SOURCE_DIR>/src/")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_SAVE}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_SAVE}")
+
+set(CMAKE_CXX_CLANG_TIDY "${CMAKE_CXX_CLANG_TIDY_SAVE}")
+set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${CMAKE_CXX_INCLUDE_WHAT_YOU_USE_SAVE}")
diff --git a/src/external/rawspeed/cmake/Modules/Pugixml.cmake.in b/src/external/rawspeed/cmake/Modules/Pugixml.cmake.in
new file mode 100644
index 000000000..2a26fd70a
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/Pugixml.cmake.in
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(pugixml-download NONE)
+
+# Enable ExternalProject CMake module
+include(ExternalProject)
+
+option(ALLOW_DOWNLOADING_PUGIXML "If pugixml src tree is not found in location specified by PUGIXML_PATH, do fetch the archive from internet" OFF)
+set(PUGIXML_PATH "/usr/src/pugixml" CACHE PATH "Path to the pugixml root tree.")
+
+# Download and install pugixml
+
+message(STATUS "Looking for pugixml sources")
+message(STATUS "Looking for pugixml sources in ${PUGIXML_PATH}")
+if(EXISTS "${PUGIXML_PATH}" AND IS_DIRECTORY "${PUGIXML_PATH}" AND EXISTS "${PUGIXML_PATH}/CMakeLists.txt")
+ message(STATUS "Found pugixml in ${PUGIXML_PATH}")
+
+ ExternalProject_Add(
+ pugixml
+ URL "${PUGIXML_PATH}"
+ PREFIX "${CMAKE_BINARY_DIR}/pugixml"
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/pugixml-src"
+ BINARY_DIR "${CMAKE_BINARY_DIR}/pugixml-build"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+else()
+ if(NOT ALLOW_DOWNLOADING_PUGIXML)
+ message(SEND_ERROR "Did not find pugixml sources! Either pass correct path in PUGIXML_PATH, or enable ALLOW_DOWNLOADING_PUGIXML, or disable BUILD_TESTING.")
+ else()
+ message(WARNING "Did not find pugixml sources! Fetching from web...")
+ ExternalProject_Add(
+ pugixml
+ URL https://github.com/zeux/pugixml/releases/download/v1.8.1/pugixml-1.8.1.tar.gz
+ URL_HASH SHA512=1aec6f8cd0c385b66e848020d94d331db788c78523f72d145726738433a784b518084ec45a6eeffb0a6585bcf2759d09ad1e3d304d15d99068d43dbfd6db9d31
+ PREFIX "${CMAKE_BINARY_DIR}/pugixml"
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/pugixml-src"
+ BINARY_DIR "${CMAKE_BINARY_DIR}/pugixml-build"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+ endif()
+endif()
diff --git a/src/external/rawspeed/cmake/Modules/Zlib.cmake b/src/external/rawspeed/cmake/Modules/Zlib.cmake
new file mode 100644
index 000000000..31a4d024f
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/Zlib.cmake
@@ -0,0 +1,64 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(zlib NONE)
+
+# Download and unpack zlib at configure time
+configure_file(${RAWSPEED_SOURCE_DIR}/cmake/Modules/Zlib.cmake.in ${CMAKE_BINARY_DIR}/zlib/CMakeLists.txt @ONLY)
+
+execute_process(
+ COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}"
+ -DALLOW_DOWNLOADING_ZLIB=${ALLOW_DOWNLOADING_ZLIB} -DZLIB_PATH:PATH=${ZLIB_PATH} .
+ RESULT_VARIABLE result
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/zlib
+)
+
+if(result)
+ message(FATAL_ERROR "CMake step for zlib failed: ${result}")
+endif()
+
+execute_process(
+ COMMAND ${CMAKE_COMMAND} --build .
+ RESULT_VARIABLE result
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/zlib
+)
+
+if(result)
+ message(FATAL_ERROR "Build step for zlib failed: ${result}")
+endif()
+
+set(ZLIB_FOUND 1)
+
+set(CMAKE_C_FLAGS_SAVE "${CMAKE_C_FLAGS}")
+set(CMAKE_CXX_FLAGS_SAVE "${CMAKE_CXX_FLAGS}")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
+
+set(CMAKE_CXX_CLANG_TIDY_SAVE "${CMAKE_CXX_CLANG_TIDY}")
+set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE_SAVE "${CMAKE_CXX_INCLUDE_WHAT_YOU_USE}")
+
+unset(CMAKE_CXX_CLANG_TIDY)
+unset(CMAKE_CXX_INCLUDE_WHAT_YOU_USE)
+
+# XXX make sure that zlib is using it's own headers
+# see https://github.com/madler/zlib/issues/218
+include_directories(BEFORE ${CMAKE_BINARY_DIR}/zlib/zlib-src)
+include_directories(BEFORE ${CMAKE_BINARY_DIR}/zlib/zlib-build)
+
+# Add zlib directly to our build. This defines
+# the gtest and gtest_main targets.
+add_subdirectory(${CMAKE_BINARY_DIR}/zlib/zlib-src
+ ${CMAKE_BINARY_DIR}/zlib/zlib-build)
+
+set(_zlib_lib zlib) # shared
+set(_zlib_lib zlibstatic) # static
+
+set_target_properties(${_zlib_lib} PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:${_zlib_lib},INTERFACE_INCLUDE_DIRECTORIES>)
+
+set(ZLIB_LIBRARIES ${_zlib_lib})
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS_SAVE}")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS_SAVE}")
+
+set(CMAKE_CXX_CLANG_TIDY "${CMAKE_CXX_CLANG_TIDY_SAVE}")
+set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${CMAKE_CXX_INCLUDE_WHAT_YOU_USE_SAVE}")
diff --git a/src/external/rawspeed/cmake/Modules/Zlib.cmake.in b/src/external/rawspeed/cmake/Modules/Zlib.cmake.in
new file mode 100644
index 000000000..1f4a7a8a9
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/Zlib.cmake.in
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(zlib-download NONE)
+
+# Enable ExternalProject CMake module
+include(ExternalProject)
+
+option(ALLOW_DOWNLOADING_ZLIB "If ZLIB src tree is not found in location specified by ZLIB_PATH, do fetch the archive from internet" OFF)
+set(ZLIB_PATH "/usr/src/zlib" CACHE PATH "Path to the zlib root tree.")
+
+# Download and install ZLIB
+
+message(STATUS "Looking for ZLIB sources")
+message(STATUS "Looking for ZLIB sources in ${ZLIB_PATH}")
+if(EXISTS "${ZLIB_PATH}" AND IS_DIRECTORY "${ZLIB_PATH}" AND EXISTS "${ZLIB_PATH}/CMakeLists.txt")
+ message(STATUS "Found ZLIB in ${ZLIB_PATH}")
+
+ ExternalProject_Add(
+ zlib
+ URL "${ZLIB_PATH}"
+ PREFIX "${CMAKE_BINARY_DIR}/zlib"
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/zlib-src"
+ BINARY_DIR "${CMAKE_BINARY_DIR}/zlib-build"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+else()
+ if(NOT ALLOW_DOWNLOADING_ZLIB)
+ message(SEND_ERROR "Did not find ZLIB sources! Either pass correct path in ZLIB_PATH, or enable ALLOW_DOWNLOADING_ZLIB, or disable USE_BUNDLED_ZLIB or disable WITH_ZLIB.")
+ else()
+ message(WARNING "Did not find ZLIB sources! Fetching from web...")
+ ExternalProject_Add(
+ zlib
+ URL https://downloads.sourceforge.net/project/libpng/zlib/1.2.11/zlib-1.2.11.tar.xz
+ URL_HASH SHA512=b7f50ada138c7f93eb7eb1631efccd1d9f03a5e77b6c13c8b757017b2d462e19d2d3e01c50fad60a4ae1bc86d431f6f94c72c11ff410c25121e571953017cb67
+ PREFIX "${CMAKE_BINARY_DIR}/zlib"
+ SOURCE_DIR "${CMAKE_BINARY_DIR}/zlib-src"
+ BINARY_DIR "${CMAKE_BINARY_DIR}/zlib-build"
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND ""
+ INSTALL_COMMAND ""
+ TEST_COMMAND ""
+ )
+ endif()
+endif()
diff --git a/src/external/rawspeed/cmake/Modules/memory-align-alloc.cmake b/src/external/rawspeed/cmake/Modules/memory-align-alloc.cmake
new file mode 100644
index 000000000..b38ba3335
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/memory-align-alloc.cmake
@@ -0,0 +1,33 @@
+include(CheckCXXSymbolExists)
+
+# C++17 has std::aligned_alloc :(
+
+CHECK_CXX_SYMBOL_EXISTS(malloc cstdlib HAVE_MALLOC)
+CHECK_CXX_SYMBOL_EXISTS(free cstdlib HAVE_FREE)
+if(NOT (HAVE_MALLOC AND HAVE_FREE))
+ message(SEND_ERROR "Can't even find plain malloc() / free() !")
+endif()
+
+CHECK_CXX_SYMBOL_EXISTS(posix_memalign cstdlib HAVE_POSIX_MEMALIGN)
+if(HAVE_POSIX_MEMALIGN)
+ return()
+endif()
+
+CHECK_CXX_SYMBOL_EXISTS(aligned_alloc cstdlib HAVE_ALIGNED_ALLOC)
+if(HAVE_ALIGNED_ALLOC)
+ return()
+endif()
+
+CHECK_CXX_SYMBOL_EXISTS(_mm_malloc xmmintrin.h HAVE_MM_MALLOC)
+CHECK_CXX_SYMBOL_EXISTS(_mm_free xmmintrin.h HAVE_MM_FREE)
+if(HAVE_MM_MALLOC AND HAVE_MM_FREE)
+ return()
+endif()
+
+CHECK_CXX_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE_ALIGNED_MALLOC)
+CHECK_CXX_SYMBOL_EXISTS(_aligned_free malloc.h HAVE_ALIGNED_FREE)
+if(HAVE_ALIGNED_MALLOC AND HAVE_ALIGNED_FREE)
+ return()
+endif()
+
+message(WARNING "Can't find any aligned malloc() implementation!")
diff --git a/src/external/rawspeed/cmake/Modules/run-xmllint.cmake b/src/external/rawspeed/cmake/Modules/run-xmllint.cmake
new file mode 100644
index 000000000..d244d062a
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/run-xmllint.cmake
@@ -0,0 +1,25 @@
+macro (check_xml XML XSD)
+ get_filename_component(FILENAME "${XML}" NAME)
+
+ set(TOUCH "${CMAKE_CURRENT_BINARY_DIR}/${FILENAME}.touch")
+
+ set(TMPNAME "validate-${FILENAME}")
+
+ add_custom_command(
+ OUTPUT "${TOUCH}"
+ COMMAND "$<TARGET_FILE:xmllint>" --nonet --valid --noout --schema "${XSD}" "${XML}"
+ COMMAND "${CMAKE_COMMAND}" -E touch "${TOUCH}" # will be empty!
+ DEPENDS xmllint "${XML}" "${XSD}"
+ COMMENT "Checking validity of ${FILENAME}"
+ VERBATIM
+ )
+
+ add_custom_target(
+ ${TMPNAME}
+ DEPENDS "${TOUCH}" # will be empty!
+ DEPENDS "${XML}"
+ )
+
+ add_dependencies(check ${TMPNAME})
+ add_dependencies(rawspeed ${TMPNAME})
+endmacro (check_xml)
diff --git a/src/external/rawspeed/cmake/Modules/thread-local.cmake b/src/external/rawspeed/cmake/Modules/thread-local.cmake
new file mode 100644
index 000000000..004babf9f
--- /dev/null
+++ b/src/external/rawspeed/cmake/Modules/thread-local.cmake
@@ -0,0 +1,23 @@
+include(CheckCXXSourceCompiles)
+
+CHECK_CXX_SOURCE_COMPILES("
+static thread_local int tls;
+int main(void)
+{
+ return 0;
+}" HAVE_CXX_THREAD_LOCAL)
+if(HAVE_CXX_THREAD_LOCAL)
+ return()
+endif()
+
+CHECK_CXX_SOURCE_COMPILES("
+static __thread int tls;
+int main(void)
+{
+ return 0;
+}" HAVE_GCC_THREAD_LOCAL)
+if(HAVE_GCC_THREAD_LOCAL)
+ return()
+endif()
+
+MESSAGE(SEND_ERROR "The compiler does not support Thread-local storage.")
diff --git a/src/external/rawspeed/cmake/OpenMP.cmake b/src/external/rawspeed/cmake/OpenMP.cmake
new file mode 100644
index 000000000..099fb6ce8
--- /dev/null
+++ b/src/external/rawspeed/cmake/OpenMP.cmake
@@ -0,0 +1,23 @@
+if(WITH_OPENMP)
+ message(STATUS "Looking for OpenMP")
+ find_package(OpenMP)
+ if(OPENMP_FOUND)
+ message(STATUS "Looking for OpenMP - found")
+ set(HAVE_OPENMP 1)
+
+ if(NOT TARGET OpenMP::OpenMP)
+ add_library(OpenMP::OpenMP INTERFACE IMPORTED)
+ set_property(TARGET OpenMP::OpenMP PROPERTY INTERFACE_COMPILE_OPTIONS "${OpenMP_CXX_FLAGS}")
+ set_property(TARGET OpenMP::OpenMP PROPERTY INTERFACE_LINK_LIBRARIES "${OpenMP_CXX_FLAGS}")
+ endif()
+
+ set_package_properties(OpenMP PROPERTIES
+ TYPE OPTIONAL
+ PURPOSE "Used for parallelization of tools (NOT library!)")
+ else()
+ message(WARNING "Looking for OpenMP - failed. utilities will not use openmp-based parallelization")
+ endif()
+else()
+ message(STATUS "OpenMP is disabled, utilities will not use openmp-based parallelization")
+endif()
+add_feature_info("OpenMP-based utilites threading" HAVE_OPENMP "used for parallelization of utilities only, NOT library!")
diff --git a/src/external/rawspeed/cmake/build-type.cmake b/src/external/rawspeed/cmake/build-type.cmake
new file mode 100644
index 000000000..cb57d610a
--- /dev/null
+++ b/src/external/rawspeed/cmake/build-type.cmake
@@ -0,0 +1,40 @@
+# Add a sensible build type default and warning because empty means no optimization and no debug info.
+if(NOT CMAKE_BUILD_TYPE)
+ message("WARNING: CMAKE_BUILD_TYPE is not defined!")
+
+ set(default_build_type "RelWithDebInfo")
+
+ if(BUILD_TESTING)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ set(default_build_type "Coverage")
+ else()
+ set(default_build_type "SANITIZE")
+ endif()
+ endif()
+
+ message("WARNING: Defaulting to CMAKE_BUILD_TYPE=${default_build_type}. Use ccmake to set a proper value.")
+
+ SET(CMAKE_BUILD_TYPE ${default_build_type} CACHE STRING "" FORCE)
+endif(NOT CMAKE_BUILD_TYPE)
+
+# yes, these build types need to be specified here in upper-case.
+set(SPECIAL_BUILD_TYPES COVERAGE SANITIZE TSAN FUZZ)
+set(CMAKE_CONFIGURATION_TYPES DEBUG RELWITHDEBINFO RELEASE ${SPECIAL_BUILD_TYPES})
+set(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING "All the avaliable build types" FORCE)
+
+string(TOUPPER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE)
+SET(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING "Choose the type of build, options are: ${CMAKE_CONFIGURATION_TYPES}." FORCE )
+
+# is this one of the known build types?
+list (FIND CMAKE_CONFIGURATION_TYPES ${CMAKE_BUILD_TYPE} BUILD_TYPE)
+if (${BUILD_TYPE} EQUAL -1)
+ message(SEND_ERROR "Unknown build type: ${CMAKE_BUILD_TYPE}. Please specify one of: ${CMAKE_CONFIGURATION_TYPES}")
+endif()
+
+# is this a special build?
+list (FIND SPECIAL_BUILD_TYPES ${CMAKE_BUILD_TYPE} SPECIAL_BUILD)
+if (${SPECIAL_BUILD} EQUAL -1)
+ unset(SPECIAL_BUILD)
+else()
+ set(SPECIAL_BUILD 1)
+endif()
diff --git a/src/external/rawspeed/cmake/clang-tidy.cmake b/src/external/rawspeed/cmake/clang-tidy.cmake
new file mode 100644
index 000000000..f94af438f
--- /dev/null
+++ b/src/external/rawspeed/cmake/clang-tidy.cmake
@@ -0,0 +1,7 @@
+find_package(LLVMClangTidy REQUIRED)
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ set(CMAKE_CXX_CLANG_TIDY "${CLANGTIDY_PATH}" -extra-arg=-Wno-unknown-warning-option)
+else()
+ set(CMAKE_CXX_CLANG_TIDY "${CLANGTIDY_PATH}")
+endif()
diff --git a/src/external/rawspeed/cmake/compiler-flags.cmake b/src/external/rawspeed/cmake/compiler-flags.cmake
new file mode 100644
index 000000000..a6cb2decc
--- /dev/null
+++ b/src/external/rawspeed/cmake/compiler-flags.cmake
@@ -0,0 +1,235 @@
+include(CheckCXXCompilerFlag)
+include(CpuMarch)
+include(CheckCXXCompilerFlagAndEnableIt)
+
+# yes, need to keep both the CMAKE_CXX_FLAGS and CMAKE_CXX_STANDARD.
+# with just the CMAKE_CXX_STANDARD, try_compile() breaks:
+# https://gitlab.kitware.com/cmake/cmake/issues/16456
+# with just the CMAKE_CXX_FLAGS, 'bundled' pugixml breaks tests
+# https://github.com/darktable-org/rawspeed/issues/112#issuecomment-321517003
+
+message(STATUS "Checking for -std=c++14 support")
+CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14)
+if(NOT COMPILER_SUPPORTS_CXX14)
+ message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support. Please use a different C++ compiler.")
+else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
+ message(STATUS "Checking for -std=c++14 support - works")
+endif()
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
+# always debug info
+add_definitions(-g3)
+add_definitions(-ggdb3)
+
+if(CMAKE_BUILD_TYPE STREQUAL "RELEASE")
+ # want assertions in all but Release build type.
+ add_definitions(-DNDEBUG)
+elseif(NOT (CMAKE_BUILD_TYPE STREQUAL "RELWITHDEBINFO" OR CMAKE_BUILD_TYPE STREQUAL "FUZZ"))
+ # if not Release/RelWithDebInfo/Fuzz build, enable extra debug mode
+ add_definitions(-DDEBUG)
+
+ # all this does not work with integer sanitizer
+ # add_definitions(-D_GLIBCXX_ASSERTIONS)
+ # add_definitions(-D_GLIBCXX_DEBUG)
+ # add_definitions(-D_GLIBCXX_DEBUG_PEDANTIC)
+
+ add_definitions(-D_GLIBCXX_SANITIZE_VECTOR)
+endif()
+
+IF(NOT APPLE)
+ set(linkerflags "-Wl,--as-needed")
+ELSE()
+ set(linkerflags "")
+ENDIF()
+# NOT CMAKE_STATIC_LINKER_FLAGS
+SET(CMAKE_SHARED_LINKER_FLAGS
+ "${CMAKE_SHARED_LINKER_FLAGS} ${linkerflags}"
+ CACHE STRING "" FORCE )
+SET(CMAKE_EXE_LINKER_FLAGS
+ "${CMAKE_EXE_LINKER_FLAGS} ${linkerflags}"
+ CACHE STRING "" FORCE )
+SET(CMAKE_MODULE_LINKER_FLAGS
+ "${CMAKE_MODULE_LINKER_FLAGS} ${linkerflags}"
+ CACHE STRING "" FORCE )
+MARK_AS_ADVANCED(
+ CMAKE_SHARED_LINKER_FLAGS
+ CMAKE_EXE_LINKER_FLAGS
+ CMAKE_MODULE_LINKER_FLAGS )
+
+if(RAWSPEED_ENABLE_LTO)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ include(llvm-toolchain)
+ set(lto_compile "-flto=thin")
+ set(lto_link "-flto=thin -fuse-ld=\"${LLVMLLD_EXECUTABLE}\" ${LLVMLLD_INCREMENTAL_LDFLAGS}")
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ include(gcc-toolchain)
+ set(lto_compile "-flto")
+ set(lto_link "-flto")
+ endif()
+
+ set(CMAKE_C_FLAGS
+ "${CMAKE_C_FLAGS} ${lto_compile}"
+ CACHE STRING "Flags used by the C compiler during all builds."
+ FORCE )
+ set(CMAKE_CXX_FLAGS
+ "${CMAKE_CXX_FLAGS} ${lto_compile}"
+ CACHE STRING "Flags used by the C++ compiler during all builds."
+ FORCE )
+ set(CMAKE_EXE_LINKER_FLAGS
+ "${CMAKE_EXE_LINKER_FLAGS} ${lto_link}"
+ CACHE STRING "Flags used for linking binaries during all builds."
+ FORCE )
+ set(CMAKE_SHARED_LINKER_FLAGS
+ "${CMAKE_SHARED_LINKER_FLAGS} ${lto_link}"
+ CACHE STRING "Flags used by the shared libraries linker during all builds."
+ FORCE )
+ set(CMAKE_MODULE_LINKER_FLAGS
+ "${CMAKE_MODULE_LINKER_FLAGS} ${lto_link}"
+ CACHE STRING "Flags used by the module linker during all builds."
+ FORCE )
+ mark_as_advanced(
+ CMAKE_C_FLAGS
+ CMAKE_CXX_FLAGS
+ CMAKE_EXE_LINKER_FLAGS
+ CMAKE_SHARED_LINKER_FLAGS
+ CMAKE_MODULE_LINKER_FLAGS )
+endif()
+
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -O0")
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(coverage_compilation "-fprofile-instr-generate=\"default-%m-%p.profraw\" -fcoverage-mapping")
+ set(coverage_link "")
+elseif(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+ set(coverage_compilation "-fprofile-arcs -ftest-coverage")
+ set(coverage_link "--coverage")
+endif()
+
+SET(CMAKE_CXX_FLAGS_COVERAGE
+ "${coverage_compilation}"
+ CACHE STRING "Flags used by the C++ compiler during coverage builds."
+ FORCE )
+SET(CMAKE_C_FLAGS_COVERAGE
+ "${coverage_compilation}"
+ CACHE STRING "Flags used by the C compiler during coverage builds."
+ FORCE )
+SET(CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ "${coverage_compilation} ${coverage_link}"
+ CACHE STRING "Flags used for linking binaries during coverage builds."
+ FORCE )
+SET(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
+ "${coverage_compilation} ${coverage_link}"
+ CACHE STRING "Flags used by the shared libraries linker during coverage builds."
+ FORCE )
+SET(CMAKE_MODULE_LINKER_FLAGS_COVERAGE
+ "${coverage_compilation} ${coverage_link}"
+ CACHE STRING "Flags used by the module linker during coverage builds."
+ FORCE )
+MARK_AS_ADVANCED(
+ CMAKE_CXX_FLAGS_COVERAGE
+ CMAKE_C_FLAGS_COVERAGE
+ CMAKE_EXE_LINKER_FLAGS_COVERAGE
+ CMAKE_SHARED_LINKER_FLAGS_COVERAGE
+ CMAKE_MODULE_LINKER_FLAGS_COVERAGE )
+
+# -fstack-protector-all
+set(SANITIZATION_DEFAULTS "-O3 -fno-optimize-sibling-calls")
+
+set(asan "-fsanitize=address -fno-omit-frame-pointer -fno-common -U_FORTIFY_SOURCE")
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(asan "${asan} -fsanitize-address-use-after-scope")
+endif()
+
+set(ubsan "-fsanitize=undefined -fno-sanitize-recover=undefined")
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(ubsan "${ubsan} -fsanitize=integer -fno-sanitize-recover=integer")
+endif()
+
+SET(CMAKE_CXX_FLAGS_SANITIZE
+ "${SANITIZATION_DEFAULTS} ${asan} ${ubsan}"
+ CACHE STRING "Flags used by the C++ compiler during sanitized (ASAN+UBSAN) builds."
+ FORCE )
+SET(CMAKE_C_FLAGS_SANITIZE
+ "${SANITIZATION_DEFAULTS} ${asan} ${ubsan}"
+ CACHE STRING "Flags used by the C compiler during sanitized (ASAN+UBSAN) builds."
+ FORCE )
+MARK_AS_ADVANCED(
+ CMAKE_CXX_FLAGS_SANITIZE
+ CMAKE_C_FLAGS_SANITIZE )
+
+set(fuzz "-O3 -ffast-math")
+
+if(NOT LIB_FUZZING_ENGINE)
+ set(fuzz "${fuzz} ${asan} ${ubsan}")
+ set(fuzz "${fuzz} -fsanitize=fuzzer-no-link")
+else()
+ # specialhandling: oss-fuzz provides all the needed flags already.
+ message(STATUS "LIB_FUZZING_ENGINE override option is passed, not setting special compiler flags.")
+endif()
+
+set(fuzz "${fuzz} -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION")
+SET(CMAKE_CXX_FLAGS_FUZZ
+ "${fuzz}"
+ CACHE STRING "Flags used by the C++ compiler during FUZZ builds."
+ FORCE )
+SET(CMAKE_C_FLAGS_FUZZ
+ "${fuzz}"
+ CACHE STRING "Flags used by the C compiler during FUZZ builds."
+ FORCE )
+SET(CMAKE_EXE_LINKER_FLAGS_FUZZ
+ "${fuzz}"
+ CACHE STRING "Flags used for linking binaries during FUZZ builds."
+ FORCE )
+SET(CMAKE_SHARED_LINKER_FLAGS_FUZZ
+ "${fuzz}"
+ CACHE STRING "Flags used by the shared libraries linker during FUZZ builds."
+ FORCE )
+SET(CMAKE_SHARED_MODULE_FLAGS_FUZZ
+ "${fuzz}"
+ CACHE STRING "Flags used by the module linker during FUZZ builds."
+ FORCE )
+MARK_AS_ADVANCED(
+ CMAKE_CXX_FLAGS_FUZZ
+ CMAKE_C_FLAGS_FUZZ
+ CMAKE_EXE_LINKER_FLAGS_FUZZ
+ CMAKE_SHARED_LINKER_FLAGS_FUZZ
+ CMAKE_SHARED_MODULE_FLAGS_FUZZ )
+
+set(ubsan "${SANITIZATION_DEFAULTS} -fsanitize=thread")
+SET(CMAKE_CXX_FLAGS_TSAN
+ "${ubsan}"
+ CACHE STRING "Flags used by the C++ compiler during TSAN builds."
+ FORCE )
+SET(CMAKE_C_FLAGS_TSAN
+ "${ubsan}"
+ CACHE STRING "Flags used by the C compiler during TSAN builds."
+ FORCE )
+# SET(CMAKE_EXE_LINKER_FLAGS_TSAN
+# "-no-pie"
+# CACHE STRING "Flags used for linking binaries during TSAN builds."
+# FORCE )
+# SET(CMAKE_SHARED_LINKER_FLAGS_TSAN
+# "-no-pie"
+# CACHE STRING "Flags used by the shared libraries linker during TSAN builds."
+# FORCE )
+# SET(CMAKE_SHARED_MODULE_FLAGS_TSAN
+# "-no-pie"
+# CACHE STRING "Flags used by the module linker during TSAN builds."
+# FORCE )
+MARK_AS_ADVANCED(
+ CMAKE_CXX_FLAGS_TSAN
+ CMAKE_C_FLAGS_TSAN
+ CMAKE_EXE_LINKER_FLAGS_TSAN
+ CMAKE_SHARED_LINKER_FLAGS_TSAN
+ CMAKE_SHARED_MODULE_FLAGS_TSAN )
+
+set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O2")
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O2")
+
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3")
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
diff --git a/src/external/rawspeed/cmake/compiler-versions.cmake b/src/external/rawspeed/cmake/compiler-versions.cmake
new file mode 100644
index 000000000..b0fffe384
--- /dev/null
+++ b/src/external/rawspeed/cmake/compiler-versions.cmake
@@ -0,0 +1,33 @@
+# want C++14 support.
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
+ message(FATAL_ERROR "GNU C compiler version ${CMAKE_C_COMPILER_VERSION} is too old. Need 5.0+")
+endif()
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
+ message(FATAL_ERROR "GNU C++ compiler version ${CMAKE_CXX_COMPILER_VERSION} is too old. Need 5.0+")
+endif()
+
+if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
+ message(FATAL_ERROR "LLVM Clang C compiler version ${CMAKE_C_COMPILER_VERSION} is too old. Need 3.4+")
+endif()
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4)
+ message(FATAL_ERROR "LLVM Clang C++ compiler version ${CMAKE_CXX_COMPILER_VERSION} is too old. Need 3.4+")
+endif()
+
+# if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
+# message(WARNING "Support for GNU C compiler version ${CMAKE_C_COMPILER_VERSION} is soft-deprecated. Consider upgrading to 5.0+")
+# endif()
+
+# if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
+# message(WARNING "Support for GNU C++ compiler version ${CMAKE_CXX_COMPILER_VERSION} is soft-deprecated. Consider upgrading to 5.0+")
+# endif()
+
+# if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 3.5)
+# message(WARNING "LLVM Clang C compiler version ${CMAKE_C_COMPILER_VERSION} is soft-deprecated. Consider upgrading to 3.5+")
+# endif()
+
+# if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)
+# message(WARNING "LLVM Clang C++ compiler version ${CMAKE_CXX_COMPILER_VERSION} is soft-deprecated. Consider upgrading to 3.5+")
+# endif()
diff --git a/src/external/rawspeed/cmake/compiler-warnings-clang.cmake b/src/external/rawspeed/cmake/compiler-warnings-clang.cmake
new file mode 100644
index 000000000..5aeacf338
--- /dev/null
+++ b/src/external/rawspeed/cmake/compiler-warnings-clang.cmake
@@ -0,0 +1,60 @@
+include(CheckCXXCompilerFlagAndEnableIt)
+
+if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ return()
+endif()
+
+set (CLANG_WARNING_FLAGS
+ "all"
+ "extra"
+ "everything"
+)
+
+set (CLANG_DISABLED_WARNING_FLAGS
+ "c++98-compat"
+ "c++98-compat-pedantic"
+ "conversion" # FIXME: really need to enable this one
+ "covered-switch-default"
+ "deprecated"
+ "double-promotion"
+ "exit-time-destructors"
+ "global-constructors"
+ "gnu-zero-variadic-macro-arguments"
+ "old-style-cast"
+ "padded"
+ "switch-enum"
+ "unused-macros"
+ "unused-parameter"
+ "weak-vtables"
+ "zero-as-null-pointer-constant" # temporary
+)
+
+set(CMAKE_REQUIRED_FLAGS_ORIG "${CMAKE_REQUIRED_FLAGS}")
+set(CMAKE_REQUIRED_FLAGS "-c -Wunreachable-code -Werror=unreachable-code")
+# see https://reviews.llvm.org/D25321
+# see https://github.com/darktable-org/rawspeed/issues/104
+CHECK_CXX_SOURCE_COMPILES(
+ "void foo() {
+ return;
+ __builtin_unreachable();
+}"
+ CLANG_CXX_FLAG_UNREACHABLE_CODE_WORKS
+)
+set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_ORIG}")
+
+if(NOT CLANG_CXX_FLAG_UNREACHABLE_CODE_WORKS)
+ list(APPEND CLANG_DISABLED_WARNING_FLAGS "unreachable-code")
+endif()
+
+if(NOT (UNIX OR APPLE))
+ # bogus warnings about std functions...
+ list(APPEND CLANG_DISABLED_WARNING_FLAGS "used-but-marked-unused")
+endif()
+
+foreach(warning ${CLANG_WARNING_FLAGS})
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-W${warning})
+endforeach()
+
+foreach(warning ${CLANG_DISABLED_WARNING_FLAGS})
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wno-${warning})
+endforeach()
diff --git a/src/external/rawspeed/cmake/compiler-warnings-gcc.cmake b/src/external/rawspeed/cmake/compiler-warnings-gcc.cmake
new file mode 100644
index 000000000..a05bef5b5
--- /dev/null
+++ b/src/external/rawspeed/cmake/compiler-warnings-gcc.cmake
@@ -0,0 +1,59 @@
+include(CheckCXXCompilerFlagAndEnableIt)
+
+if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ return()
+endif()
+
+set (GCC_WARNING_FLAGS
+ "all"
+ "extra"
+
+ "cast-qual"
+ "extra"
+ "extra-semi"
+ "format=2"
+ "missing-prototypes"
+ "old-style-casts"
+ "pointer-arith"
+ "strict-prototypes"
+ "suggest-attribute=const"
+ "suggest-attribute=noreturn"
+ "suggest-attribute=pure"
+ "suggest-final-methods"
+ "suggest-final-types"
+ "suggest-override"
+ "traditional"
+ "vla"
+# "cast-align"
+# "conversion"
+)
+
+if(UNIX OR APPLE)
+ list(APPEND GCC_WARNING_FLAGS
+ "missing-format-attribute"
+ "suggest-attribute=format"
+ )
+endif()
+
+set (GCC_DISABLED_WARNING_FLAGS
+ "unused-parameter"
+)
+
+set (GCC_NOERROR_WARNING_FLAGS
+ "suggest-final-methods"
+ "suggest-final-types"
+ "suggest-override"
+ "suggest-attribute=noreturn"
+)
+
+foreach(warning ${GCC_WARNING_FLAGS})
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-W${warning})
+endforeach()
+
+foreach(warning ${GCC_DISABLED_WARNING_FLAGS})
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wno-${warning})
+endforeach()
+
+foreach(warning ${GCC_NOERROR_WARNING_FLAGS})
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wno-error=${warning})
+endforeach()
diff --git a/src/external/rawspeed/cmake/compiler-warnings.cmake b/src/external/rawspeed/cmake/compiler-warnings.cmake
new file mode 100644
index 000000000..de1c97405
--- /dev/null
+++ b/src/external/rawspeed/cmake/compiler-warnings.cmake
@@ -0,0 +1,25 @@
+include(CheckCXXCompilerFlagAndEnableIt)
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ include(compiler-warnings-gcc)
+endif()
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ include(compiler-warnings-clang)
+endif()
+
+if(NOT (UNIX OR APPLE))
+ # on windows, resuts in bogus false-positive varnings
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wno-format)
+endif()
+
+if(NOT SPECIAL_BUILD)
+ # should be < 64Kb
+ math(EXPR MAX_MEANINGFUL_SIZE 4*1024)
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wstack-usage=${MAX_MEANINGFUL_SIZE})
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wframe-larger-than=${MAX_MEANINGFUL_SIZE})
+
+ # as small as possible, but 1Mb+ is ok.
+ math(EXPR MAX_MEANINGFUL_SIZE 32*1024)
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wlarger-than=${MAX_MEANINGFUL_SIZE})
+endif()
diff --git a/src/external/rawspeed/cmake/gcc-coverage.cmake b/src/external/rawspeed/cmake/gcc-coverage.cmake
new file mode 100644
index 000000000..232607601
--- /dev/null
+++ b/src/external/rawspeed/cmake/gcc-coverage.cmake
@@ -0,0 +1,33 @@
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
+ message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
+ endif()
+elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
+ message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+endif()
+
+if(NOT CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
+ message(WARNING "Wrong build type, need COVERAGE.")
+endif()
+
+add_custom_target(
+ coverage-clean
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target genhtml-clean
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target lcov-clean
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target gcov-clean
+)
+
+add_custom_target(
+ coverage
+ DEPENDS tests
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target coverage-clean
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target lcov-baseline
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target test
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target lcov-capture
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target lcov-combine
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target lcov-postprocess
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target genhtml
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Doing everything to generate clean fresh HTML coverage report"
+ USES_TERMINAL
+)
diff --git a/src/external/rawspeed/cmake/gcc-gcov.cmake b/src/external/rawspeed/cmake/gcc-gcov.cmake
new file mode 100644
index 000000000..bd4f0e8f8
--- /dev/null
+++ b/src/external/rawspeed/cmake/gcc-gcov.cmake
@@ -0,0 +1,38 @@
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
+ message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
+ endif()
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
+ message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+endif()
+
+if(NOT CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
+ message(WARNING "Wrong build type, need COVERAGE.")
+endif()
+
+find_package(GCov REQUIRED)
+find_package(Find REQUIRED)
+
+set(GCOV_OPTS "-pb")
+
+if(NOT APPLE)
+ # DONT elide source prefix.
+ set(GCOV_OPTS ${GCOV_OPTS} -aflu)
+endif()
+
+add_custom_target(
+ gcov
+ COMMAND "${FIND_PATH}" "${CMAKE_BINARY_DIR}" -type f -name '*.gcno' -exec "${GCOV_PATH}" ${GCOV_OPTS} {} + > /dev/null
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Running gcov tool on all the *.gcno files to produce *.gcov files"
+ USES_TERMINAL
+)
+
+# DONT remove *.gcov files here!
+add_custom_target(
+ gcov-clean
+ COMMAND "${FIND_PATH}" "${CMAKE_BINARY_DIR}" -type f -name '*.gcda' -delete > /dev/null
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Removing all the *.gcda files"
+)
diff --git a/src/external/rawspeed/cmake/gcc-toolchain.cmake b/src/external/rawspeed/cmake/gcc-toolchain.cmake
new file mode 100644
index 000000000..cc3e2a579
--- /dev/null
+++ b/src/external/rawspeed/cmake/gcc-toolchain.cmake
@@ -0,0 +1,12 @@
+if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ return()
+endif()
+
+find_package(GCCAr REQUIRED)
+set(CMAKE_AR "${GCCAR_EXECUTABLE}" CACHE FILEPATH "" FORCE)
+
+find_package(GCCNm REQUIRED)
+set(CMAKE_NM "${GCCNM_EXECUTABLE}" CACHE FILEPATH "" FORCE)
+
+find_package(GCCRanLib REQUIRED)
+set(CMAKE_RANLIB "${GCCRANLIB_EXECUTABLE}" CACHE FILEPATH "" FORCE)
diff --git a/src/external/rawspeed/cmake/genhtml.cmake b/src/external/rawspeed/cmake/genhtml.cmake
new file mode 100644
index 000000000..410946ca1
--- /dev/null
+++ b/src/external/rawspeed/cmake/genhtml.cmake
@@ -0,0 +1,34 @@
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
+ message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
+ endif()
+elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
+ message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+endif()
+
+if(NOT CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
+ message(WARNING "Wrong build type, need COVERAGE.")
+endif()
+
+find_package(GenHtml REQUIRED)
+find_package(CppFilt REQUIRED)
+
+add_custom_target(
+ genhtml
+ COMMAND "${GENHTML_PATH}"
+ --demangle-cpp --precision 2
+ -o "${CMAKE_BINARY_DIR}/coverage/"
+ --prefix "${CMAKE_SOURCE_DIR}"
+ lcov.final.info
+ COMMAND "${CMAKE_COMMAND}" -E echo "Use $$ sensible-browser \"./coverage/index.html\" to view the coverage report."
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Running genhtml tool to generate HTML coverage report"
+ USES_TERMINAL
+)
+
+add_custom_target(
+ genhtml-clean
+ COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_BINARY_DIR}/coverage"
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Removing HTML coverage report"
+)
diff --git a/src/external/rawspeed/cmake/iwyu.cmake b/src/external/rawspeed/cmake/iwyu.cmake
new file mode 100644
index 000000000..0fd7ea772
--- /dev/null
+++ b/src/external/rawspeed/cmake/iwyu.cmake
@@ -0,0 +1,40 @@
+set(IWYU_IMP "${CMAKE_SOURCE_DIR}/cmake/iwyu.imp")
+
+find_program(iwyu_path NAMES include-what-you-use iwyu)
+if(NOT iwyu_path)
+ message(FATAL_ERROR "Could not find the program include-what-you-use.")
+else(NOT iwyu_path)
+ set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${iwyu_path}" -Xiwyu --mapping_file=${IWYU_IMP} -Xiwyu --check_also=${CMAKE_SOURCE_DIR}/src/* -Xiwyu --check_also=${CMAKE_SOURCE_DIR}/src/*/* -Xiwyu --check_also=${CMAKE_SOURCE_DIR}/src/*/*/* -Xiwyu --check_also=${CMAKE_SOURCE_DIR}/src/*/*/*/*)
+endif()
+
+find_program(iwyu_tool_path NAMES iwyu_tool iwyu_tool.py)
+if(iwyu_tool_path)
+ add_custom_command(
+ OUTPUT "${CMAKE_BINARY_DIR}/iwyu.log"
+ COMMAND "${iwyu_tool_path}" -v -p "${CMAKE_BINARY_DIR}"
+ -- --mapping_file=${IWYU_IMP} --check_also=${CMAKE_SOURCE_DIR}/src/* --check_also=${CMAKE_SOURCE_DIR}/src/*/* --check_also=${CMAKE_SOURCE_DIR}/src/*/*/* --check_also=${CMAKE_SOURCE_DIR}/src/*/*/*/* 2>
+ "${CMAKE_BINARY_DIR}/iwyu.log"
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Running include-what-you-use tool"
+ VERBATIM
+ )
+ add_custom_target(iwyu
+ DEPENDS "${CMAKE_BINARY_DIR}/iwyu.log"
+ VERBATIM
+ )
+endif()
+
+find_program(fix_includes_path NAMES fix_include fix_includes.py)
+if(fix_includes_path)
+ add_custom_target(iwyu_fix
+ COMMAND "${fix_includes_path}" --noblank_lines --comments
+ --safe_headers < "${CMAKE_BINARY_DIR}/iwyu.log" || true
+ COMMAND ${CMAKE_COMMAND} -E remove "${CMAKE_BINARY_DIR}/iwyu.log"
+ DEPENDS "${CMAKE_BINARY_DIR}/iwyu.log"
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Running include-what-you-use fix_includes tool"
+ VERBATIM
+ )
+endif()
+
+unset(IWYU_IMP)
diff --git a/src/external/rawspeed/cmake/iwyu.imp b/src/external/rawspeed/cmake/iwyu.imp
new file mode 100644
index 000000000..441812158
--- /dev/null
+++ b/src/external/rawspeed/cmake/iwyu.imp
@@ -0,0 +1,8 @@
+[
+ { include: ["<zconf.h>", "private", "<zlib.h>", "public"] },
+ { include: ["<jconfig.h>", "private", "<jpeglib.h>", "public"] },
+ { include: ["<jmorecfg.h>", "private", "<jpeglib.h>", "public"] },
+ { include: ["@<gtest/.*>", "private", "<gtest/gtest.h>", "public"] },
+ { include: ["@<gmock/.*>", "private", "<gmock/gmock.h>", "public"] },
+ { include: ["<ThreadSafetyAnalysis.h>", "private", "\"ThreadSafetyAnalysis.h\"", "public"] }
+]
diff --git a/src/external/rawspeed/cmake/lcov.cmake b/src/external/rawspeed/cmake/lcov.cmake
new file mode 100644
index 000000000..47cfe83f9
--- /dev/null
+++ b/src/external/rawspeed/cmake/lcov.cmake
@@ -0,0 +1,61 @@
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3)
+ message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
+ endif()
+elseif(NOT CMAKE_COMPILER_IS_GNUCXX)
+ message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...")
+endif()
+
+if(NOT CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
+ message(WARNING "Wrong build type, need COVERAGE.")
+endif()
+
+find_package(GCov REQUIRED)
+find_package(LCov REQUIRED)
+
+add_custom_target(
+ lcov-baseline
+ COMMAND "${LCOV_PATH}" --capture --initial --gcov-tool "${GCOV_PATH}"
+ --directory "${CMAKE_BINARY_DIR}"
+ --output-file lcov.baseline.info
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Capturnig initial zero coverage info"
+ USES_TERMINAL
+)
+
+add_custom_target(
+ lcov-capture
+ COMMAND "${LCOV_PATH}" --capture --gcov-tool "${GCOV_PATH}"
+ --directory "${CMAKE_BINARY_DIR}"
+ --output-file lcov.coverage.info
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Capturing the actual code coverage info"
+ USES_TERMINAL
+)
+
+add_custom_target(
+ lcov-combine
+ COMMAND "${LCOV_PATH}"
+ --add-tracefile lcov.baseline.info --add-tracefile lcov.coverage.info
+ --output-file lcov.total.info
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Combining initial zero coverage info and actual code coverage info"
+ USES_TERMINAL
+)
+
+add_custom_target(
+ lcov-postprocess
+ COMMAND "${LCOV_PATH}" --extract lcov.total.info '${CMAKE_SOURCE_DIR}/*' --output-file lcov.cleaned.info
+ COMMAND "${LCOV_PATH}" --remove lcov.cleaned.info '${CMAKE_BINARY_DIR}/*' --output-file lcov.final.info
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Cleaning the final code coverage info"
+ USES_TERMINAL
+)
+
+add_custom_target(
+ lcov-clean
+ COMMAND "${LCOV_PATH}" --directory "${CMAKE_BINARY_DIR}" --zerocounters > /dev/null
+ COMMAND "${CMAKE_COMMAND}" -E remove lcov.baseline.info lcov.coverage.info lcov.total.info lcov.cleaned.info lcov.final.info
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Resetting all execution counts to zero."
+)
diff --git a/src/external/rawspeed/cmake/libc++.cmake b/src/external/rawspeed/cmake/libc++.cmake
new file mode 100644
index 000000000..56f0f8ae4
--- /dev/null
+++ b/src/external/rawspeed/cmake/libc++.cmake
@@ -0,0 +1,13 @@
+if(NOT RAWSPEED_USE_LIBCXX)
+ return()
+endif()
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+list(REMOVE_ITEM CMAKE_CXX_IMPLICIT_LINK_LIBRARIES stdc++)
+list(APPEND CMAKE_CXX_IMPLICIT_LINK_LIBRARIES c++)
+list(REMOVE_DUPLICATES CMAKE_CXX_IMPLICIT_LINK_LIBRARIES)
+
+# Also remove incorrectly parsed -lto_library flag
+# It wasn't present with Xcode 7.2 and appeared before 8.3 release
+# cmake 3.7.2 doesn't understand this flag and thinks it's a library
+list(REMOVE_ITEM CMAKE_CXX_IMPLICIT_LINK_LIBRARIES to_library)
diff --git a/src/external/rawspeed/cmake/llvm-cov.cmake b/src/external/rawspeed/cmake/llvm-cov.cmake
new file mode 100644
index 000000000..7ec9b2f61
--- /dev/null
+++ b/src/external/rawspeed/cmake/llvm-cov.cmake
@@ -0,0 +1,42 @@
+if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ message(FATAL_ERROR "Compiler is not clang! Aborting...")
+endif()
+
+if(NOT CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
+ message(WARNING "Wrong build type, need COVERAGE.")
+endif()
+
+find_package(LLVMCov REQUIRED)
+find_package(Demangler REQUIRED)
+
+# FIXME: all this does not really work because only the rstest coverage is shown
+
+add_custom_target(
+ coverage-show
+ DEPENDS rstest
+ COMMAND "${LLVMCOV_PATH}" show -Xdemangler=$<TARGET_FILE:demangler> -instr-profile "${CMAKE_BINARY_DIR}/rawspeed.profdata" "$<TARGET_FILE:rstest>" -format html -output-dir "${CMAKE_BINARY_DIR}/coverage"
+ COMMAND "${CMAKE_COMMAND}" -E echo "Use $$ sensible-browser \"./coverage/index.html\" to view the coverage report."
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Running llvm-cov tool on the *.profdata file to generate HTML coverage report"
+ VERBATIM
+)
+
+add_custom_target(
+ coverage-clean
+ COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_BINARY_DIR}/coverage"
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Removing HTML coverage report"
+)
+
+add_custom_target(
+ coverage
+ DEPENDS tests rstest
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target coverage-clean
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target profdata-clean
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target test
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target profdata
+ COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_BINARY_DIR}" --target coverage-show
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Doing everything to generate clean fresh HTML coverage report"
+ USES_TERMINAL
+)
diff --git a/src/external/rawspeed/cmake/llvm-opt-report.cmake b/src/external/rawspeed/cmake/llvm-opt-report.cmake
new file mode 100644
index 000000000..fd33c24a7
--- /dev/null
+++ b/src/external/rawspeed/cmake/llvm-opt-report.cmake
@@ -0,0 +1,29 @@
+if(NOT USE_LLVM_OPT_REPORT OR NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ return()
+endif()
+
+include(CheckCXXCompilerFlag)
+
+find_package(LLVMOptViewer REQUIRED)
+
+message(STATUS "Checking for -fsave-optimization-record support")
+CHECK_CXX_COMPILER_FLAG("-fsave-optimization-record" HAVE_CXX_FLAG_FSAVE_OPTIMIZATION_RECORD)
+if(NOT HAVE_CXX_FLAG_FSAVE_OPTIMIZATION_RECORD)
+ message(FATAL_ERROR "The compiler ${CMAKE_CXX_COMPILER} does not support saving optimization records.")
+else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsave-optimization-record")
+endif()
+
+set(REPORT_PATH "${CMAKE_CURRENT_BINARY_DIR}/opt-report")
+
+add_custom_target(opt-report
+ COMMAND "${CMAKE_COMMAND}" -E remove_directory "${REPORT_PATH}"
+ COMMAND "${LLVMOPTVIEWER_PATH}"
+ --output-dir "${REPORT_PATH}"
+ -source-dir "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${CMAKE_CURRENT_BINARY_DIR}"
+ COMMAND "${CMAKE_COMMAND}" -E echo "Use $$ sensible-browser \"${REPORT_PATH}\" to view the optimizatons report."
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+ COMMENT "Generating HTML output to visualize optimization records from the YAML files"
+ VERBATIM
+ USES_TERMINAL)
diff --git a/src/external/rawspeed/cmake/llvm-profdata.cmake b/src/external/rawspeed/cmake/llvm-profdata.cmake
new file mode 100644
index 000000000..ecd4247ec
--- /dev/null
+++ b/src/external/rawspeed/cmake/llvm-profdata.cmake
@@ -0,0 +1,25 @@
+if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ message(FATAL_ERROR "Compiler is not clang! Aborting...")
+endif()
+
+if(NOT CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
+ message(WARNING "Wrong build type, need COVERAGE.")
+endif()
+
+find_package(LLVMProfData REQUIRED)
+find_package(Find REQUIRED)
+
+add_custom_target(
+ profdata
+ COMMAND "${FIND_PATH}" "${CMAKE_BINARY_DIR}" -type f -name '*.profraw' -exec "${LLVMPROFDATA_PATH}" merge -o "${CMAKE_BINARY_DIR}/rawspeed.profdata" {} + > /dev/null
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Running llvm-profdata tool on all the *.profraw files"
+)
+
+add_custom_target(
+ profdata-clean
+ COMMAND "${FIND_PATH}" "${CMAKE_BINARY_DIR}" -type f -name '*.profdata' -delete > /dev/null
+ COMMAND "${FIND_PATH}" "${CMAKE_BINARY_DIR}" -type f -name '*.profraw' -delete > /dev/null
+ WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+ COMMENT "Removing all the *.profdata and *.profraw files"
+)
diff --git a/src/external/rawspeed/cmake/llvm-toolchain.cmake b/src/external/rawspeed/cmake/llvm-toolchain.cmake
new file mode 100644
index 000000000..7c2a8326e
--- /dev/null
+++ b/src/external/rawspeed/cmake/llvm-toolchain.cmake
@@ -0,0 +1,19 @@
+find_package(LLVMAr REQUIRED)
+set(CMAKE_AR "${LLVMAR_EXECUTABLE}" CACHE FILEPATH "" FORCE)
+
+find_package(LLVMNm REQUIRED)
+set(CMAKE_NM "${LLVMNM_EXECUTABLE}" CACHE FILEPATH "" FORCE)
+
+find_package(LLVMObjCopy)
+if(LLVMObjCopy_FOUND)
+ set(CMAKE_OBJCOPY "${LLVMOBJCOPY_EXECUTABLE}" CACHE FILEPATH "" FORCE)
+endif()
+
+find_package(LLVMObjDump REQUIRED)
+set(CMAKE_OBJDUMP "${LLVMOBJDUMP_EXECUTABLE}" CACHE FILEPATH "" FORCE)
+
+find_package(LLVMRanLib REQUIRED)
+set(CMAKE_RANLIB "${LLVMRANLIB_EXECUTABLE}" CACHE FILEPATH "" FORCE)
+
+find_package(LLVMLLD REQUIRED)
+set(CMAKE_LINKER "${LLVMLLD_EXECUTABLE}" CACHE FILEPATH "" FORCE)
diff --git a/src/external/rawspeed/cmake/sample-based-testing.cmake b/src/external/rawspeed/cmake/sample-based-testing.cmake
new file mode 100644
index 000000000..a1d29adb2
--- /dev/null
+++ b/src/external/rawspeed/cmake/sample-based-testing.cmake
@@ -0,0 +1,67 @@
+message(STATUS "Looking for sample set for sample-based testing")
+message(STATUS "Looking for sample set in ${REFERENCE_SAMPLE_ARCHIVE}")
+if(NOT (EXISTS "${REFERENCE_SAMPLE_ARCHIVE}"
+ AND EXISTS "${REFERENCE_SAMPLE_ARCHIVE}/filelist.sha1"
+ AND EXISTS "${REFERENCE_SAMPLE_ARCHIVE}/timestamp.txt"))
+ message(SEND_ERROR "Did not find sample set for sample-based testing! Either pass correct path in REFERENCE_SAMPLE_ARCHIVE, or disable ENABLE_SAMPLEBASED_TESTING.")
+endif()
+
+message(STATUS "Found sample set in ${REFERENCE_SAMPLE_ARCHIVE}")
+
+file(STRINGS "${REFERENCE_SAMPLE_ARCHIVE}/filelist.sha1" _REFERENCE_SAMPLES ENCODING UTF-8)
+
+set(REFERENCE_SAMPLES)
+set(REFERENCE_SAMPLE_HASHES)
+
+foreach(STR ${_REFERENCE_SAMPLES})
+ string(SUBSTRING "${STR}" 40 -1 SAMPLENAME)
+ string(STRIP "${SAMPLENAME}" SAMPLENAME)
+ set(SAMPLENAME "${REFERENCE_SAMPLE_ARCHIVE}/${SAMPLENAME}")
+
+ if(NOT EXISTS "${SAMPLENAME}")
+ message(SEND_ERROR "The sample \"${SAMPLENAME}\" does not exist!")
+ endif()
+
+ list(APPEND REFERENCE_SAMPLES "${SAMPLENAME}")
+ list(APPEND REFERENCE_SAMPLE_HASHES "${SAMPLENAME}.hash")
+ list(APPEND REFERENCE_SAMPLE_HASHES "${SAMPLENAME}.hash.failed")
+endforeach()
+
+add_custom_target(rstest-create)
+add_custom_command(TARGET rstest-create
+ COMMAND rstest -c ${REFERENCE_SAMPLES}
+ WORKING_DIRECTORY "${REFERENCE_SAMPLE_ARCHIVE}"
+ COMMENT "Running rstest on all the samples in the sample set to generate the missing hashes"
+ VERBATIM
+ USES_TERMINAL)
+
+add_custom_target(rstest-recreate)
+add_custom_command(TARGET rstest-recreate
+ COMMAND rstest -c -f ${REFERENCE_SAMPLES}
+ WORKING_DIRECTORY "${REFERENCE_SAMPLE_ARCHIVE}"
+ COMMENT "Running rstest on all the samples in the sample set to [re]generate all the hashes"
+ VERBATIM
+ USES_TERMINAL)
+
+add_custom_target(rstest-test) # hashes must exist beforehand
+add_custom_command(TARGET rstest-test
+ COMMAND rstest ${REFERENCE_SAMPLES}
+ WORKING_DIRECTORY "${REFERENCE_SAMPLE_ARCHIVE}"
+ COMMENT "Running rstest on all the samples in the sample set to check for regressions"
+ VERBATIM
+ USES_TERMINAL)
+
+add_custom_target(rstest-check) # hashes should exist beforehand if you want to check for regressions
+add_custom_command(TARGET rstest-check
+ COMMAND rstest -f ${REFERENCE_SAMPLES}
+ WORKING_DIRECTORY "${REFERENCE_SAMPLE_ARCHIVE}"
+ COMMENT "Trying to decode all the samples in the sample set"
+ VERBATIM
+ USES_TERMINAL)
+
+add_custom_target(rstest-clean)
+add_custom_command(TARGET rstest-clean
+ COMMAND "${CMAKE_COMMAND}" -E remove ${REFERENCE_SAMPLE_HASHES}
+ WORKING_DIRECTORY "${REFERENCE_SAMPLE_ARCHIVE}"
+ COMMENT "Removing *.hash, *.hash.failed for the each sample in the set"
+ VERBATIM)
diff --git a/src/external/rawspeed/cmake/src-dependencies.cmake b/src/external/rawspeed/cmake/src-dependencies.cmake
new file mode 100644
index 000000000..7a3a471b6
--- /dev/null
+++ b/src/external/rawspeed/cmake/src-dependencies.cmake
@@ -0,0 +1,148 @@
+if(BUILD_TESTING)
+ # want GTEST_ADD_TESTS() macro. NOT THE ACTUAL MODULE!
+ include(GTEST_ADD_TESTS)
+
+ # for the actual gtest:
+
+ # at least in debian, they are the package only installs their source code,
+ # so if one wants to use them, he needs to compile them in-tree
+ include(GoogleTest)
+
+ add_dependencies(dependencies gtest gmock_main)
+endif()
+
+if(BUILD_BENCHMARKING)
+ include(GoogleBenchmark)
+
+ add_dependencies(dependencies benchmark)
+endif()
+
+if(WITH_PTHREADS)
+ message(STATUS "Looking for PThreads")
+ set(CMAKE_THREAD_PREFER_PTHREAD 1)
+ find_package(Threads)
+ if(NOT CMAKE_USE_PTHREADS_INIT)
+ message(SEND_ERROR "Did not found POSIX Threads! Either make it find PThreads, or pass -DWITH_PTHREADS=OFF to disable threading.")
+ else()
+ message(STATUS "Looking for PThreads - found")
+ set(HAVE_PTHREAD 1)
+ target_link_libraries(rawspeed PUBLIC Threads::Threads)
+ set_package_properties(Threads PROPERTIES
+ TYPE RECOMMENDED
+ DESCRIPTION "POSIX Threads"
+ PURPOSE "Used for parallelization of the library itself")
+ endif()
+else()
+ message(STATUS "PThread-based threading is disabled. Not searching for PThreads")
+endif()
+add_feature_info("PThread-based library threading" HAVE_PTHREAD "used for parallelized image decoding")
+
+include(OpenMP)
+
+if(WITH_PUGIXML)
+ message(STATUS "Looking for pugixml")
+ if(NOT USE_BUNDLED_PUGIXML)
+ find_package(Pugixml 1.2)
+ if(NOT Pugixml_FOUND)
+ message(SEND_ERROR "Did not found Pugixml! Either make it find Pugixml, or pass -DUSE_BUNDLED_PUGIXML=ON to enable in-tree pugixml.")
+ else()
+ message(STATUS "Looking for pugixml - found (system)")
+ endif()
+ else()
+ include(Pugixml)
+ if(NOT Pugixml_FOUND)
+ message(SEND_ERROR "Managed to fail to use 'bundled' Pugixml!")
+ else()
+ message(STATUS "Looking for pugixml - found ('in-tree')")
+ add_dependencies(dependencies ${Pugixml_LIBRARIES})
+ endif()
+ endif()
+
+ if(Pugixml_FOUND)
+ set(HAVE_PUGIXML 1)
+
+ if(NOT TARGET Pugixml::Pugixml)
+ add_library(Pugixml::Pugixml INTERFACE IMPORTED)
+ set_property(TARGET Pugixml::Pugixml PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Pugixml_INCLUDE_DIRS}")
+ set_property(TARGET Pugixml::Pugixml PROPERTY INTERFACE_LINK_LIBRARIES "${Pugixml_LIBRARIES}")
+ endif()
+
+ target_link_libraries(rawspeed PUBLIC Pugixml::Pugixml)
+ set_package_properties(Pugixml PROPERTIES
+ TYPE REQUIRED
+ URL http://pugixml.org/
+ DESCRIPTION "Light-weight, simple and fast XML parser"
+ PURPOSE "Used for loading of data/cameras.xml")
+ endif()
+else()
+ message(STATUS "Pugixml library support is disabled. I hope you know what you are doing.")
+endif()
+add_feature_info("XML reading" HAVE_PUGIXML "used for loading of data/cameras.xml")
+
+if(WITH_JPEG)
+ message(STATUS "Looking for JPEG")
+ find_package(JPEG)
+ if(NOT JPEG_FOUND)
+ message(SEND_ERROR "Did not find JPEG! Either make it find JPEG, or pass -DWITH_JPEG=OFF to disable JPEG.")
+ else()
+ message(STATUS "Looking for JPEG - found")
+ set(HAVE_JPEG 1)
+
+ if(NOT TARGET JPEG::JPEG)
+ add_library(JPEG::JPEG INTERFACE IMPORTED)
+ set_property(TARGET JPEG::JPEG PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${JPEG_INCLUDE_DIRS}")
+ set_property(TARGET JPEG::JPEG PROPERTY INTERFACE_LINK_LIBRARIES "${JPEG_LIBRARIES}")
+ endif()
+
+ target_link_libraries(rawspeed PUBLIC JPEG::JPEG)
+ set_package_properties(JPEG PROPERTIES
+ TYPE RECOMMENDED
+ DESCRIPTION "free library for handling the JPEG image data format, implements a JPEG codec"
+ PURPOSE "Used for decoding DNG Lossy JPEG compression")
+
+ include(CheckJPEGSymbols)
+ endif()
+else()
+ message(STATUS "JPEG is disabled, DNG Lossy JPEG support won't be available.")
+endif()
+add_feature_info("Lossy JPEG decoding" HAVE_JPEG "used for DNG Lossy JPEG compression decoding")
+
+if (WITH_ZLIB)
+ message(STATUS "Looking for ZLIB")
+ if(NOT USE_BUNDLED_ZLIB)
+ find_package(ZLIB)
+ if(NOT ZLIB_FOUND)
+ message(SEND_ERROR "Did not find ZLIB! Either make it find ZLIB, or pass -DWITH_ZLIB=OFF to disable ZLIB, or pass -DUSE_BUNDLED_ZLIB=ON to enable in-tree ZLIB.")
+ else()
+ include(CheckZLIB)
+ message(STATUS "Looking for ZLIB - found (system)")
+ endif()
+ else()
+ include(Zlib)
+ if(NOT ZLIB_FOUND)
+ message(SEND_ERROR "Managed to fail to use 'bundled' ZLIB!")
+ else()
+ message(STATUS "Looking for ZLIB - found ('in-tree')")
+ add_dependencies(dependencies ${ZLIB_LIBRARIES})
+ endif()
+ endif()
+
+ if(ZLIB_FOUND)
+ set(HAVE_ZLIB 1)
+
+ if(NOT TARGET ZLIB::ZLIB)
+ add_library(ZLIB::ZLIB INTERFACE IMPORTED)
+ set_property(TARGET ZLIB::ZLIB PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INCLUDE_DIRS}")
+ set_property(TARGET ZLIB::ZLIB PROPERTY INTERFACE_LINK_LIBRARIES "${ZLIB_LIBRARIES}")
+ endif()
+
+ target_link_libraries(rawspeed PUBLIC ZLIB::ZLIB)
+ set_package_properties(ZLIB PROPERTIES
+ TYPE RECOMMENDED
+ DESCRIPTION "software library used for data compression"
+ PURPOSE "Used for decoding DNG Deflate compression")
+ endif()
+else()
+ message(STATUS "ZLIB is disabled, DNG deflate support won't be available.")
+endif()
+add_feature_info("ZLIB decoding" HAVE_ZLIB "used for DNG Deflate compression decoding")
diff --git a/src/external/rawspeed/credits.txt b/src/external/rawspeed/credits.txt
new file mode 100644
index 000000000..a1126040f
--- /dev/null
+++ b/src/external/rawspeed/credits.txt
@@ -0,0 +1,24 @@
+RawSpeed - a fast RAW file decoder.
+Copyright (C) 2009-2014 Klaus Post
+
+Project github: https://github.com/darktable-org/rawspeed
+
+Email: klauspost (at) gmail (dot) com
+
+
+RawSpeed contains code from the following projects:
+
+ * libopenraw by Hubert Figuiere, et al.
+ * http://libopenraw.freedesktop.org
+
+ * dcraw by David Coffin
+ * http://www.cybercom.net/~dcoffin/
+
+Thanks to:
+ * Pedro Côrte-Real for writing support for Minolta & old Panasonic cameras.
+ * Pascal de Bruijn for a ton of help with camera definitions
+ * Alex Tutubalin for bug reports, help and good suggestions
+ * Laurent Clevy for his excellent CR2 documentation project:
+ * http://lclevy.free.fr/cr2/index.html
+ * All who supplied RAW test images to Rawstudio
+ * Of course all involved with the Rawstudio project
diff --git a/src/external/rawspeed/data/CMakeLists.txt b/src/external/rawspeed/data/CMakeLists.txt
new file mode 100644
index 000000000..c0f38f9b8
--- /dev/null
+++ b/src/external/rawspeed/data/CMakeLists.txt
@@ -0,0 +1,12 @@
+if(USE_XMLLINT)
+ find_package(XMLLINT)
+endif()
+
+if(USE_XMLLINT AND XMLLINT_FOUND)
+ include(run-xmllint)
+ check_xml(${CMAKE_CURRENT_SOURCE_DIR}/cameras.xml ${CMAKE_CURRENT_SOURCE_DIR}/cameras.xsd)
+endif()
+
+if(WITH_PUGIXML)
+ install(FILES cameras.xml showcameras.xsl DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/rawspeed)
+endif()
diff --git a/src/external/rawspeed/data/README.md b/src/external/rawspeed/data/README.md
new file mode 100644
index 000000000..ca692fc35
--- /dev/null
+++ b/src/external/rawspeed/data/README.md
@@ -0,0 +1,131 @@
+# RawSpeed Camera Definition File
+
+The camera definition file is used for decoding images which don’t require any code changes. This enables us to add support for cameras which were not yet released when the code was written.
+
+```xml
+<Camera make="Panasonic" model="DMC-FZ45" mode="4:3" supported="yes" decoder_version="0">
+ <ID make="Panasonic" model="DMC-FZ45">Panasonic DMC-FZ45</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color><Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color><Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-58" height="-10"/>
+ <Sensor black="150" white="4097" iso_min="0" iso_max="0"/>
+ <BlackAreas>
+ <Vertical x="0" width="60"/>
+ <Horizontal y="2" height="46"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="coolpixsplit" value=""/>
+ </Hints>
+ <Aliases>
+ <Alias id="DMC-FZ40">DMC-FZ40</Alias>
+ </Aliases>
+</Camera>
+```
+
+Let’s go through it line for line:
+
+## Camera Name
+
+```xml
+<Camera make="Panasonic" model="DMC-FZ45" mode="4:3" supported="yes" decoder_version="0">
+```
+
+This the basic camera identification. In this the make and model are required. This must be exactly as specified in the EXIF data of the file.
+
+Mode refers to specific decoder modes which are special for each manufacturer. For cameras with specific modes there is usually a default (no mode specified) and some for non-default operation. For Canon for instance mode refers to “sRaw1″ and “sRaw2″. For Panasonic it refers to cropping modes, since they require different cropping of the output image.
+
+The supported tag specifies whether a camera is supported. If this tag isn’t added it is assumed to be supported.
+
+The decoder_version is a possibility to disable decoding, if the decoder version is too old to properly decode the images from this camera. If the code version of RawSpeed is too old to decode this camera type, it will refuse to do so. If this isn’t specified it is assumed that all older versions of RawSpeed can decode the image.
+
+## Camera ID
+
+```xml
+<ID make="Panasonic" model="DMC-FZ45">Panasonic DMC-FZ45</ID>
+```
+
+This sets the canonical name for the camera. The content of the tag should be the same as the UniqueCameraModel DNG field in the Adobe DNG converted raw file and can be used to match the camera against DCP files or other external references. The make and model attributes are clean names (no repetitions, spurious words, etc) that can be used in UI. If the Alias tag is omitted the make and model from the Camera tag are used instead (joined with a space for UniqueCameraModel), so in this particular case the tag is actually not needed.
+
+## CFA Colors
+
+```xml
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color><Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color><Color x="1" y="1">GREEN</Color>
+ </CFA>
+```
+
+This refers to the color layout of the sensor. This is the position of the colors on the uncropped image, so it will be the same no matter what crop you specify. Currently only 2×2 CFA patterns are possible.
+
+From version 2, there is an alternative syntax; *CFA2*. This definition allows for sizes *bigger than 2x2* and has a simpler syntax:
+
+```xml
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+```
+Valid colors are:
+
+Colors are G(reen), R(ed), B(blue) , F(uji green), C(yan), M(agenta) and Y(ellow).
+
+## Image Cropping
+
+```xml
+ <Crop x="0" y="0" width="-58" height="-10"/>
+```
+
+This is the cropping to be applied to the image. x & y are specified relative to the top-left of the image and are specified in pixels. Width & Height can be a number which is the desired output size in pixels. A negative number for width or height specifies a number of pixels that must be cropped from the bottom/right side of the image.
+
+## Sensor Info
+
+```xml
+ <Sensor black="150" white="4097" iso_min="0" iso_max="0"/>
+```
+
+This tag can be added more than 1 time, but at least 1 must be present.
+
+This specifies the black and white levels of images captured. Black and white must be specified. On cameras (some Nikons for instance) and files (DNG images) where this can be read from the image files themselves this is overridden.
+
+The iso_min and iso_max are optional which indicates an ISO range where this must be applied. If both are set to 0, or left undefined they act as default values for all ISO values. Note that not all cameras may decode the ISO value.
+
+Both ISO values are inclusive, so specify ranges so they don’t overlap (0->399, 400->799, etc). If different entry ranges overlap the first match will be used.
+
+For backward compatibility, leave the default value as the last entry.
+
+## Sensor Black Areas
+
+```xml
+ <BlackAreas>
+ <Vertical x="0" width="60"/>
+ <Horizontal y="2" height="46"/>
+ </BlackAreas>
+```
+
+This entry specifies one or more “black” areas on the sensor. This is areas where the sensor receives no light and it can therefore be used to accurately determine the black level of each image. The areas can be described as a vertical area starting a fixed number of pixels from the left and having a fixed width, or a horizontal, starting a fixed number of pixels down and having a fixed height.
+
+All the areas are summed up in a histogram for each color component, and the median value is selected as the black value. This should ensure that noise and minor differences in hardware shouldn’t influence the calculations.
+
+If any black areas are defined it will override any “black” value set in the Sensor definition.
+
+## Decoder Hints
+
+```xml
+ <Hints>
+ <Hint name="coolpixsplit" value=""/>
+ </Hints>
+```
+
+This may contain manufacturer-specific hints for decoding. This can result in the code taking a specific decoder path, or otherwise treat the image differently. This is mainly used when it isn’t possible to determine which way to decode the image directly from the image data.
+
+## Camera Model Aliases
+
+```xml
+ <Aliases>
+ <Alias id="DMC-FZ40">DMC-FZ40</Alias>
+ </Aliases>
+```
+
+This is a possibility to add one or more model aliases for a camera, which may have different model names in different regions. The id attribute specifies the clean model name for this alias, if omitted defaults to alias value (so in this case is not really needed).
diff --git a/src/external/rawspeed/data/cameras.xml b/src/external/rawspeed/data/cameras.xml
new file mode 100644
index 000000000..1835e7263
--- /dev/null
+++ b/src/external/rawspeed/data/cameras.xml
@@ -0,0 +1,11226 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<?xml-stylesheet type="text/xsl" href="showcameras.xsl" ?>
+<!--
+ License: CC-BY-SA 3.0
+
+ This work is licensed under a
+ Creative Commons Attribution-ShareAlike 3.0 Unported License.
+
+ See more at:
+ http://creativecommons.org/licenses/by-sa/3.0/
+-->
+
+<!DOCTYPE Cameras [
+<!ELEMENT BlackAreas ( Vertical*, Horizontal* ) >
+
+<!ELEMENT Camera ( ID?, CFA?, CFA2?, Crop?, Sensor*, BlackAreas?, Aliases?, Hints? ) >
+<!ATTLIST Camera make CDATA #REQUIRED >
+<!ATTLIST Camera model CDATA #REQUIRED >
+<!ATTLIST Camera supported CDATA #IMPLIED >
+<!ATTLIST Camera mode CDATA #IMPLIED >
+<!ATTLIST Camera decoder_version CDATA #IMPLIED >
+
+<!ELEMENT Cameras ( Camera+ ) >
+<!ATTLIST Cameras version CDATA #IMPLIED >
+
+<!ELEMENT CFA ( Color+ ) >
+<!ATTLIST CFA height NMTOKEN #REQUIRED >
+<!ATTLIST CFA width NMTOKEN #REQUIRED >
+
+<!ELEMENT CFA2 ( Color*, ColorRow* ) >
+<!ATTLIST CFA2 height NMTOKEN #REQUIRED >
+<!ATTLIST CFA2 width NMTOKEN #REQUIRED >
+
+<!ELEMENT Color ( #PCDATA ) >
+<!ATTLIST Color x NMTOKEN #REQUIRED >
+<!ATTLIST Color y NMTOKEN #REQUIRED >
+
+<!ELEMENT ColorRow ( #PCDATA ) >
+<!ATTLIST ColorRow y NMTOKEN #REQUIRED >
+
+<!ELEMENT Crop EMPTY >
+<!ATTLIST Crop height NMTOKEN #REQUIRED >
+<!ATTLIST Crop width NMTOKEN #REQUIRED >
+<!ATTLIST Crop x NMTOKEN #REQUIRED >
+<!ATTLIST Crop y NMTOKEN #REQUIRED >
+
+<!ELEMENT Horizontal EMPTY >
+<!ATTLIST Horizontal height NMTOKEN #REQUIRED >
+<!ATTLIST Horizontal y NMTOKEN #REQUIRED >
+
+<!ELEMENT Sensor EMPTY >
+<!ATTLIST Sensor white NMTOKEN #REQUIRED >
+<!ATTLIST Sensor black NMTOKEN #REQUIRED >
+<!ATTLIST Sensor black_colors NMTOKEN #IMPLIED >
+<!ATTLIST Sensor iso_list NMTOKENS #IMPLIED >
+<!ATTLIST Sensor iso_min NMTOKEN #IMPLIED >
+<!ATTLIST Sensor iso_max NMTOKEN #IMPLIED >
+
+<!ELEMENT Vertical EMPTY >
+<!ATTLIST Vertical width NMTOKEN #REQUIRED >
+<!ATTLIST Vertical x NMTOKEN #REQUIRED >
+
+<!ELEMENT Hints ( Hint+ ) >
+<!ELEMENT Hint EMPTY >
+<!ATTLIST Hint name CDATA #REQUIRED >
+<!ATTLIST Hint value CDATA #REQUIRED >
+
+<!ELEMENT Aliases ( Alias+ ) >
+<!ATTLIST Alias id CDATA #IMPLIED >
+<!ELEMENT Alias (#PCDATA) >
+
+<!ELEMENT ID (#PCDATA) >
+<!ATTLIST ID make CDATA #REQUIRED >
+<!ATTLIST ID model CDATA #REQUIRED >
+]>
+
+<Cameras>
+ <Camera make="ARRI" model="ALEXA" supported="no"> <!-- no samples -->
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 100D">
+ <ID make="Canon" model="EOS 100D">Canon EOS 100D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="72" y="52" width="0" height="0"/>
+ <Sensor black="2048" white="15000"/>
+ <Sensor black="2047" white="12277" iso_list="100"/>
+ <Sensor black="2047" white="15000" iso_list="200 6400"/>
+ <Sensor black="2048" white="15000" iso_list="800 3200"/>
+ <Sensor black="2049" white="15000" iso_list="1600"/>
+ <Sensor black="2046" white="15000" iso_list="25600"/>
+ <BlackAreas>
+ <Vertical x="0" width="72"/>
+ <Horizontal y="8" height="44"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Rebel SL1">Canon EOS REBEL SL1</Alias>
+ <Alias id="EOS Kiss X7">Canon EOS Kiss X7</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 200D">
+ <ID make="Canon" model="EOS 200D">Canon EOS 200D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="266" y="42" width="-6" height="-4"/>
+ <Sensor black="2049" white="14338"/>
+ <Sensor black="511" white="11892" iso_list="100"/>
+ <Sensor black="511" white="14338" iso_list="200"/>
+ <Sensor black="2041" white="14338" iso_list="51200"/>
+ <BlackAreas>
+ <Vertical x="0" width="260"/>
+ <Horizontal y="0" height="38"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Rebel SL2">Canon EOS Rebel SL2</Alias>
+ <Alias id="EOS Kiss X9">Canon EOS Kiss X9</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 300D DIGITAL">
+ <ID make="Canon" model="EOS 300D">Canon EOS 300D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="64" y="12" width="0" height="0"/>
+ <Sensor black="126" white="4000"/>
+ <Sensor black="127" white="4000" iso_list="200"/>
+ <Sensor black="128" white="4000" iso_list="400"/>
+ <Sensor black="129" white="4000" iso_list="800"/>
+ <Sensor black="251" white="4000" iso_list="1600"/>
+ <Sensor black="250" white="4000" iso_list="3200"/>
+ <BlackAreas>
+ <Vertical x="6" width="58"/>
+ <Horizontal y="4" height="8"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Digital Rebel">Canon EOS DIGITAL REBEL</Alias>
+ <Alias id="EOS Kiss Digital">Canon EOS Kiss Digital</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS D30">
+ <ID make="Canon" model="EOS D30">Canon EOS D30</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="52" y="10" width="0" height="-6"/>
+ <Sensor black="126" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="46"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS D60">
+ <ID make="Canon" model="EOS D60">Canon EOS D60</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="68" y="18" width="-4" height="-4"/>
+ <Sensor black="127" white="4000"/>
+ <BlackAreas>
+ <Vertical x="0" width="60"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 10D">
+ <ID make="Canon" model="EOS 10D">Canon EOS 10D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="64" y="12" width="0" height="0"/>
+ <Sensor black="127" white="4000"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 20D">
+ <ID make="Canon" model="EOS 20D">Canon EOS 20D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="74" y="12" width="3522" height="2348"/>
+ <Sensor black="126" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="72"/>
+ <Horizontal y="2" height="8"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="50"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 30D">
+ <ID make="Canon" model="EOS 30D">Canon EOS 30D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="74" y="12" width="3522" height="2348"/>
+ <Sensor black="127" white="3398"/>
+ <BlackAreas>
+ <Vertical x="0" width="72"/>
+ <Horizontal y="2" height="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 350D DIGITAL">
+ <ID make="Canon" model="EOS 350D">Canon EOS 350D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="42" y="14" width="3474" height="2314"/>
+ <Sensor black="255" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="40"/>
+ <Horizontal y="0" height="12"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="Digital Rebel XT">Canon EOS DIGITAL REBEL XT</Alias>
+ <Alias id="Kiss Digital N">Canon EOS Kiss Digital N</Alias>
+ <Alias id="EOS 350D">Canon EOS 350D</Alias>
+ <Alias id="EOS 350D">Canon EOS 350D Digital</Alias>
+ </Aliases>
+ <Hints>
+ <Hint name="wb_offset" value="50"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 40D" decoder_version="2">
+ <ID make="Canon" model="EOS 40D">Canon EOS 40D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="30" y="18" width="3908" height="2602"/>
+ <Sensor black="1021" white="13600"/>
+ <BlackAreas>
+ <Vertical x="0" width="28"/>
+ <Horizontal y="4" height="12"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 40D" mode="sRaw1">
+ <ID make="Canon" model="EOS 40D">Canon EOS 40D</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="sraw_40d" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 40D" mode="sRaw2">
+ <ID make="Canon" model="EOS 40D">Canon EOS 40D</ID>
+ <Crop x="0" y="0" width="1944" height="1296"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="sraw_40d" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 450D">
+ <ID make="Canon" model="EOS 450D">Canon EOS 450D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="22" y="18" width="4290" height="2856"/>
+ <Sensor black="1020" white="14500"/>
+ <Aliases>
+ <Alias id="Digital Rebel XSi">Canon EOS DIGITAL REBEL XSi</Alias>
+ <Alias id="Kiss Digital X2">Canon EOS Kiss Digital X2</Alias>
+ <Alias id="Kiss X2">Canon EOS Kiss X2</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 50D" decoder_version="1">
+ <ID make="Canon" model="EOS 50D">Canon EOS 50D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="64" y="52" width="4752" height="3158"/>
+ <Sensor black="1020" white="13653"/>
+ <BlackAreas>
+ <Vertical x="0" width="60"/>
+ <Horizontal y="2" height="46"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 50D" mode="sRaw1">
+ <ID make="Canon" model="EOS 50D">Canon EOS 50D</ID>
+ <Crop x="0" y="0" width="3272" height="2178"/>
+ <Sensor black="0" white="53000"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 50D" mode="sRaw2">
+ <ID make="Canon" model="EOS 50D">Canon EOS 50D</ID>
+ <Crop x="0" y="0" width="2376" height="1584"/>
+ <Sensor black="0" white="53000"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 60D" decoder_version="1">
+ <ID make="Canon" model="EOS 60D">Canon EOS 60D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="146" y="54" width="0" height="0"/>
+ <Sensor black="2026" white="14200"/>
+ <BlackAreas>
+ <Vertical x="0" width="140"/>
+ <Horizontal y="4" height="46"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 60D" mode="sRaw1">
+ <ID make="Canon" model="EOS 60D">Canon EOS 60D</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 60D" mode="sRaw2">
+ <ID make="Canon" model="EOS 60D">Canon EOS 60D</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 70D" decoder_version="1">
+ <ID make="Canon" model="EOS 70D">Canon EOS 70D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="72" y="38" width="0" height="0"/>
+ <Sensor black="2026" white="13653" iso_min="0" iso_max="199"/>
+ <Sensor black="2026" white="16383" iso_min="6400" iso_max="25600"/>
+ <Sensor black="2026" white="15387"/>
+ <BlackAreas>
+ <Vertical x="0" width="72"/>
+ <Horizontal y="0" height="38"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 70D" mode="sRaw1">
+ <ID make="Canon" model="EOS 70D">Canon EOS 70D</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="53000"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 70D" mode="sRaw2">
+ <ID make="Canon" model="EOS 70D">Canon EOS 70D</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="53000"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 80D">
+ <ID make="Canon" model="EOS 80D">Canon EOS 80D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="266" y="42" width="-8" height="-4"/>
+ <Sensor black="512" white="11892" iso_list="100 125"/>
+ <Sensor black="512" white="10749" iso_list="160"/>
+ <Sensor black="511" white="14338" iso_list="200 250"/>
+ <Sensor black="2048" white="10749" iso_list="320 640 1250 2500 5000"/>
+ <Sensor black="2048" white="14338" iso_list="400 500 800 1000 1600 2000 3200 4000 6400 16000"/>
+ <Sensor black="2046" white="14338" iso_list="8000 25600"/>
+ <Sensor black="2045" white="14338" iso_list="10000"/>
+ <Sensor black="2049" white="14338" iso_list="12800"/>
+ <BlackAreas>
+ <Vertical x="0" width="263"/>
+ <Horizontal y="0" height="33"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 80D" mode="sRaw1" decoder_version="8">
+ <ID make="Canon" model="EOS 80D">Canon EOS 80D</ID>
+ <Crop x="28" y="10" width="0" height="0"/>
+ <Sensor black="0" white="48816" iso_list="320 640 1250 2500 5000"/>
+ <Sensor black="0" white="51936" iso_list="160"/>
+ <Sensor black="0" white="55680" iso_list="400 500 800 1000 1600 2000 3200 4000 6400 12800 16000 25600"/>
+ <Sensor black="0" white="55688" iso_list="8000 10000"/>
+ <Sensor black="0" white="58832" iso_list="100 125 200 250"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 80D" mode="sRaw2" decoder_version="7">
+ <ID make="Canon" model="EOS 80D">Canon EOS 80D</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="48468" iso_list="2500"/>
+ <Sensor black="0" white="48488" iso_list="1250"/>
+ <Sensor black="0" white="48492" iso_list="320"/>
+ <Sensor black="0" white="48496" iso_list="640"/>
+ <Sensor black="0" white="48588" iso_list="5000"/>
+ <Sensor black="0" white="51932" iso_list="160"/>
+ <Sensor black="0" white="55680" iso_list="400 500 800 1000 1600 2000 3200 4000 6400 12800 16000 25600"/>
+ <Sensor black="0" white="55688" iso_list="8000 10000"/>
+ <Sensor black="0" white="58832" iso_list="100 125 200 250"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 700D">
+ <ID make="Canon" model="EOS 700D">Canon EOS 700D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="72" y="52" width="0" height="0"/>
+ <Sensor black="2052" white="15000"/>
+ <Sensor black="2048" white="12277" iso_list="100"/>
+ <Sensor black="2048" white="11222" iso_list="160 320 640 1250 2500 5000"/>
+ <BlackAreas>
+ <Vertical x="0" width="70"/>
+ <Horizontal y="4" height="50"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Rebel T5i">Canon EOS REBEL T5i</Alias>
+ <Alias id="EOS Kiss X7i">Canon EOS Kiss X7i</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 750D">
+ <ID make="Canon" model="EOS 750D">Canon EOS 750D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="72" y="34" width="0" height="0"/>
+ <Sensor black="2047" white="11765" iso_min="0" iso_max = "199"/>
+ <Sensor black="2047" white="14580"/>
+ <Aliases>
+ <Alias id="EOS Rebel T6i">Canon EOS Rebel T6i</Alias>
+ <Alias id="EOS Kiss X8i">Canon EOS Kiss X8i</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 800D">
+ <ID make="Canon" model="EOS 800D">Canon EOS 800D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="266" y="42" width="-6" height="-4"/>
+ <Sensor black="2049" white="14338"/>
+ <Sensor black="511" white="11892" iso_list="100"/>
+ <Sensor black="511" white="14338" iso_list="200"/>
+ <BlackAreas>
+ <Vertical x="0" width="260"/>
+ <Horizontal y="2" height="36"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Rebel T7i">Canon EOS Rebel T7i</Alias>
+ <Alias id="EOS Kiss X9i">Canon EOS Kiss X9i</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 760D">
+ <ID make="Canon" model="EOS 760D">Canon EOS 760D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="72" y="34" width="0" height="0"/>
+ <Sensor black="2047" white="11765" iso_min="0" iso_max = "199"/>
+ <Sensor black="2047" white="14580"/>
+ <Aliases>
+ <Alias id="EOS Rebel T6s">Canon EOS Rebel T6s</Alias>
+ <Alias id="EOS 8000D">Canon EOS 8000D</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 77D">
+ <ID make="Canon" model="EOS 77D">Canon EOS 77D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="266" y="42" width="-6" height="-4"/>
+ <Sensor black="2048" white="14338"/>
+ <Sensor black="511" white="11892" iso_list="100"/>
+ <Sensor black="511" white="14338" iso_list="200"/>
+ <Sensor black="2037" white="14338" iso_list="51200"/>
+ <BlackAreas>
+ <Vertical x="0" width="260"/>
+ <Horizontal y="2" height="32"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS 9000D">Canon EOS 9000D</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 500D">
+ <ID make="Canon" model="EOS 500D">Canon EOS 500D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="62" y="30" width="4722" height="3142"/>
+ <Sensor black="1020" white="16000"/>
+ <BlackAreas>
+ <Vertical x="0" width="56"/>
+ <Horizontal y="2" height="22"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Rebel T1i">Canon EOS REBEL T1i</Alias>
+ <Alias id="EOS Kiss X3">Canon EOS Kiss X3</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 550D">
+ <ID make="Canon" model="EOS 550D">Canon EOS 550D</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="1">GREEN</Color>
+ <Color x="0" y="1">RED</Color>
+ </CFA>
+ <Crop x="148" y="54" width="0" height="0"/>
+ <Sensor black="2048" white="15831"/>
+ <BlackAreas>
+ <Vertical x="0" width="140"/>
+ <Horizontal y="4" height="44"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Rebel T2i">Canon EOS REBEL T2i</Alias>
+ <Alias id="EOS Kiss X4">Canon EOS Kiss X4</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 600D">
+ <ID make="Canon" model="EOS 600D">Canon EOS 600D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="146" y="54" width="0" height="0"/>
+ <Sensor black="2026" white="13584" iso_min="0" iso_max = "199"/>
+ <Sensor black="2026" white="15304"/>
+ <BlackAreas>
+ <Vertical x="0" width="140"/>
+ <Horizontal y="4" height="44"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Rebel T3i">Canon EOS REBEL T3i</Alias>
+ <Alias id="EOS Kiss X5">Canon EOS Kiss X5</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 650D">
+ <ID make="Canon" model="EOS 650D">Canon EOS 650D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="76" y="56" width="0" height="0"/>
+ <Sensor black="2026" white="13584" iso_min="0" iso_max = "199"/>
+ <Sensor black="2026" white="15304"/>
+ <BlackAreas>
+ <Vertical x="0" width="70"/>
+ <Horizontal y="4" height="44"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Rebel T4i">Canon EOS REBEL T4i</Alias>
+ <Alias id="EOS Kiss X6i">Canon EOS Kiss X6i</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 5D">
+ <ID make="Canon" model="EOS 5D">Canon EOS 5D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="90" y="34" width="4386" height="2920"/>
+ <Sensor black="127" white="3692"/>
+ <BlackAreas>
+ <Vertical x="0" width="88"/>
+ <Horizontal y="2" height="30"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 5D Mark II" decoder_version="1">
+ <ID make="Canon" model="EOS 5D Mark II">Canon EOS 5D Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="158" y="51" width="5634" height="3753"/>
+ <Sensor black="1024" white="12995" iso_list="160 320 640 1250"/>
+ <Sensor black="1024" white="15950"/>
+ <BlackAreas>
+ <Vertical x="0" width="156"/>
+ <Horizontal y="2" height="48"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 5D Mark II" mode="sRaw1">
+ <ID make="Canon" model="EOS 5D Mark II">Canon EOS 5D Mark II</ID>
+ <Crop x="0" y="0" width="3872" height="2574"/>
+ <Sensor black="0" white="57200" iso_list="160 320 640 1250"/>
+ <Sensor black="0" white="64948"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 5D Mark II" mode="sRaw2">
+ <ID make="Canon" model="EOS 5D Mark II">Canon EOS 5D Mark II</ID>
+ <Crop x="0" y="0" width="2808" height="1872"/>
+ <Sensor black="0" white="57200" iso_list="160 320 640 1250"/>
+ <Sensor black="0" white="64948"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 5D Mark III" decoder_version="2">
+ <ID make="Canon" model="EOS 5D Mark III">Canon EOS 5D Mark III</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="124" y="82" width="-2" height="0"/>
+ <Sensor black="2060" white="16383"/>
+ <Sensor black="2060" white="15700" iso_list="400 500 1600"/>
+ <Sensor black="2060" white="15200" iso_list="100 125 200 250 800 2000"/>
+ <Sensor black="2060" white="15100" iso_list="2500 10000"/>
+ <Sensor black="2060" white="13700" iso_list="160 320 1250"/>
+ <Sensor black="2060" white="14200" iso_list="640 5000"/>
+ <BlackAreas>
+ <Vertical x="0" width="120"/>
+ <Horizontal y="2" height="78"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 5D Mark III" mode="sRaw1">
+ <ID make="Canon" model="EOS 5D Mark III">Canon EOS 5D Mark III</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="44112" iso_list="160 320 640 1250 2500 5000 10000"/>
+ <Sensor black="0" white="50300" iso_list="100 20000"/>
+ <Sensor black="0" white="55128" iso_list="25600 51200 65535"/>
+ <Sensor black="0" white="53220"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 5D Mark III" mode="sRaw2">
+ <ID make="Canon" model="EOS 5D Mark III">Canon EOS 5D Mark III</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="44112" iso_list="160 320 640 1250 2500 5000 10000"/>
+ <Sensor black="0" white="51300" iso_list="250"/>
+ <Sensor black="0" white="55028" iso_list="25600 51200 65535"/>
+ <Sensor black="0" white="53000"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 5D Mark IV">
+ <ID make="Canon" model="EOS 5D Mark IV">Canon EOS 5D Mark IV</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="136" y="44" width="0" height="0"/>
+ <Sensor black="2049" white="14448"/>
+ <Sensor black="513" white="14008" iso_list="50 100 125"/>
+ <Sensor black="512" white="10838" iso_list="160"/>
+ <Sensor black="512" white="14448" iso_list="200 250"/>
+ <Sensor black="2048" white="10838" iso_list="320 640 1250 2500 5000 10000 20000"/>
+ <Sensor black="2049" white="13533" iso_list="102400"/>
+ <BlackAreas>
+ <Vertical x="0" width="134"/>
+ <Horizontal y="0" height="40"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 5DS" decoder_version="6">
+ <ID make="Canon" model="EOS 5DS">Canon EOS 5DS</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="160" y="64" width="-2" height="0"/>
+ <Sensor black="2048" white="15181"/>
+ <Sensor black="2048" white="14466" iso_list="50 100"/>
+ <BlackAreas>
+ <Vertical x="0" width="150"/>
+ <Horizontal y="2" height="60"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 5DS R" decoder_version="6">
+ <ID make="Canon" model="EOS 5DS R">Canon EOS 5DS R</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="160" y="64" width="-2" height="0"/>
+ <Sensor black="2048" white="15181"/>
+ <Sensor black="2048" white="14466" iso_list="50 100"/>
+ <BlackAreas>
+ <Vertical x="0" width="150"/>
+ <Horizontal y="2" height="60"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 6D" decoder_version="2">
+ <ID make="Canon" model="EOS 6D">Canon EOS 6D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="74" y="40" width="0" height="-2"/>
+ <Sensor black="2048" white="15000"/>
+ <Sensor black="2047" white="15000" iso_list="50 100 125 200 250 16000"/>
+ <Sensor black="2047" white="13100" iso_list="160"/>
+ <Sensor black="2047" white="13000" iso_list="320"/>
+ <Sensor black="2048" white="13000" iso_list="640 1250 2500 5000 10000 20000"/>
+ <Sensor black="2048" white="16000" iso_list="51200 102400"/>
+ <BlackAreas>
+ <Vertical x="0" width="68"/>
+ <Horizontal y="2" height="36"/>
+ </BlackAreas>
+ </Camera>
+ <!---Guess -->
+ <Camera make="Canon" model="Canon EOS 6D" mode="sRaw1" decoder_version="3">
+ <ID make="Canon" model="EOS 6D">Canon EOS 6D</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="48664"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <!---Guess -->
+ <Camera make="Canon" model="Canon EOS 6D" mode="sRaw2">
+ <ID make="Canon" model="EOS 6D">Canon EOS 6D</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="48664"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 6D Mark II" decoder_version="9">
+ <ID make="Canon" model="EOS 6D Mark II">Canon EOS 6D Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="128" y="52" width="-4" height="-4"/>
+ <Sensor black="2049" white="14558"/>
+ <Sensor black="513" white="14558" iso_list="50 100 125 200 250"/>
+ <Sensor black="513" white="11301" iso_list="160"/>
+ <Sensor black="2049" white="11301" iso_list="320 640 1250 2500 5000 10000"/>
+ <BlackAreas>
+ <Vertical x="2" width="116"/>
+ <Horizontal y="8" height="32"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 6D Mark II" mode="sRaw1" decoder_version="9">
+ <ID make="Canon" model="EOS 6D Mark II">Canon EOS 6D Mark II</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="16383"/> <!-- don't know -->
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 6D Mark II" mode="sRaw2" decoder_version="9">
+ <ID make="Canon" model="EOS 6D Mark II">Canon EOS 6D Mark II</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="16383"/> <!-- don't know -->
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 7D" decoder_version="1">
+ <ID make="Canon" model="EOS 7D">Canon EOS 7D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="158" y="52" width="5202" height="3464"/>
+ <Sensor black="1025" white="8150" iso_min="12800" iso_max="12800"/>
+ <Sensor black="2050" white="16300"/>
+ <BlackAreas>
+ <Vertical x="8" width="156"/>
+ <Horizontal y="32" height="18"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 7D" mode="sRaw1">
+ <ID make="Canon" model="EOS 7D">Canon EOS 7D</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="44200" iso_list="100 125 160 320 640 1250"/>
+ <Sensor black="0" white="54000"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 7D" mode="sRaw2">
+ <ID make="Canon" model="EOS 7D">Canon EOS 7D</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="44200" iso_list="100 125 160 320 640 1250"/>
+ <Sensor black="0" white="54000"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 7D Mark II">
+ <ID make="Canon" model="EOS 7D Mark II">Canon EOS 7D Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="72" y="38" width="0" height="0"/>
+ <Sensor black="2047" white="13400" iso_list="100 125 160 200 250 320"/>
+ <Sensor black="2047" white="15100"/>
+ <BlackAreas>
+ <Vertical x="4" width="64"/>
+ <Horizontal y="24" height="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 7D Mark II" mode="sRaw1">
+ <ID make="Canon" model="EOS 7D Mark II">Canon EOS 7D Mark II</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 7D Mark II" mode="sRaw2">
+ <ID make="Canon" model="EOS 7D Mark II">Canon EOS 7D Mark II</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 1000D">
+ <ID make="Canon" model="EOS 1000D">Canon EOS 1000D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="42" y="18" width="3906" height="2602"/>
+ <Sensor black="255" white="3650" iso_min="0" iso_max="199"/>
+ <Sensor black="255" white="4036"/>
+ <BlackAreas>
+ <Vertical x="0" width="41"/>
+ <Horizontal y="2" height="14"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Digital Rebel XS">Canon EOS DIGITAL REBEL XS</Alias>
+ <Alias id="EOS Kiss Digital F">Canon EOS Kiss Digital F</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 1100D">
+ <ID make="Canon" model="EOS 1100D">Canon EOS 1100D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="64" y="20" width="0" height="0"/>
+ <Sensor black="2036" white="15500"/>
+ <BlackAreas>
+ <Vertical x="0" width="58"/>
+ <Horizontal y="4" height="12"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Rebel T3">Canon EOS REBEL T3</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 1200D">
+ <ID make="Canon" model="EOS 1200D">Canon EOS 1200D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="146" y="54" width="0" height="0"/>
+ <Sensor black="2046" white="12279" iso_min="0" iso_max = "199"/>
+ <Sensor black="2046" white="15000"/>
+ <BlackAreas>
+ <Vertical x="0" width="140"/>
+ <Horizontal y="4" height="44"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Rebel T5">Canon EOS REBEL T5</Alias>
+ <Alias id="EOS Kiss X70">Canon EOS Kiss X70</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 1300D">
+ <ID make="Canon" model="EOS 1300D">Canon EOS 1300D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="146" y="54" width="0" height="0"/>
+ <Sensor black="2048" white="15000"/>
+ <Sensor black="2046" white="12279" iso_list="100"/>
+ <Sensor black="2046" white="15000" iso_list="200"/>
+ <Sensor black="2047" white="15000" iso_list="3200"/>
+ <BlackAreas>
+ <Vertical x="0" width="140"/>
+ <Horizontal y="4" height="44"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Rebel T6">Canon EOS Rebel T6</Alias>
+ <Alias id="EOS Kiss X80">Canon EOS Kiss X80</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS 400D DIGITAL">
+ <ID make="Canon" model="EOS 400D">Canon EOS 400D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="42" y="18" width="3906" height="2602"/>
+ <Sensor black="255" white="3726"/>
+ <BlackAreas>
+ <Vertical x="0" width="40"/>
+ <Horizontal y="4" height="12"/>
+ </BlackAreas>
+ <Aliases>
+ <Alias id="EOS Digital Rebel XTi">Canon EOS DIGITAL REBEL XTi</Alias>
+ <Alias id="EOS Kiss Digital X">Canon EOS Kiss Digital X</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS M">
+ <ID make="Canon" model="EOS M">Canon EOS M</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="76" y="56" width="0" height="0"/>
+ <Sensor black="2026" white="13584" iso_min="0" iso_max = "199"/>
+ <Sensor black="2026" white="15304"/>
+ <BlackAreas>
+ <Vertical x="0" width="70"/>
+ <Horizontal y="4" height="44"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS M2">
+ <ID make="Canon" model="EOS M2">Canon EOS M2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="72" y="52" width="0" height="0"/>
+ <Sensor black="2026" white="13584" iso_min="0" iso_max = "199"/>
+ <Sensor black="2026" white="15304"/>
+ <BlackAreas>
+ <Vertical x="0" width="70"/>
+ <Horizontal y="4" height="44"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS M3">
+ <ID make="Canon" model="EOS M3">Canon EOS M3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="72" y="34" width="0" height="0"/>
+ <Sensor black="2048" white="16000"/>
+ <BlackAreas>
+ <Vertical x="2" width="68"/>
+ <Horizontal y="2" height="30"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS M5">
+ <ID make="Canon" model="EOS M5">Canon EOS M5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="266" y="38" width="0" height="0"/>
+ <Sensor black="2048" white="16000"/>
+ <Sensor black="512" white="16000" iso_list="100 125 200 250"/>
+ <Sensor black="512" white="13200" iso_list="160"/>
+ <Sensor black="2048" white="13200" iso_list="320 640 1250 2500 5000"/>
+ <BlackAreas>
+ <Vertical x="4" width="260"/>
+ <Horizontal y="4" height="30"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS M6">
+ <ID make="Canon" model="EOS M6">Canon EOS M6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="266" y="42" width="-6" height="-4"/>
+ <Sensor black="2048" white="16000"/>
+ <Sensor black="512" white="16000" iso_list="100 125 200 250"/>
+ <Sensor black="512" white="13200" iso_list="160"/>
+ <Sensor black="2048" white="13200" iso_list="320 640 1250 2500 5000"/>
+ <BlackAreas>
+ <Vertical x="4" width="260"/>
+ <Horizontal y="4" height="30"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS M10">
+ <ID make="Canon" model="EOS M10">Canon EOS M10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="72" y="52" width="0" height="-2"/>
+ <Sensor black="2048" white="16000"/>
+ <BlackAreas>
+ <Vertical x="2" width="68"/>
+ <Horizontal y="2" height="40"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS M100">
+ <ID make="Canon" model="EOS M100">Canon EOS M100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="266" y="42" width="-6" height="-4"/>
+ <Sensor black="2048" white="16000"/>
+ <Sensor black="512" white="16000" iso_list="100 125 200 250"/>
+ <Sensor black="512" white="13200" iso_list="160"/>
+ <Sensor black="2048" white="13200" iso_list="320 640 1250 2500 5000"/>
+ <BlackAreas>
+ <Vertical x="4" width="260"/>
+ <Horizontal y="4" height="30"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D" decoder_version="8">
+ <ID make="Canon" model="EOS-1D">Canon EOS-1D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3588"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1DS" decoder_version="8">
+ <ID make="Canon" model="EOS-1Ds">Canon EOS-1Ds</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3500"/>
+ </Camera>
+ <Camera make="Canon" model="EOS D2000C" decoder_version="8">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="96" white="4095"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D Mark II">
+ <ID make="Canon" model="EOS-1D Mark II">Canon EOS-1D Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="74" y="12" width="3522" height="2348"/>
+ <Sensor black="127" white="3700"/>
+ <BlackAreas>
+ <Vertical x="0" width="72"/>
+ <Horizontal y="2" height="8"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="68"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D Mark II N">
+ <ID make="Canon" model="EOS-1D Mark II N">Canon EOS-1D Mark II N</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="74" y="12" width="3522" height="2348"/>
+ <Sensor black="127" white="3700"/>
+ <BlackAreas>
+ <Vertical x="0" width="72"/>
+ <Horizontal y="2" height="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D Mark III" decoder_version="1">
+ <ID make="Canon" model="EOS-1D Mark III">Canon EOS-1D Mark III</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="78" y="20" width="3906" height="2600"/>
+ <Sensor black="1023" white="15100"/>
+ <BlackAreas>
+ <Vertical x="2" width="74"/>
+ <Horizontal y="4" height="14"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D Mark III" mode="sRaw1">
+ <ID make="Canon" model="EOS-1D Mark III">Canon EOS-1D Mark III</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D Mark III" mode="sRaw2">
+ <ID make="Canon" model="EOS-1D Mark III">Canon EOS-1D Mark III</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D Mark IV" decoder_version="1">
+ <ID make="Canon" model="EOS-1D Mark IV">Canon EOS-1D Mark IV</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="144" y="46" width="-64" height="-2"/>
+ <Sensor black="2000" white="13000"/>
+ <BlackAreas>
+ <Vertical x="0" width="140"/>
+ <Horizontal y="26" height="16"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D Mark IV" mode="sRaw1">
+ <ID make="Canon" model="EOS-1D Mark IV">Canon EOS-1D Mark IV</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D Mark IV" mode="sRaw2">
+ <ID make="Canon" model="EOS-1D Mark IV">Canon EOS-1D Mark IV</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1Ds Mark II">
+ <ID make="Canon" model="EOS-1Ds Mark II">Canon EOS-1Ds Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="98" y="13" width="5010" height="3336"/>
+ <Sensor black="126" white="4060"/>
+ <BlackAreas>
+ <Vertical x="0" width="96"/>
+ <Horizontal y="2" height="10"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="68"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1Ds Mark III" decoder_version="1">
+ <ID make="Canon" model="EOS-1Ds Mark III">Canon EOS-1Ds Mark III</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="62" y="20" width="5640" height="3752"/>
+ <Sensor black="1021" white="15100"/>
+ <BlackAreas>
+ <Vertical x="0" width="60"/>
+ <Horizontal y="4" height="14"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1Ds Mark III" mode="sRaw1">
+ <ID make="Canon" model="EOS-1Ds Mark III">Canon EOS-1Ds Mark III</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1Ds Mark III" mode="sRaw2">
+ <ID make="Canon" model="EOS-1Ds Mark III">Canon EOS-1Ds Mark III</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D X" decoder_version="1">
+ <ID make="Canon" model="EOS-1D X">Canon EOS-1D X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="128" y="102" width="0" height="-2"/>
+ <Sensor black="2050" white="15100"/>
+ <BlackAreas>
+ <Vertical x="0" width="120"/>
+ <Horizontal y="0" height="98"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D X" mode="sRaw1">
+ <ID make="Canon" model="EOS-1D X">Canon EOS-1D X</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D X" mode="sRaw2">
+ <ID make="Canon" model="EOS-1D X">Canon EOS-1D X</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D X Mark II">
+ <ID make="Canon" model="EOS-1D X Mark II">Canon EOS-1D X Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="74" y="40" width="-2" height="0"/>
+ <Sensor black="2048" white="14888"/>
+ <Sensor black="512" white="13898" iso_list="50 100"/>
+ <Sensor black="512" white="14888" iso_list="125 160 200 250"/>
+ <Sensor black="2049" white="14888" iso_list="1600 2500 51200"/>
+ <Sensor black="2050" white="13533" iso_list="102400"/>
+ <Sensor black="2048" white="13533" iso_list="204800"/>
+ <Sensor black="2049" white="13533" iso_list="409600"/>
+ <BlackAreas>
+ <Vertical x="0" width="68"/>
+ <Horizontal y="0" height="36"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D X Mark II" mode="sRaw1">
+ <ID make="Canon" model="EOS-1D X Mark II">Canon EOS-1D X Mark II</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon EOS-1D X Mark II" mode="sRaw2">
+ <ID make="Canon" model="EOS-1D X Mark II">Canon EOS-1D X Mark II</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="sraw_new" value=""/>
+ <Hint name="invert_sraw_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot Pro1">
+ <ID make="Canon" model="PowerShot Pro1">Canon PowerShot Pro1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="4" y="6" width="-52" height="-6"/>
+ <Sensor black="129" white="4095"/>
+ <BlackAreas>
+ <Vertical x="3294" width="50"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="96"/>
+ <Hint name="wb_mangle" value="true"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot Pro70" supported="no">
+ <ID make="Canon" model="PowerShot Pro70">Canon PowerShot Pro70</ID>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G1">
+ <ID make="Canon" model="PowerShot G1">Canon PowerShot G1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">FUJI_GREEN</Color>
+ <Color x="1" y="0">MAGENTA</Color>
+ <Color x="0" y="1">YELLOW</Color>
+ <Color x="1" y="1">CYAN</Color>
+ </CFA>
+ <Crop x="4" y="8" width="-52" height="-2"/>
+ <Sensor black="31" white="1023"/>
+ <BlackAreas>
+ <Vertical x="2094" width="50"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="no_decompressed_lowbits" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G2">
+ <ID make="Canon" model="PowerShot G2">Canon PowerShot G2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="12" y="6" width="-52" height="-2"/>
+ <Sensor black="0" white="1023"/>
+ <BlackAreas>
+ <Vertical x="2326" width="50"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="no_decompressed_lowbits" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G3">
+ <ID make="Canon" model="PowerShot G3">Canon PowerShot G3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="12" y="6" width="-52" height="-2"/>
+ <Sensor black="0" white="4095"/>
+ <BlackAreas>
+ <Vertical x="2326" width="50"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G3 X">
+ <ID make="Canon" model="PowerShot G3 X">Canon PowerShot G3 X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="96" y="17" width="0" height="0"/>
+ <Sensor black="2047" white="16000"/>
+ <BlackAreas>
+ <Vertical x="0" width="90"/>
+ <Horizontal y="0" height="16"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G5">
+ <ID make="Canon" model="PowerShot G5">Canon PowerShot G5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="12" y="6" width="-44" height="-2"/>
+ <Sensor black="0" white="4095"/>
+ <BlackAreas>
+ <Vertical x="2632" width="40"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G5 X">
+ <ID make="Canon" model="PowerShot G5 X">Canon PowerShot G5 X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="96" y="17" width="0" height="0"/>
+ <Sensor black="2047" white="16000"/>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G6">
+ <ID make="Canon" model="PowerShot G6">Canon PowerShot G6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="44" y="12" width="-4" height="-4"/>
+ <Sensor black="128" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="40"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="96"/>
+ <Hint name="wb_mangle" value="true"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G7 X">
+ <ID make="Canon" model="PowerShot G7 X">Canon PowerShot G7 X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="96" y="18" width="0" height="0"/>
+ <Sensor black="511" white="4000"/>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G7 X Mark II">
+ <ID make="Canon" model="PowerShot G7 X Mark II">Canon PowerShot G7 X Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="96" y="22" width="0" height="0"/>
+ <Sensor black="2047" white="16000"/>
+ <Sensor black="2046" white="16000" iso_list="1600 2000 2500"/>
+ <Sensor black="2048" white="16000" iso_list="3200 4000"/>
+ <Sensor black="2049" white="16000" iso_list="5000 6400 8000"/>
+ <Sensor black="2050" white="16000" iso_list="10000 12800"/>
+ <BlackAreas>
+ <Vertical x="0" width="76"/>
+ <Horizontal y="0" height="14"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G1 X">
+ <ID make="Canon" model="PowerShot G1 X">Canon PowerShot G1 X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="82" y="52" width="-14" height="0"/>
+ <Sensor black="0" white="16383"/>
+ <BlackAreas>
+ <Vertical x="0" width="68"/>
+ <Horizontal y="0" height="46"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G1 X Mark II">
+ <ID make="Canon" model="PowerShot G1 X Mark II">Canon PowerShot G1 X Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="82" y="52" width="-14" height="0"/>
+ <Sensor black="0" white="16000"/>
+ <BlackAreas>
+ <Vertical x="0" width="68"/>
+ <Horizontal y="0" height="46"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G12">
+ <ID make="Canon" model="PowerShot G12">Canon PowerShot G12</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="54" y="14" width="-12" height="-18"/>
+ <Sensor black="120" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="50"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G11">
+ <ID make="Canon" model="PowerShot G11">Canon PowerShot G11</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="10" y="18" width="-56" height="-14"/>
+ <Sensor black="120" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="10"/>
+ <Vertical x="3696" width="48"/>
+ <Horizontal y="0" height="14"/>
+ <Horizontal y="2778" height="6"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G10">
+ <ID make="Canon" model="PowerShot G10">Canon PowerShot G10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="12" y="13" width="4432" height="3323"/>
+ <Sensor black="128" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="10"/>
+ <Horizontal y="0" height="8"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G9">
+ <ID make="Canon" model="PowerShot G9">Canon PowerShot G9</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="48" y="12" width="4032" height="3024"/>
+ <Sensor black="125" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="46"/>
+ <Horizontal y="0" height="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G9 X">
+ <ID make="Canon" model="PowerShot G9 X">Canon PowerShot G9 X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="96" y="18" width="0" height="0"/>
+ <Sensor black="2047" white="16000"/>
+ <BlackAreas>
+ <Vertical x="0" width="70"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G9 X Mark II">
+ <ID make="Canon" model="PowerShot G9 X Mark II">Canon PowerShot G9 X Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="104" y="22" width="-6" height="-6"/>
+ <Sensor black="2048" white="16000"/>
+ <BlackAreas>
+ <Vertical x="0" width="76"/>
+ <Horizontal y="0" height="14"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G15">
+ <ID make="Canon" model="PowerShot G15">Canon PowerShot G15</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="106" y="12" width="-10" height="-66"/>
+ <Sensor black="500" white="2800" iso_min="12800" iso_max="12800"/>
+ <Sensor black="128" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="100"/>
+ <Horizontal y="3062" height="60"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot G16" decoder_version="4">
+ <ID make="Canon" model="PowerShot G16">Canon PowerShot G16</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="96" y="18" width="-24" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="80"/>
+ <Horizontal y="0" height="16"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot SX1 IS">
+ <ID make="Canon" model="PowerShot SX1 IS">Canon PowerShot SX1 IS</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="192" y="12" width="3958" height="2760"/>
+ <Sensor black="125" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="188"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot S30">
+ <ID make="Canon" model="PowerShot S30">Canon PowerShot S30</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="4" y="8" width="-52" height="-2"/>
+ <Sensor black="31" white="1023"/>
+ <BlackAreas>
+ <Vertical x="2094" width="50"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="no_decompressed_lowbits" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot S40">
+ <ID make="Canon" model="PowerShot S40">Canon PowerShot S40</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="12" y="6" width="-52" height="-2"/>
+ <Sensor black="0" white="1023"/>
+ <BlackAreas>
+ <Vertical x="2326" width="50"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="no_decompressed_lowbits" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot S45">
+ <ID make="Canon" model="PowerShot S45">Canon PowerShot S45</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="12" y="6" width="-52" height="-2"/>
+ <Sensor black="129" white="4095"/>
+ <BlackAreas>
+ <Vertical x="2326" width="50"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot S50">
+ <ID make="Canon" model="PowerShot S50">Canon PowerShot S50</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="12" y="6" width="-44" height="-2"/>
+ <Sensor black="129" white="4095"/>
+ <BlackAreas>
+ <Vertical x="2632" width="40"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot S60">
+ <ID make="Canon" model="PowerShot S60">Canon PowerShot S60</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="12" y="6" width="-44" height="-2"/>
+ <Sensor black="129" white="4095"/>
+ <BlackAreas>
+ <Vertical x="2632" width="40"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="96"/>
+ <Hint name="wb_mangle" value="true"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot S70">
+ <ID make="Canon" model="PowerShot S70">Canon PowerShot S70</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="44" y="12" width="-4" height="-4"/>
+ <Sensor black="129" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="40"/>
+ <Horizontal y="0" height="10"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="96"/>
+ <Hint name="wb_mangle" value="true"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot S90">
+ <ID make="Canon" model="PowerShot S90">Canon PowerShot S90</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="10" y="18" width="-54" height="-10"/>
+ <Sensor black="125" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="6"/>
+ <Horizontal y="0" height="14"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot S95">
+ <ID make="Canon" model="PowerShot S95">Canon PowerShot S95</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="66" y="24" width="-20" height="-24"/>
+ <Sensor black="125" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="50"/>
+ <Vertical x="3738" width="6"/>
+ <Horizontal y="0" height="10"/>
+ <Horizontal y="2774" height="10"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot S100">
+ <ID make="Canon" model="PowerShot S100">Canon PowerShot S100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="104" y="12" width="-10" height="-66"/>
+ <Sensor black="125" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="100"/>
+ <Horizontal y="0" height="10"/>
+ <Horizontal y="3062" height="60"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot S110">
+ <ID make="Canon" model="PowerShot S110">Canon PowerShot S110</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="106" y="12" width="-10" height="-66"/>
+ <Sensor black="500" white="3072" iso_min="12800" iso_max="12800"/>
+ <Sensor black="128" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="100"/>
+ <Horizontal y="3062" height="60"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot S120">
+ <ID make="Canon" model="PowerShot S120">Canon PowerShot S120</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="121" y="30" width="-47" height="-14"/>
+ <Sensor black="0" white="4000"/>
+ <BlackAreas>
+ <Vertical x="0" width="74"/>
+ <Horizontal y="0" height="12"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot SX50 HS">
+ <ID make="Canon" model="PowerShot SX50 HS">Canon PowerShot SX50 HS</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="100" y="20" width="-10" height="0"/>
+ <Sensor black="127" white="4095"/>
+ <BlackAreas>
+ <Vertical x="6" width="70"/>
+ <Horizontal y="0" height="16"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot SX60 HS">
+ <ID make="Canon" model="PowerShot SX60 HS">Canon PowerShot SX60 HS</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="112" y="26" width="-24" height="-10"/>
+ <Sensor black="128" white="4000"/>
+ <BlackAreas>
+ <Vertical x="0" width="70"/>
+ <Horizontal y="0" height="16"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="wb_offset" value="142"/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D100" mode="12bit-compressed">
+ <ID make="Nikon" model="D100">Nikon D100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="2" y="0" width="3030" height="2024"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D100" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D100">Nikon D100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="2" y="0" width="3030" height="2024"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D1" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D1">Nikon D1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="2000" height="1312"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="nikon_wb_adjustment" value="true"/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D1H" mode="12bit-compressed">
+ <ID make="Nikon" model="D1H">Nikon D1H</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="2012" height="1324"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D1H" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D1H">Nikon D1H</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="2012" height="1324"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D1X" mode="12bit-compressed">
+ <ID make="Nikon" model="D1X">Nikon D1X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4024" height="1324"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="pixel_aspect_ratio" value="0.5"/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D1X" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D1X">Nikon D1X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4024" height="1324"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="pixel_aspect_ratio" value="0.5"/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D200" mode="12bit-compressed">
+ <ID make="Nikon" model="D200">Nikon D200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="2" y="0" width="3898" height="2616"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D200" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D200">Nikon D200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="2" y="0" width="3898" height="2616"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D2H" mode="12bit-compressed">
+ <ID make="Nikon" model="D2H">Nikon D2H</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="6" y="0" width="-8" height="1648"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D2H" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D2H">Nikon D2H</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="6" y="0" width="-8" height="1648"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D2Hs" mode="12bit-compressed">
+ <ID make="Nikon" model="D2Hs">Nikon D2Hs</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="6" y="0" width="-8" height="1648"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D2Hs" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D2Hs">Nikon D2Hs</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="6" y="0" width="-8" height="1648"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D2X" mode="12bit-compressed">
+ <ID make="Nikon" model="D2X">Nikon D2X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="-8"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D2X" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D2X">Nikon D2X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="-8"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3" mode="14bit-compressed">
+ <ID make="Nikon" model="D3">Nikon D3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="4282" height="2844"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D3">Nikon D3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="4282" height="2844"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3" mode="12bit-compressed">
+ <ID make="Nikon" model="D3">Nikon D3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="4282" height="2844"/>
+ <Sensor black="0" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D3">Nikon D3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="4282" height="2844"/>
+ <Sensor black="0" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3S" mode="14bit-compressed">
+ <ID make="Nikon" model="D3S">Nikon D3S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3S" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D3S">Nikon D3S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3S" mode="12bit-compressed">
+ <ID make="Nikon" model="D3S">Nikon D3S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3S" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D3S">Nikon D3S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3X" mode="14bit-compressed">
+ <ID make="Nikon" model="D3X">Nikon D3X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="6080" height="4044"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3X" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D3X">Nikon D3X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="6080" height="4044"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3X" mode="12bit-compressed">
+ <ID make="Nikon" model="D3X">Nikon D3X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="6080" height="4044"/>
+ <Sensor black="0" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3X" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D3X">Nikon D3X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="6080" height="4044"/>
+ <Sensor black="0" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D300" mode="14bit-compressed">
+ <ID make="Nikon" model="D300">Nikon D300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4320" height="2868"/>
+ <Sensor black="0" white="15236"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D300" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D300">Nikon D300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4320" height="2868"/>
+ <Sensor black="0" white="15236"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D300" mode="12bit-compressed">
+ <ID make="Nikon" model="D300">Nikon D300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4320" height="2868"/>
+ <Sensor black="0" white="3808"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D300" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D300">Nikon D300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4320" height="2868"/>
+ <Sensor black="0" white="3808"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D300S" mode="14bit-compressed">
+ <ID make="Nikon" model="D300S">Nikon D300S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4320" height="2868"/>
+ <Sensor black="0" white="15236"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D300S" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D300S">Nikon D300S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4320" height="2868"/>
+ <Sensor black="0" white="15236"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D300S" mode="12bit-compressed">
+ <ID make="Nikon" model="D300S">Nikon D300S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4320" height="2868"/>
+ <Sensor black="0" white="3808"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D300S" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D300S">Nikon D300S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4320" height="2868"/>
+ <Sensor black="0" white="3808"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3000" mode="12bit-compressed">
+ <ID make="Nikon" model="D3000">Nikon D3000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3898" height="2610"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3200" mode="12bit-compressed">
+ <ID make="Nikon" model="D3200">Nikon D3200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-48" height="0"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3300" mode="12bit-compressed">
+ <ID make="Nikon" model="D3300">Nikon D3300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-8" height="-8"/>
+ <Sensor black="150" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3300" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D3300">Nikon D3300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-8" height="-8"/>
+ <Sensor black="150" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3400" mode="12bit-compressed">
+ <ID make="Nikon" model="D3400">Nikon D3400</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D4" mode="14bit-compressed">
+ <ID make="Nikon" model="D4">Nikon D4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D4" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D4">Nikon D4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D4" mode="12bit-compressed">
+ <ID make="Nikon" model="D4">Nikon D4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D4" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D4">Nikon D4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5" mode="14bit-compressed">
+ <ID make="Nikon" model="D5">Nikon D5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="400" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D5">Nikon D5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="400" white="15520"/>
+ <Hints>
+ <Hint name="msb_override" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5" mode="12bit-compressed">
+ <ID make="Nikon" model="D5">Nikon D5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="100" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D5">Nikon D5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="100" white="3880"/>
+ <Hints>
+ <Hint name="msb_override" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON Df" mode="14bit-compressed">
+ <ID make="Nikon" model="Df">Nikon Df</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="15520"/>
+ <BlackAreas>
+ <Vertical x="4984" width="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON Df" mode="14bit-uncompressed">
+ <ID make="Nikon" model="Df">Nikon Df</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="15520"/>
+ <BlackAreas>
+ <Vertical x="4984" width="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON Df" mode="12bit-compressed">
+ <ID make="Nikon" model="Df">Nikon Df</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="3880"/>
+ <BlackAreas>
+ <Vertical x="4984" width="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON Df" mode="12bit-uncompressed">
+ <ID make="Nikon" model="Df">Nikon Df</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="3880"/>
+ <BlackAreas>
+ <Vertical x="4984" width="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5100" mode="14bit-compressed" decoder_version="2">
+ <ID make="Nikon" model="D5100">Nikon D5100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-46" height="0"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5100" mode="14bit-uncompressed" decoder_version="2"> <!-- the camera lies, see https://redmine.darktable.org/issues/11268 -->
+ <ID make="Nikon" model="D5100">Nikon D5100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-46" height="0"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D3100" mode="12bit-compressed" decoder_version="2">
+ <ID make="Nikon" model="D3100">Nikon D3100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="12" y="2" width="-26" height="-6"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D40" mode="12bit-compressed">
+ <ID make="Nikon" model="D40">Nikon D40</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3038" height="2014"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D40" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D40">Nikon D40</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3038" height="2014"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D40X" mode="12bit-compressed">
+ <ID make="Nikon" model="D40X">Nikon D40X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="4" y="0" width="3896" height="2613"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D40X" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D40X">Nikon D40X</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="4" y="0" width="3896" height="2613"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D50" mode="12bit-compressed">
+ <ID make="Nikon" model="D50">Nikon D50</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-2" height="-2"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D500" mode="14bit-compressed">
+ <ID make="Nikon" model="D500">Nikon D500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="2" width="-2" height="-2"/>
+ <Sensor black="400" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D500" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D500">Nikon D500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="2" width="-2" height="-2"/>
+ <Sensor black="400" white="15520"/>
+ <Hints>
+ <Hint name="msb_override" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D500" mode="12bit-compressed">
+ <ID make="Nikon" model="D500">Nikon D500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="2" width="-2" height="-2"/>
+ <Sensor black="100" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D500" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D500">Nikon D500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="2" width="-2" height="-2"/>
+ <Sensor black="100" white="3880"/>
+ <Hints>
+ <Hint name="msb_override" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5000" mode="12bit-compressed">
+ <ID make="Nikon" model="D5000">Nikon D5000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4310" height="2868"/>
+ <Sensor black="0" white="3767"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5000" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D5000">Nikon D5000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4310" height="2868"/>
+ <Sensor black="0" white="3767"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5200" mode="14bit-compressed">
+ <ID make="Nikon" model="D5200">Nikon D5200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5300" mode="12bit-compressed">
+ <ID make="Nikon" model="D5300">Nikon D5300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5300" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D5300">Nikon D5300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5300" mode="14bit-compressed">
+ <ID make="Nikon" model="D5300">Nikon D5300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="600" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5300" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D5300">Nikon D5300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="600" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5500" mode="12bit-compressed">
+ <ID make="Nikon" model="D5500">Nikon D5500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5500" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D5500">Nikon D5500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5500" mode="14bit-compressed">
+ <ID make="Nikon" model="D5500">Nikon D5500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="600" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5500" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D5500">Nikon D5500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="600" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5600" mode="12bit-compressed">
+ <ID make="Nikon" model="D5600">Nikon D5600</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5600" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D5600">Nikon D5600</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5600" mode="14bit-compressed">
+ <ID make="Nikon" model="D5600">Nikon D5600</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="600" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D5600" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D5600">Nikon D5600</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="600" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D60" mode="12bit-compressed">
+ <ID make="Nikon" model="D60">Nikon D60</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3900" height="2613"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D60" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D60">Nikon D60</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3900" height="2613"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D600" mode="14bit-compressed">
+ <ID make="Nikon" model="D600">Nikon D600</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D600" mode="12bit-compressed">
+ <ID make="Nikon" model="D600">Nikon D600</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D610" mode="14bit-compressed">
+ <ID make="Nikon" model="D610">Nikon D610</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D610" mode="12bit-compressed">
+ <ID make="Nikon" model="D610">Nikon D610</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-50" height="0"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D70" mode="12bit-compressed">
+ <ID make="Nikon" model="D70">Nikon D70</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3038" height="2014"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D700" mode="12bit-compressed">
+ <ID make="Nikon" model="D700">Nikon D700</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="4282" height="2844"/>
+ <Sensor black="0" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D700" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D700">Nikon D700</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="4282" height="2844"/>
+ <Sensor black="0" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D700" mode="14bit-compressed">
+ <ID make="Nikon" model="D700">Nikon D700</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="4282" height="2844"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D700" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D700">Nikon D700</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="4282" height="2844"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D750" mode="12bit-compressed">
+ <ID make="Nikon" model="D750">Nikon D750</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D750" mode="14bit-compressed">
+ <ID make="Nikon" model="D750">Nikon D750</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="600" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D7000" mode="14bit-compressed">
+ <ID make="Nikon" model="D7000">Nikon D7000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-46" height="-2"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D7000" mode="12bit-compressed">
+ <ID make="Nikon" model="D7000">Nikon D7000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-46" height="-2"/>
+ <Sensor black="0" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D7100" mode="14bit-compressed">
+ <ID make="Nikon" model="D7100">Nikon D7100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D7100" mode="12bit-compressed">
+ <ID make="Nikon" model="D7100">Nikon D7100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D7200" mode="14bit-compressed">
+ <ID make="Nikon" model="D7200">Nikon D7200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="600" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D7200" mode="14bit-uncompressed" supported="no">
+ <ID make="Nikon" model="D7200">Nikon D7200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="600" white="15892"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D7200" mode="12bit-compressed">
+ <ID make="Nikon" model="D7200">Nikon D7200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D7200" mode="12bit-uncompressed" supported="no">
+ <ID make="Nikon" model="D7200">Nikon D7200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3972"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D7500" mode="12bit-compressed">
+ <ID make="Nikon" model="D7500">Nikon D7500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="100" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D7500" mode="14bit-compressed">
+ <ID make="Nikon" model="D7500">Nikon D7500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="400" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D70s" mode="12bit-compressed">
+ <ID make="Nikon" model="D70s">Nikon D70s</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3040" height="2014"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D80" mode="12bit-compressed">
+ <ID make="Nikon" model="D80">Nikon D80</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3900" height="2611"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D80" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D80">Nikon D80</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3900" height="2611"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D800" mode="7424x4924-14bit-uncompressed">
+ <ID make="Nikon" model="D800">Nikon D800</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-48" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D800" mode="14bit-compressed">
+ <ID make="Nikon" model="D800">Nikon D800</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-48" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D800" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D800">Nikon D800</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D800" mode="12bit-compressed">
+ <ID make="Nikon" model="D800">Nikon D800</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-48" height="0"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D800" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D800">Nikon D800</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-48" height="0"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D800E" mode="7424x4924-14bit-uncompressed">
+ <ID make="Nikon" model="D800E">Nikon D800E</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-48" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D800E" mode="14bit-compressed">
+ <ID make="Nikon" model="D800E">Nikon D800E</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-48" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D800E" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D800E">Nikon D800E</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D800E" mode="12bit-compressed">
+ <ID make="Nikon" model="D800E">Nikon D800E</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-48" height="0"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D800E" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D800E">Nikon D800E</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="2" y="0" width="-48" height="0"/>
+ <Sensor black="0" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D810" mode="sNEF-uncompressed">
+ <ID make="Nikon" model="D810">Nikon D810</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D810" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D810">Nikon D810</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3880"/>
+ <Hints>
+ <Hint name="msb_override" value=""/>
+
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D810" mode="12bit-compressed">
+ <ID make="Nikon" model="D810">Nikon D810</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D810" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D810">Nikon D810</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="600" white="15520"/>
+ <Hints>
+ <Hint name="msb_override" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D810" mode="14bit-compressed">
+ <ID make="Nikon" model="D810">Nikon D810</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="600" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D850" mode="12bit-compressed">
+ <ID make="Nikon" model="D850">Nikon D850</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="100" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D850" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D850">Nikon D850</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="100" white="3880"/>
+ <Hints>
+ <Hint name="msb_override" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D850" mode="14bit-compressed">
+ <ID make="Nikon" model="D850">Nikon D850</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="400" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D850" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D850">Nikon D850</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="400" white="15520"/>
+ <Hints>
+ <Hint name="msb_override" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D4S" mode="sNEF-uncompressed">
+ <ID make="Nikon" model="D4S">Nikon D4S</ID>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D4S" mode="12bit-compressed">
+ <ID make="Nikon" model="D4S">Nikon D4S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="192" white="3880"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D4S" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D4S">Nikon D4S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="192" white="3880"/>
+ <Hints>
+ <Hint name="msb_override" value=""/>
+
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D4S" mode="14bit-uncompressed">
+ <ID make="Nikon" model="D4S">Nikon D4S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="768" white="15520"/>
+ <Hints>
+ <Hint name="msb_override" value=""/>
+
+ </Hints>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D4S" mode="14bit-compressed">
+ <ID make="Nikon" model="D4S">Nikon D4S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="768" white="15520"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D90" mode="12bit-compressed">
+ <ID make="Nikon" model="D90">Nikon D90</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4310" height="2868"/>
+ <Sensor black="0" white="3767"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON D90" mode="12bit-uncompressed">
+ <ID make="Nikon" model="D90">Nikon D90</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4310" height="2868"/>
+ <Sensor black="0" white="3767"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 J1" mode="12bit-compressed" decoder_version="4">
+ <ID make="Nikon" model="1 J1">Nikon 1 J1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="-2"/>
+ <Sensor black="0" white="3300"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 J2" mode="12bit-compressed" decoder_version="4">
+ <ID make="Nikon" model="1 J2">Nikon 1 J2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="-2"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 J3" mode="12bit-compressed" decoder_version="4">
+ <ID make="Nikon" model="1 J3">Nikon 1 J3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="-2"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 J4" mode="12bit-compressed" decoder_version="4">
+ <ID make="Nikon" model="1 J4">Nikon 1 J4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="200" white="4000"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 J5" mode="12bit-compressed">
+ <ID make="Nikon" model="1 J5">Nikon 1 J5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="200" white="3800"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 J5" mode="12bit-uncompressed">
+ <ID make="Nikon" model="1 J5">Nikon 1 J5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="200" white="3800"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 S1" mode="12bit-compressed" decoder_version="4">
+ <ID make="Nikon" model="1 S1">Nikon 1 S1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="-2"/>
+ <Sensor black="0" white="3300"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 S2" mode="12bit-compressed" decoder_version="4">
+ <ID make="Nikon" model="1 S2">Nikon 1 S2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="200" white="4095"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 V1" mode="12bit-compressed" decoder_version="4">
+ <ID make="Nikon" model="1 V1">Nikon 1 V1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="-2"/>
+ <Sensor black="0" white="3300"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 V2" mode="12bit-compressed" decoder_version="4">
+ <ID make="Nikon" model="1 V2">Nikon 1 V2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 V3" mode="12bit-compressed" decoder_version="4">
+ <ID make="Nikon" model="1 V3">Nikon 1 V3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="200" white="4000"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 V3" mode="12bit-uncompressed" decoder_version="4">
+ <ID make="Nikon" model="1 V3">Nikon 1 V3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="200" white="4000"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="NIKON 1 AW1" mode="12bit-compressed" decoder_version="4">
+ <ID make="Nikon" model="1 AW1">Nikon 1 AW1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Sensor black="0" white="3300" iso_list="160"/>
+ </Camera>
+ <Camera make="NIKON" model="E5400" mode="12bit-uncompressed" decoder_version="3">
+ <ID make="Nikon" model="E5400">Nikon E5400</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="2608" height="1950"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="coolpixsplit" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="E5700" mode="12bit-uncompressed" decoder_version="4">
+ <ID make="Nikon" model="E5700">Nikon E5700</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">FUJI_GREEN</Color>
+ <Color x="1" y="0">MAGENTA</Color>
+ <Color x="0" y="1">YELLOW</Color>
+ <Color x="1" y="1">CYAN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="2576" height="1924"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="coolpixsplit" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="E8400" mode="12bit-compressed" decoder_version="3" supported="no"> <!-- need raw sample for whitelevel -->
+ <ID make="Nikon" model="E8400">Nikon E8400</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3280" height="2454"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="coolpixsplit" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="E8400" mode="12bit-uncompressed" decoder_version="3" supported="no"> <!-- need raw sample for whitelevel -->
+ <ID make="Nikon" model="E8400">Nikon E8400</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3280" height="2454"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="coolpixsplit" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="COOLPIX P330" mode="12bit-compressed" decoder_version="5">
+ <ID make="Nikon" model="Coolpix P330">Nikon Coolpix P330</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="3200" white="65000"/>
+ <Hints>
+ <Hint name="force_uncompressed" value=""/>
+ <Hint name="real_bpp" value="16"/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="COOLPIX P340" mode="12bit-compressed" decoder_version="5">
+ <ID make="Nikon" model="Coolpix P340">Nikon Coolpix P340</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="200" white="3800"/>
+ </Camera>
+ <Camera make="NIKON" model="COOLPIX P340" mode="12bit-uncompressed" decoder_version="5">
+ <ID make="Nikon" model="Coolpix P340">Nikon Coolpix P340</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="200" white="3800"/>
+ </Camera>
+ <Camera make="NIKON CORPORATION" model="COOLPIX A" mode="14bit-compressed">
+ <ID make="Nikon" model="Coolpix A">Nikon Coolpix A</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="0" white="15892"/>
+ </Camera>
+ <Camera make="NIKON" model="COOLPIX B700">
+ <ID make="Nikon" model="COOLPIX B700">Nikon Coolpix B700</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="200" white="4000"/>
+ <Hints>
+ <Hint name="coolpixmangled" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="COOLPIX B700" mode="12bit-uncompressed">
+ <ID make="Nikon" model="COOLPIX B700">Nikon Coolpix B700</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="200" white="4000"/>
+ <Hints>
+ <Hint name="coolpixmangled" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="COOLPIX P6000" mode="12bit-uncompressed" decoder_version="1">
+ <ID make="Nikon" model="Coolpix P6000">Nikon Coolpix P6000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="coolpixmangled" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="COOLPIX P7000" mode="12bit-uncompressed" decoder_version="1">
+ <ID make="Nikon" model="Coolpix P7000">Nikon Coolpix P7000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Sensor black="255" white="4095" iso_min="400" iso_max="3200"/>
+ <!-- In usual Nikon style, ISO 6400 is marked as ISO 0 -->
+ <Sensor black="255" white="4095" iso_min="0" iso_max="1"/>
+ <Hints>
+ <Hint name="coolpixmangled" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="COOLPIX P7100" mode="12bit-uncompressed" decoder_version="1">
+ <ID make="Nikon" model="Coolpix P7100">Nikon Coolpix P7100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3800"/>
+ <Sensor black="250" white="3800" iso_min="400" iso_max="0"/>
+ <!-- In usual Nikon style, ISO 6400 is marked as ISO 0 -->
+ <Sensor black="260" white="3800" iso_min="0" iso_max="1"/>
+ <Hints>
+ <Hint name="coolpixmangled" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="COOLPIX P7700" mode="12bit-compressed" decoder_version="5">
+ <ID make="Nikon" model="Coolpix P7700">Nikon Coolpix P7700</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="3200" white="65000"/>
+ <Hints>
+ <Hint name="force_uncompressed" value=""/>
+ <Hint name="real_bpp" value="16"/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="COOLPIX P7800" mode="12bit-compressed" decoder_version="5">
+ <ID make="Nikon" model="Coolpix P7800">Nikon Coolpix P7800</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="3200" white="65000"/>
+ <Hints>
+ <Hint name="force_uncompressed" value=""/>
+ <Hint name="real_bpp" value="16"/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="E8800" mode="12bit-compressed" decoder_version="3" supported="no"> <!-- need raw sample for whitelevel -->
+ <ID make="Nikon" model="Coolpix E8800">Nikon Coolpix E8800</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3280" height="2454"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="coolpixsplit" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="NIKON" model="E8800" mode="12bit-uncompressed" decoder_version="3" supported="no"> <!-- need raw sample for whitelevel -->
+ <ID make="Nikon" model="Coolpix E8800">Nikon Coolpix E8800</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3280" height="2454"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="coolpixsplit" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="OLYMPUS OPTICAL CO.,LTD" model="C5050Z">
+ <ID make="Olympus" model="C5050Z">Olympus C5050Z</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS CORPORATION" model="C5060WZ">
+ <ID make="Olympus" model="C5060WZ">Olympus C5060WZ</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS CORPORATION" model="C8080WZ">
+ <ID make="Olympus" model="C8080WZ">Olympus C8080WZ</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3280" height="2453"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS CORPORATION" model="E-1">
+ <ID make="Olympus" model="E-1">Olympus E-1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="2624" height="1966"/>
+ <Sensor black="65" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS CORPORATION" model="TG-4">
+ <ID make="Olympus" model="TG-4">Olympus TG-4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="16" y="8" width="-16" height="-8"/>
+ <Sensor black="0" white="4000"/>
+ </Camera>
+ <Camera make="OLYMPUS CORPORATION" model="TG-5">
+ <ID make="Olympus" model="TG-5">Olympus TG-5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-24" height="0"/>
+ <Sensor black="256" white="4000"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="C7070WZ">
+ <ID make="Olympus" model="C7070WZ">Olympus C7070WZ</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3088" height="2309"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-3">
+ <ID make="Olympus" model="E-3">Olympus E-3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3720" height="2800"/>
+ <Sensor black="65" white="4015"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-30">
+ <ID make="Olympus" model="E-30">Olympus E-30</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-6" height="-2"/>
+ <Sensor black="65" white="4015"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-300" decoder_version="3">
+ <ID make="Olympus" model="E-300">Olympus E-300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3340" height="2504"/>
+ <Sensor black="63" white="4095"/>
+ <Hints>
+ <Hint name="force_uncompressed" value=""/>
+ <Hint name="packed_with_control" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-330" decoder_version="3">
+ <ID make="Olympus" model="E-330">Olympus E-330</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3250" height="2450"/>
+ <Sensor black="77" white="4095"/>
+ <Hints>
+ <Hint name="force_uncompressed" value=""/>
+ <Hint name="packed_with_control" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-400">
+ <ID make="Olympus" model="E-400">Olympus E-400</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3768" height="2840"/>
+ <Sensor black="96" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-410">
+ <ID make="Olympus" model="E-410">Olympus E-410</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3720" height="2800"/>
+ <Sensor black="72" white="3500"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-420">
+ <ID make="Olympus" model="E-420">Olympus E-420</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3720" height="2800"/>
+ <Sensor black="68" white="4015"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-450">
+ <ID make="Olympus" model="E-450">Olympus E-450</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="69" white="4015"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-500" decoder_version="3">
+ <ID make="Olympus" model="E-500">Olympus E-500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3340" height="2504"/>
+ <Sensor black="63" white="3967"/>
+ <Hints>
+ <Hint name="force_uncompressed" value=""/>
+ <Hint name="packed_with_control" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-510">
+ <ID make="Olympus" model="E-510">Olympus E-510</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3720" height="2800"/>
+ <Sensor black="72" white="3500"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-520">
+ <ID make="Olympus" model="E-520">Olympus E-520</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3720" height="2800"/>
+ <Sensor black="69" white="4015"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-600">
+ <ID make="Olympus" model="E-600">Olympus E-600</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4096" height="3072"/>
+ <Sensor black="64" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-620">
+ <ID make="Olympus" model="E-620">Olympus E-620</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4096" height="3072"/>
+ <Sensor black="64" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="SP320">
+ <ID make="Olympus" model="SP320">Olympus SP320</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="SP350">
+ <ID make="Olympus" model="SP350">Olympus SP350</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3280" height="2453"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="SP500UZ">
+ <ID make="Olympus" model="SP500UZ">Olympus SP500UZ</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="2832" height="2117"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-5">
+ <ID make="Olympus" model="E-5">Olympus E-5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-4" height="0"/>
+ <Sensor black="80" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS OPTICAL CO.,LTD" model="E-10">
+ <ID make="Olympus" model="E-10">Olympus E-10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="2256" height="1684"/>
+ <Sensor black="32" white="1023"/>
+ </Camera>
+ <Camera make="OLYMPUS OPTICAL CO.,LTD" model="E-20,E-20N,E-20P">
+ <ID make="Olympus" model="E-20">Olympus E-20</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="2576" height="1924"/>
+ <Sensor black="0" white="4092"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-M1">
+ <ID make="Olympus" model="E-M1">Olympus E-M1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="255" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS CORPORATION" model="E-M1MarkII">
+ <ID make="Olympus" model="E-M1MarkII">Olympus E-M1 Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="254" white="4000"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-M10">
+ <ID make="Olympus" model="E-M10">Olympus E-M10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-24" height="-8"/>
+ <Sensor black="254" white="4000"/>
+ </Camera>
+ <Camera make="OLYMPUS CORPORATION" model="E-M10MarkII">
+ <ID make="Olympus" model="E-M10 Mark II">Olympus E-M10 Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="254" white="4000"/>
+ </Camera>
+ <Camera make="OLYMPUS CORPORATION" model="E-M10 Mark III">
+ <ID make="Olympus" model="E-M10 Mark III">Olympus E-M10 Mark III</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="254" white="4000"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-M5">
+ <ID make="Olympus" model="E-M5">Olympus E-M5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-24" height="-8"/>
+ <Sensor black="255" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-M5MarkII">
+ <ID make="Olympus" model="E-M5 Mark II">Olympus E-M5 Mark II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="254" white="4000"/>
+ <Sensor black="249" white="4000" iso_min="800" iso_max="3199"/>
+ <Sensor black="235" white="4000" iso_min="3200" iso_max="6399"/>
+ <Sensor black="230" white="4000" iso_min="6400" iso_max="12799"/>
+ <Sensor black="220" white="4000" iso_min="12800" iso_max="25599"/>
+ <Sensor black="187" white="4000" iso_min="25600" iso_max="25600"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-P1">
+ <ID make="Olympus" model="E-P1">Olympus E-P1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4094" height="3082"/>
+ <Sensor black="55" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-PL1">
+ <ID make="Olympus" model="E-PL1">Olympus E-PL1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4094" height="3082"/>
+ <Sensor black="55" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-PL2">
+ <ID make="Olympus" model="E-PL2">Olympus E-PL2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-4" height="0"/>
+ <Sensor black="45" white="4095"/>
+ <BlackAreas>
+ <Vertical x="4097" width="2"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-PL3">
+ <ID make="Olympus" model="E-PL3">Olympus E-PL3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-30" height="0"/>
+ <Sensor black="45" white="4095"/>
+ <BlackAreas>
+ <Vertical x="4064" width="6"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-PL5">
+ <ID make="Olympus" model="E-PL5">Olympus E-PL5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-24" height="-8"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-PL6">
+ <ID make="Olympus" model="E-PL6">Olympus E-PL6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-24" height="-8"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-PL7">
+ <ID make="Olympus" model="E-PL7">Olympus E-PL7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-24" height="-8"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-P5">
+ <ID make="Olympus" model="E-P5">Olympus E-P5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-24" height="-8"/>
+ <Sensor black="250" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-PM1">
+ <ID make="Olympus" model="E-PM1">Olympus E-PM1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-24" height="0"/>
+ <Sensor black="45" white="4095"/>
+ <BlackAreas>
+ <Vertical x="4064" width="6"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-PM2">
+ <ID make="Olympus" model="E-PM2">Olympus E-PM2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-24" height="-8"/>
+ <Sensor black="250" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-P2">
+ <ID make="Olympus" model="E-P2">Olympus E-P2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="55" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="E-P3">
+ <ID make="Olympus" model="E-P3">Olympus E-P3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-26" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS CORPORATION" model="PEN-F">
+ <ID make="Olympus" model="PEN-F">Olympus PEN-F</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="254" white="4000"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="XZ-1">
+ <ID make="Olympus" model="XZ-1">Olympus XZ-1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="-2"/>
+ <Sensor black="55" white="3972"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="XZ-2" decoder_version="3">
+ <ID make="Olympus" model="XZ-2">Olympus XZ-2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="-2"/>
+ <Sensor black="200" white="4092"/>
+ <Hints>
+ <Hint name="force_uncompressed" value=""/>
+ <Hint name="jpeg32_bitorder" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="XZ-10" decoder_version="3">
+ <ID make="Olympus" model="XZ-10">Olympus XZ-10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="200" white="3900"/>
+ <Hints>
+ <Hint name="force_uncompressed" value=""/>
+ <Hint name="jpeg32_bitorder" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="SP570UZ">
+ <ID make="Olympus" model="SP570UZ">Olympus SP570UZ</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="OLYMPUS IMAGING CORP." model="STYLUS1">
+ <ID make="Olympus" model="Stylus1">Olympus Stylus1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-14" height="0"/>
+ <Sensor black="200" white="3900"/>
+ <Aliases>
+ <Alias id="Stylus1">STYLUS1,1s</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-CM1">
+ <ID make="Panasonic" model="DMC-CM1">Panasonic DMC-CM1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="142" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-CM1" mode="3:2">
+ <ID make="Panasonic" model="DMC-CM1">Panasonic DMC-CM1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="142" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FX150">
+ <ID make="Panasonic" model="DMC-FX150">Panasonic DMC-FX150</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4429" height="3324"/>
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FX150" mode = "4:3">
+ <ID make="Panasonic" model="DMC-FX150">Panasonic DMC-FX150</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4429" height="3324"/>
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ28" mode = "4:3">
+ <ID make="Panasonic" model="DMC-FZ28">Panasonic DMC-FZ28</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3668" height="2754"/>
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ28" mode = "16:9">
+ <ID make="Panasonic" model="DMC-FZ28">Panasonic DMC-FZ28</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3668" height="2754"/>
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ28">
+ <ID make="Panasonic" model="DMC-FZ28">Panasonic DMC-FZ28</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-56" height="-4"/>
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ150">
+ <ID make="Panasonic" model="DMC-FZ150">Panasonic DMC-FZ150</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="145" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ150" mode="4:3">
+ <ID make="Panasonic" model="DMC-FZ150">Panasonic DMC-FZ150</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="145" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ150" mode="3:2">
+ <ID make="Panasonic" model="DMC-FZ150">Panasonic DMC-FZ150</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="143" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ150" mode="1:1">
+ <ID make="Panasonic" model="DMC-FZ150">Panasonic DMC-FZ150</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-16" height="0"/>
+ <Sensor black="142" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ150" mode="16:9">
+ <ID make="Panasonic" model="DMC-FZ150">Panasonic DMC-FZ150</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="142" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ200">
+ <ID make="Panasonic" model="DMC-FZ200">Panasonic DMC-FZ200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="-4"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ200" mode="4:3">
+ <ID make="Panasonic" model="DMC-FZ200">Panasonic DMC-FZ200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="-4"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ200" mode="3:2">
+ <ID make="Panasonic" model="DMC-FZ200">Panasonic DMC-FZ200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ200" mode="1:1">
+ <ID make="Panasonic" model="DMC-FZ200">Panasonic DMC-FZ200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-16" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ200" mode="16:9">
+ <ID make="Panasonic" model="DMC-FZ200">Panasonic DMC-FZ200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ300">
+ <ID make="Panasonic" model="DMC-FZ300">Panasonic DMC-FZ300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ300" mode="4:3">
+ <ID make="Panasonic" model="DMC-FZ300">Panasonic DMC-FZ300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ330">
+ <ID make="Panasonic" model="DMC-FZ330">Panasonic DMC-FZ300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="142" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ330" mode="4:3">
+ <ID make="Panasonic" model="DMC-FZ330">Panasonic DMC-FZ300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="142" white="4095"/>
+ </Camera>
+
+ <Camera make="Panasonic" model = "DMC-G1">
+ <ID make="Panasonic" model="DMC-G1">Panasonic DMC-G1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4018" height="3016" />
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G1" mode="4:3">
+ <ID make="Panasonic" model="DMC-G1">Panasonic DMC-G1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4018" height="3016" />
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G1" mode="16:9">
+ <ID make="Panasonic" model="DMC-G1">Panasonic DMC-G1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="0" />
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G1" mode="3:2">
+ <ID make="Panasonic" model="DMC-G1">Panasonic DMC-G1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0" />
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G2" mode="4:3">
+ <ID make="Panasonic" model="DMC-G2">Panasonic DMC-G2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0" />
+ <Sensor black="0" white="3900"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G2" mode="3:2">
+ <ID make="Panasonic" model="DMC-G2">Panasonic DMC-G2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0" />
+ <Sensor black="0" white="3900"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G2" mode="16:9">
+ <ID make="Panasonic" model="DMC-G2">Panasonic DMC-G2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0" />
+ <Sensor black="0" white="3900"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G2" mode="1:1">
+ <ID make="Panasonic" model="DMC-G2">Panasonic DMC-G2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0" />
+ <Sensor black="0" white="3900"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G2">
+ <ID make="Panasonic" model="DMC-G2">Panasonic DMC-G2</ID>
+ <!-- Default Guess -->
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0" />
+ <Sensor black="0" white="3900"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G10">
+ <ID make="Panasonic" model="DMC-G10">Panasonic DMC-G10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0" />
+ <Sensor black="0" white="3900"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G10" mode="4:3">
+ <ID make="Panasonic" model="DMC-G10">Panasonic DMC-G10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0" />
+ <Sensor black="0" white="3900"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH1" mode="4:3">
+ <ID make="Panasonic" model="DMC-GH1">Panasonic DMC-GH1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH1" mode="3:2">
+ <ID make="Panasonic" model="DMC-GH1">Panasonic DMC-GH1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-28" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH1">
+ <ID make="Panasonic" model="DMC-GH1">Panasonic DMC-GH1</ID>
+ <!-- Default Guess -->
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH3" mode="4:3">
+ <ID make="Panasonic" model="DMC-GH3">Panasonic DMC-GH3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-194" height="0"/>
+ <Sensor black="155" white="3956"/>
+ <Sensor black="165" white="3941" iso_min="6400"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH3" mode="3:2">
+ <ID make="Panasonic" model="DMC-GH3">Panasonic DMC-GH3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-194" height="0"/>
+ <Sensor black="155" white="3956"/>
+ <Sensor black="165" white="3941" iso_min="6400"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH3" mode="16:9">
+ <ID make="Panasonic" model="DMC-GH3">Panasonic DMC-GH3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-194" height="0"/>
+ <Sensor black="155" white="3956"/>
+ <Sensor black="165" white="3941" iso_min="6400"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH3" mode="1:1">
+ <ID make="Panasonic" model="DMC-GH3">Panasonic DMC-GH3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="155" white="3956"/>
+ <Sensor black="165" white="3941" iso_min="6400"/>
+ </Camera>
+ <!-- Default Guess -->
+ <Camera make="Panasonic" model = "DMC-GH3">
+ <ID make="Panasonic" model="DMC-GH3">Panasonic DMC-GH3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-194" height="0"/>
+ <Sensor black="155" white="3956"/>
+ <Sensor black="165" white="3941" iso_min="6400"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH4" mode="4:3">
+ <ID make="Panasonic" model="DMC-GH4">Panasonic DMC-GH4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-200" height="-8"/>
+ <Sensor black="142" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH4" mode="3:2">
+ <ID make="Panasonic" model="DMC-GH4">Panasonic DMC-GH4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-200" height="-8"/>
+ <Sensor black="142" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH4" mode="16:9">
+ <ID make="Panasonic" model="DMC-GH4">Panasonic DMC-GH4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-200" height="-8"/>
+ <Sensor black="142" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH4" mode="1:1">
+ <ID make="Panasonic" model="DMC-GH4">Panasonic DMC-GH4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="142" white="4095"/>
+ </Camera>
+ <!-- Default Guess -->
+ <Camera make="Panasonic" model = "DMC-GH4">
+ <ID make="Panasonic" model="DMC-GH4">Panasonic DMC-GH4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="8" y="8" width="-200" height="-8"/>
+ <Sensor black="142" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF1">
+ <ID make="Panasonic" model="DMC-GF1">Panasonic DMC-GF1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF1" mode="4:3">
+ <ID make="Panasonic" model="DMC-GF1">Panasonic DMC-GF1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF1" mode="16:9">
+ <ID make="Panasonic" model="DMC-GF1">Panasonic DMC-GF1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF1" mode="3:2">
+ <ID make="Panasonic" model="DMC-GF1">Panasonic DMC-GF1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF1" mode="1:1">
+ <ID make="Panasonic" model="DMC-GF1">Panasonic DMC-GF1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="15" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF2">
+ <ID make="Panasonic" model="DMC-GF2">Panasonic DMC-GF2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-74" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF2" mode="4:3">
+ <ID make="Panasonic" model="DMC-GF2">Panasonic DMC-GF2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-74" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF2" mode="16:9">
+ <ID make="Panasonic" model="DMC-GF2">Panasonic DMC-GF2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-74" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF2" mode="3:2">
+ <ID make="Panasonic" model="DMC-GF2">Panasonic DMC-GF2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-74" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF2" mode="1:1">
+ <ID make="Panasonic" model="DMC-GF2">Panasonic DMC-GF2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-74" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GM1" mode="4:3">
+ <ID make="Panasonic" model="DMC-GM1">Panasonic DMC-GM1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-206" height="0"/>
+ <Sensor black="143" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GM1" mode="3:2">
+ <ID make="Panasonic" model="DMC-GM1">Panasonic DMC-GM1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-206" height="0"/>
+ <Sensor black="143" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GM1" mode="16:9">
+ <ID make="Panasonic" model="DMC-GM1">Panasonic DMC-GM1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-206" height="0"/>
+ <Sensor black="143" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GM1" mode="1:1">
+ <ID make="Panasonic" model="DMC-GM1">Panasonic DMC-GM1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="143" white="3971"/>
+ </Camera>
+ <!-- Default Guess -->
+ <Camera make="Panasonic" model = "DMC-GM1">
+ <ID make="Panasonic" model="DMC-GM1">Panasonic DMC-GM1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-206" height="0"/>
+ <Sensor black="143" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GM5">
+ <ID make="Panasonic" model="DMC-GM5">Panasonic DMC-GM5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GM5" mode="4:3">
+ <ID make="Panasonic" model="DMC-GM5">Panasonic DMC-GM5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="8" y="8" width="4592" height="3448"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GM5" mode="3:2">
+ <ID make="Panasonic" model="DMC-GM5">Panasonic DMC-GM5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="8" y="8" width="4592" height="3064"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GM5" mode="16:9">
+ <ID make="Panasonic" model="DMC-GM5">Panasonic DMC-GM5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="8" y="8" width="4592" height="2584"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GM5" mode="1:1">
+ <ID make="Panasonic" model="DMC-GM5">Panasonic DMC-GM5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="8" y="8" width="3424" height="3424"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G3" mode="4:3">
+ <ID make="Panasonic" model="DMC-G3">Panasonic DMC-G3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-152" height="0"/>
+ <Sensor black="143" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G3" mode="1:1">
+ <ID make="Panasonic" model="DMC-G3">Panasonic DMC-G3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-200" height="0"/>
+ <Sensor black="143" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G3" mode="16:9">
+ <ID make="Panasonic" model="DMC-G3">Panasonic DMC-G3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-168" height="0"/>
+ <Sensor black="143" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G3" mode="3:2">
+ <ID make="Panasonic" model="DMC-G3">Panasonic DMC-G3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-168" height="0"/>
+ <Sensor black="143" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G3">
+ <ID make="Panasonic" model="DMC-G3">Panasonic DMC-G3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="143" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G5" mode="4:3">
+ <ID make="Panasonic" model="DMC-G5">Panasonic DMC-G5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-192" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G5" mode="3:2">
+ <ID make="Panasonic" model="DMC-G5">Panasonic DMC-G5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-192" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G5" mode="16:9">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-192" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G5" mode="1:1">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G5">
+ <ID make="Panasonic" model="DMC-G5">Panasonic DMC-G5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-192" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G6">
+ <ID make="Panasonic" model="DMC-G6">Panasonic DMC-G6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-194" height="0"/>
+ <Sensor black="142" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G6" mode="4:3">
+ <ID make="Panasonic" model="DMC-G6">Panasonic DMC-G6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-194" height="0"/>
+ <Sensor black="142" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G6" mode="3:2">
+ <ID make="Panasonic" model="DMC-G6">Panasonic DMC-G6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-194" height="0"/>
+ <Sensor black="142" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G6" mode="16:9">
+ <ID make="Panasonic" model="DMC-G6">Panasonic DMC-G6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-194" height="0"/>
+ <Sensor black="142" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-G6" mode="1:1">
+ <ID make="Panasonic" model="DMC-G6">Panasonic DMC-G6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="142" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G7">
+ <ID make="Panasonic" model="DMC-G7">Panasonic DMC-G7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Aliases>
+ <Alias>DMC-G70</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G7" mode="4:3">
+ <ID make="Panasonic" model="DMC-G7">Panasonic DMC-G7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Aliases>
+ <Alias>DMC-G70</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G7" mode="3:2">
+ <ID make="Panasonic" model="DMC-G7">Panasonic DMC-G7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Aliases>
+ <Alias>DMC-G70</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G7" mode="1:1">
+ <ID make="Panasonic" model="DMC-G7">Panasonic DMC-G7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Aliases>
+ <Alias>DMC-G70</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G7" mode="16:9">
+ <ID make="Panasonic" model="DMC-G7">Panasonic DMC-G7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Aliases>
+ <Alias>DMC-G70</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G8">
+ <ID make="Panasonic" model="DMC-G8">Panasonic DMC-G8</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Aliases>
+ <Alias>DMC-G80</Alias>
+ <Alias>DMC-G81</Alias>
+ <Alias>DMC-G85</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-G8" mode="4:3">
+ <ID make="Panasonic" model="DMC-G8">Panasonic DMC-G8</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Aliases>
+ <Alias>DMC-G80</Alias>
+ <Alias>DMC-G81</Alias>
+ <Alias>DMC-G85</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF3">
+ <ID make="Panasonic" model="DMC-GF3">Panasonic DMC-GF3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-72" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF3" mode= "4:3">
+ <ID make="Panasonic" model="DMC-GF3">Panasonic DMC-GF3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-72" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF3" mode= "3:2">
+ <ID make="Panasonic" model="DMC-GF3">Panasonic DMC-GF3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-72" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF3" mode= "16:9">
+ <ID make="Panasonic" model="DMC-GF3">Panasonic DMC-GF3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-72" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF3" mode= "1:1">
+ <ID make="Panasonic" model="DMC-GF3">Panasonic DMC-GF3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-184" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF5">
+ <ID make="Panasonic" model="DMC-GF5">Panasonic DMC-GF5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF5" mode= "4:3">
+ <ID make="Panasonic" model="DMC-GF5">Panasonic DMC-GF5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF5" mode= "16:9">
+ <ID make="Panasonic" model="DMC-GF5">Panasonic DMC-GF5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF5" mode= "3:2">
+ <ID make="Panasonic" model="DMC-GF5">Panasonic DMC-GF5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF5" mode= "1:1">
+ <ID make="Panasonic" model="DMC-GF5">Panasonic DMC-GF5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-16" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF6">
+ <ID make="Panasonic" model="DMC-GF6">Panasonic DMC-GF6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF6" mode= "4:3">
+ <ID make="Panasonic" model="DMC-GF6">Panasonic DMC-GF6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF6" mode= "16:9">
+ <ID make="Panasonic" model="DMC-GF6">Panasonic DMC-GF6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF6" mode= "3:2">
+ <ID make="Panasonic" model="DMC-GF6">Panasonic DMC-GF6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GF6" mode= "1:1">
+ <ID make="Panasonic" model="DMC-GF6">Panasonic DMC-GF6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-34" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GF7">
+ <ID make="Panasonic" model="DMC-GF7">Panasonic DMC-GF7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GF7" mode="4:3">
+ <ID make="Panasonic" model="DMC-GF7">Panasonic DMC-GF7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GF7" mode="1:1">
+ <ID make="Panasonic" model="DMC-GF7">Panasonic DMC-GF7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GF7" mode="3:2">
+ <ID make="Panasonic" model="DMC-GF7">Panasonic DMC-GF7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GF7" mode="16:9">
+ <ID make="Panasonic" model="DMC-GF7">Panasonic DMC-GF7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH2">
+ <ID make="Panasonic" model="DMC-GH2">Panasonic DMC-GH2</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="1">RED</Color>
+ <Color x="0" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-216" height="0"/>
+ <Sensor black="15" white="3800"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH2" mode="4:3">
+ <ID make="Panasonic" model="DMC-GH2">Panasonic DMC-GH2</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="1">RED</Color>
+ <Color x="0" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-136" height="0"/>
+ <Sensor black="15" white="3800"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH2" mode="16:9">
+ <ID make="Panasonic" model="DMC-GH2">Panasonic DMC-GH2</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="1">RED</Color>
+ <Color x="0" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-216" height="0"/>
+ <Sensor black="15" white="3800"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH2" mode="3:2">
+ <ID make="Panasonic" model="DMC-GH2">Panasonic DMC-GH2</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="1">RED</Color>
+ <Color x="0" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-216" height="0"/>
+ <Sensor black="15" white="3800"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH2" mode="1:1">
+ <ID make="Panasonic" model="DMC-GH2">Panasonic DMC-GH2</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="1">RED</Color>
+ <Color x="0" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-168" height="0"/>
+ <Sensor black="15" white="3800"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GH1" mode="16:9">
+ <ID make="Panasonic" model="DMC-GH1">Panasonic DMC-GH1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-28" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ35" mode="4:3">
+ <ID make="Panasonic" model="DMC-FZ35">Panasonic DMC-FZ35</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="150" white="3986"/>
+ <Aliases>
+ <Alias>DMC-FZ38</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ35">
+ <ID make="Panasonic" model="DMC-FZ35">Panasonic DMC-FZ35</ID>
+ <!-- Default Guess -->
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="150" white="3986"/>
+ <Aliases>
+ <Alias>DMC-FZ38</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ45">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-58" height="-10"/>
+ <Sensor black="150" white="3986"/>
+ <Aliases>
+ <Alias>DMC-FZ40</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ45" mode = "4:3">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-58" height="-10"/>
+ <Sensor black="150" white="3986"/>
+ <Aliases>
+ <Alias>DMC-FZ40</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ70">
+ <ID make="Panasonic" model="DMC-FZ70">Panasonic DMC-FZ70</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-182" height="0"/>
+ <Sensor black="120" white="3971"/>
+ <Aliases>
+ <Alias>DMC-FZ72</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ70" mode="4:3">
+ <ID make="Panasonic" model="DMC-FZ70">Panasonic DMC-FZ70</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-182" height="0"/>
+ <Sensor black="120" white="3971"/>
+ <Aliases>
+ <Alias>DMC-FZ72</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ70" mode="1:1">
+ <ID make="Panasonic" model="DMC-FZ70">Panasonic DMC-FZ70</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="144" white="3956"/>
+ <Aliases>
+ <Alias>DMC-FZ72</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ70" mode="3:2">
+ <ID make="Panasonic" model="DMC-FZ70">Panasonic DMC-FZ70</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-182" height="0"/>
+ <Sensor black="144" white="3956"/>
+ <Aliases>
+ <Alias>DMC-FZ72</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ70" mode="16:9">
+ <ID make="Panasonic" model="DMC-FZ70">Panasonic DMC-FZ70</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-182" height="0"/>
+ <Sensor black="144" white="3956"/>
+ <Aliases>
+ <Alias>DMC-FZ72</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ100">
+ <ID make="Panasonic" model="DMC-FZ100">Panasonic DMC-FZ100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-200" height="0"/>
+ <Sensor black="120" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ100" mode="4:3">
+ <ID make="Panasonic" model="DMC-FZ100">Panasonic DMC-FZ100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-200" height="0"/>
+ <Sensor black="120" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ1000">
+ <ID make="Panasonic" model="DMC-FZ1000">Panasonic DMC-FZ1000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ1000" mode="3:2">
+ <ID make="Panasonic" model="DMC-FZ1000">Panasonic DMC-FZ1000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="142" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ1000" mode="1:1">
+ <ID make="Panasonic" model="DMC-FZ1000">Panasonic DMC-FZ1000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ1000" mode="4:3">
+ <ID make="Panasonic" model="DMC-FZ1000">Panasonic DMC-FZ1000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-160" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ1000" mode="16:9">
+ <ID make="Panasonic" model="DMC-FZ1000">Panasonic DMC-FZ1000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GX1">
+ <ID make="Panasonic" model="DMC-GX1">Panasonic DMC-GX1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-154" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GX1" mode = "4:3">
+ <ID make="Panasonic" model="DMC-GX1">Panasonic DMC-GX1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-154" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GX1" mode = "3:2">
+ <ID make="Panasonic" model="DMC-GX1">Panasonic DMC-GX1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-170" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GX1" mode = "16:9">
+ <ID make="Panasonic" model="DMC-GX1">Panasonic DMC-GX1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-170" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GX1" mode = "1:1">
+ <ID make="Panasonic" model="DMC-GX1">Panasonic DMC-GX1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-198" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GX7">
+ <ID make="Panasonic" model="DMC-GX7">Panasonic DMC-GX7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GX7" mode = "4:3">
+ <ID make="Panasonic" model="DMC-GX7">Panasonic DMC-GX7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GX7" mode = "3:2">
+ <ID make="Panasonic" model="DMC-GX7">Panasonic DMC-GX7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GX7" mode = "16:9">
+ <ID make="Panasonic" model="DMC-GX7">Panasonic DMC-GX7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-208" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-GX7" mode = "1:1">
+ <ID make="Panasonic" model="DMC-GX7">Panasonic DMC-GX7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="0"/>
+ <Sensor black="150" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GX8">
+ <ID make="Panasonic" model="DMC-GX8">Panasonic DMC-GX8</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-64" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GX8" mode="4:3">
+ <ID make="Panasonic" model="DMC-GX8">Panasonic DMC-GX8</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-64" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GX85">
+ <ID make="Panasonic" model="DMC-GX85">Panasonic DMC-GX85</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-206" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Aliases>
+ <Alias>DMC-GX80</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-GX85" mode="4:3">
+ <ID make="Panasonic" model="DMC-GX85">Panasonic DMC-GX85</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-206" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Aliases>
+ <Alias>DMC-GX80</Alias>
+ </Aliases>
+ </Camera>
+ <!-- Default guess -->
+ <Camera make="Panasonic" model = "DMC-LF1">
+ <ID make="Panasonic" model="DMC-LF1">Panasonic DMC-LF1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-130" height="0"/>
+ <Sensor black="143" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LF1" mode="4:3">
+ <ID make="Panasonic" model="DMC-LF1">Panasonic DMC-LF1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-126" height="0"/>
+ <Sensor black="143" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LF1" mode="3:2">
+ <ID make="Panasonic" model="DMC-LF1">Panasonic DMC-LF1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-126" height="0"/>
+ <Sensor black="143" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LF1" mode="16:9">
+ <ID make="Panasonic" model="DMC-LF1">Panasonic DMC-LF1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-126" height="0"/>
+ <Sensor black="143" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LF1" mode="1:1">
+ <ID make="Panasonic" model="DMC-LF1">Panasonic DMC-LF1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-16" height="0"/>
+ <Sensor black="142" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX3">
+ <ID make="Panasonic" model="DMC-LX3">Panasonic DMC-LX3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-84" height="0"/>
+ <Sensor black="15" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX3" mode="16:9">
+ <ID make="Panasonic" model="DMC-LX3">Panasonic DMC-LX3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3990" height="2250"/>
+ <Sensor black="15" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX3" mode="4:3">
+ <ID make="Panasonic" model="DMC-LX3">Panasonic DMC-LX3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3666" height="2754"/>
+ <Sensor black="15" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX3" mode="3:2">
+ <ID make="Panasonic" model="DMC-LX3">Panasonic DMC-LX3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="15" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX3" mode="1:1">
+ <ID make="Panasonic" model="DMC-LX3">Panasonic DMC-LX3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-74" height="0"/>
+ <Sensor black="15" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LX15">
+ <ID make="Panasonic" model="DMC-LX15">Panasonic DMC-LX9</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Sensor black="142" white="2095" iso_list="80"/>
+ <Sensor black="142" white="3400" iso_list="100"/>
+ <Sensor black="142" white="4095" iso_list="125"/>
+ <Sensor black="144" white="4095" iso_list="640 800"/>
+ <Sensor black="145" white="4095" iso_list="1250 1600"/>
+ <Sensor black="149" white="4095" iso_list="3200"/>
+ <Sensor black="154" white="4095" iso_list="6400"/>
+ <Sensor black="166" white="4095" iso_list="12800"/>
+ <Sensor black="167" white="4095" iso_list="25600"/>
+ <Aliases>
+ <Alias>DMC-LX9</Alias>
+ <Alias>DMC-LX10</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LX15" mode="3:2">
+ <ID make="Panasonic" model="DMC-LX15">Panasonic DMC-LX9</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Sensor black="142" white="2095" iso_list="80"/>
+ <Sensor black="142" white="3400" iso_list="100"/>
+ <Sensor black="142" white="4095" iso_list="125"/>
+ <Sensor black="144" white="4095" iso_list="640 800"/>
+ <Sensor black="145" white="4095" iso_list="1250 1600"/>
+ <Sensor black="149" white="4095" iso_list="3200"/>
+ <Sensor black="154" white="4095" iso_list="6400"/>
+ <Sensor black="166" white="4095" iso_list="12800"/>
+ <Sensor black="167" white="4095" iso_list="25600"/>
+ <Aliases>
+ <Alias>DMC-LX9</Alias>
+ <Alias>DMC-LX10</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="LEICA" model="DIGILUX 2" decoder_version="2">
+ <ID make="Leica" model="Digilux 2">Leica Digilux 2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="LEICA" model="DIGILUX 2" mode="4:3" decoder_version="2">
+ <ID make="Leica" model="Digilux 2">Leica Digilux 2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="LEICA" model="D-LUX 3" decoder_version="2">
+ <ID make="Leica" model="D-LUX 3">Leica D-LUX 3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="LEICA" model="D-LUX 3" mode="16:9" decoder_version="2">
+ <ID make="Leica" model="D-LUX 3">Leica D-LUX 3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="17" y="17" width="-65" height="-24"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="LEICA" model="V-LUX 1" decoder_version="2">
+ <ID make="Leica" model="V-LUX 1">Leica V-LUX 1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="LEICA" model="V-LUX 1" mode="3:2" decoder_version="2">
+ <ID make="Leica" model="V-LUX 1">Leica V-LUX 1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="4" y="0" width="-14" height="-3"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="LEICA" model="V-LUX 1" mode="4:3" decoder_version="2">
+ <ID make="Leica" model="V-LUX 1">Leica V-LUX 1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="4" y="0" width="-14" height="-3"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-L10" decoder_version="2">
+ <ID make="Panasonic" model="DMC-L10">Panasonic DMC-L10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-28" height="-1"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-L10" mode="4:3" decoder_version="2">
+ <ID make="Panasonic" model="DMC-L10">Panasonic DMC-L10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-28" height="-1"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ30" decoder_version="2">
+ <ID make="Panasonic" model="DMC-FZ30">Panasonic DMC-FZ30</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ30" mode="4:3" decoder_version="2">
+ <ID make="Panasonic" model="DMC-FZ30">Panasonic DMC-FZ30</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-16" height="0"/>
+ <Sensor black="0" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ50" decoder_version="2">
+ <ID make="Panasonic" model="DMC-FZ50">Panasonic DMC-FZ50</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-FZ50" mode = "4:3" decoder_version="2">
+ <ID make="Panasonic" model="DMC-FZ50">Panasonic DMC-FZ50</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="20" y="18" width="-16" height="-5"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ50" mode="16:9" decoder_version="2">
+ <ID make="Panasonic" model="DMC-FZ50">Panasonic DMC-FZ50</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="3" y="0" width="-15" height="-5"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ50" mode="3:2" decoder_version="2">
+ <ID make="Panasonic" model="DMC-FZ50">Panasonic DMC-FZ50</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="3" y="0" width="-17" height="-5"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ8" decoder_version="2">
+ <ID make="Panasonic" model="DMC-FZ8">Panasonic DMC-FZ8</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ8" mode="4:3" decoder_version="2">
+ <ID make="Panasonic" model="DMC-FZ8">Panasonic DMC-FZ8</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="5" y="0" width="-31" height="-1"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ18" decoder_version="2">
+ <ID make="Panasonic" model="DMC-FZ18">Panasonic DMC-FZ18</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ18" mode="4:3" decoder_version="2">
+ <ID make="Panasonic" model="DMC-FZ18">Panasonic DMC-FZ18</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="10" y="0" width="-30" height="-1"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ18" mode="16:9">
+ <ID make="Panasonic" model="DMC-FZ18">Panasonic DMC-FZ18</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="9" y="0" width="-31" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-FZ18" mode="3:2">
+ <ID make="Panasonic" model="DMC-FZ18">Panasonic DMC-FZ18</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="9" y="0" width="-31" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-L1" decoder_version="2">
+ <ID make="Panasonic" model="DMC-L1">Panasonic DMC-L1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-11" height="-1"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-L1" mode="4:3" decoder_version="2">
+ <ID make="Panasonic" model="DMC-L1">Panasonic DMC-L1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-11" height="-1"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LX2" decoder_version="2">
+ <ID make="Panasonic" model="DMC-LX2">Panasonic DMC-LX2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LX2" mode="16:9" decoder_version="2">
+ <ID make="Panasonic" model="DMC-LX2">Panasonic DMC-LX2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="4" y="0" width="-38" height="-3"/>
+ <Sensor black="0" white="3986"/>
+ </Camera>
+ <!-- Leica D-Lux 4 is the same camera as LX-3 -->
+ <Camera make="LEICA" model = "D-LUX 4">
+ <ID make="Leica" model="D-LUX 4">Leica D-LUX 4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-84" height="0"/>
+ <Sensor black="15" white="3971"/>
+ </Camera>
+ <Camera make="LEICA" model = "D-LUX 4" mode="16:9">
+ <ID make="Leica" model="D-LUX 4">Leica D-LUX 4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3990" height="2250"/>
+ <Sensor black="15" white="3971"/>
+ </Camera>
+ <Camera make="LEICA" model = "D-LUX 4" mode="4:3">
+ <ID make="Leica" model="D-LUX 4">Leica D-LUX 4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3666" height="2754"/>
+ <Sensor black="15" white="3971"/>
+ </Camera>
+ <Camera make="LEICA" model = "D-LUX 4" mode="3:2">
+ <ID make="Leica" model="D-LUX 4">Leica D-LUX 4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="0"/>
+ <Sensor black="15" white="3971"/>
+ </Camera>
+
+ <Camera make="Panasonic" model = "DMC-LX5">
+ <ID make="Panasonic" model="DMC-LX5">Panasonic DMC-LX5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-200" height="-4"/>
+ <Sensor black="150" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX5" mode="4:3">
+ <ID make="Panasonic" model="DMC-LX5">Panasonic DMC-LX5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-200" height="-4"/>
+ <Sensor black="150" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX5" mode="3:2">
+ <ID make="Panasonic" model="DMC-LX5">Panasonic DMC-LX5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-74" height="-4"/>
+ <Sensor black="150" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX5" mode="16:9">
+ <ID make="Panasonic" model="DMC-LX5">Panasonic DMC-LX5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-104" height="-4"/>
+ <Sensor black="150" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX5" mode="1:1">
+ <ID make="Panasonic" model="DMC-LX5">Panasonic DMC-LX5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-220" height="-4"/>
+ <Sensor black="150" white="3986"/>
+ </Camera>
+ <!-- Leica D-Lux 5 is the same camera as LX-5 -->
+ <Camera make="LEICA" model = "D-LUX 5">
+ <ID make="Leica" model="D-LUX 5">Leica D-LUX 5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-200" height="-4"/>
+ <Sensor black="150" white="3986"/>
+ </Camera>
+ <Camera make="LEICA" model = "D-LUX 5" mode="4:3">
+ <ID make="Leica" model="D-LUX 5">Leica D-LUX 5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-200" height="-4"/>
+ <Sensor black="150" white="3986"/>
+ </Camera>
+ <Camera make="LEICA" model = "D-LUX 5" mode="3:2">
+ <ID make="Leica" model="D-LUX 5">Leica D-LUX 5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-74" height="-4"/>
+ <Sensor black="150" white="3986"/>
+ </Camera>
+ <Camera make="LEICA" model = "D-LUX 5" mode="16:9">
+ <ID make="Leica" model="D-LUX 5">Leica D-LUX 5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-104" height="-4"/>
+ <Sensor black="150" white="3986"/>
+ </Camera>
+ <Camera make="LEICA" model = "D-LUX 5" mode="1:1">
+ <ID make="Leica" model="D-LUX 5">Leica D-LUX 5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-220" height="-4"/>
+ <Sensor black="150" white="3986"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX7">
+ <ID make="Panasonic" model="DMC-LX7">Panasonic DMC-LX7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-34" height="0"/>
+ <Sensor black="150" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX7" mode="4:3">
+ <ID make="Panasonic" model="DMC-LX7">Panasonic DMC-LX7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-34" height="0"/>
+ <Sensor black="150" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX7" mode="3:2">
+ <ID make="Panasonic" model="DMC-LX7">Panasonic DMC-LX7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="150" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX7" mode="16:9">
+ <ID make="Panasonic" model="DMC-LX7">Panasonic DMC-LX7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-160" height="0"/>
+ <Sensor black="150" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model = "DMC-LX7" mode="1:1">
+ <ID make="Panasonic" model="DMC-LX7">Panasonic DMC-LX7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-48" height="0"/>
+ <Sensor black="150" white="3971"/>
+ </Camera>
+ <!-- LEICA D-LUX 6 is the same camera as Panasonic DMC-LX7 -->
+ <Camera make="LEICA" model = "D-LUX 6">
+ <ID make="Leica" model="D-LUX 6">Leica D-LUX 6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-34" height="0"/>
+ <Sensor black="150" white="3971"/>
+ </Camera>
+ <Camera make="LEICA" model = "D-LUX 6" mode="4:3">
+ <ID make="Leica" model="D-LUX 6">Leica D-LUX 6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-34" height="0"/>
+ <Sensor black="150" white="3971"/>
+ </Camera>
+ <Camera make="LEICA" model = "D-LUX 6" mode="3:2">
+ <ID make="Leica" model="D-LUX 6">Leica D-LUX 6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="150" white="3971"/>
+ </Camera>
+ <Camera make="LEICA" model = "D-LUX 6" mode="16:9">
+ <ID make="Leica" model="D-LUX 6">Leica D-LUX 6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-160" height="0"/>
+ <Sensor black="150" white="3971"/>
+ </Camera>
+ <Camera make="LEICA" model = "D-LUX 6" mode="1:1">
+ <ID make="Leica" model="D-LUX 6">Leica D-LUX 6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-48" height="0"/>
+ <Sensor black="150" white="3971"/>
+ </Camera>
+ <Camera make="LEICA" model="D-LUX (Typ 109)">
+ <ID make="Leica" model="D-LUX (Typ 109)">Leica D-LUX (Typ 109)</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="LEICA" model="D-LUX (Typ 109)" mode="4:3">
+ <ID make="Leica" model="D-LUX (Typ 109)">Leica D-LUX (Typ 109)</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-16" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="LEICA" model="D-LUX (Typ 109)" mode="3:2">
+ <ID make="Leica" model="D-LUX (Typ 109)">Leica D-LUX (Typ 109)</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-80" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="LEICA" model="D-LUX (Typ 109)" mode="16:9">
+ <ID make="Leica" model="D-LUX (Typ 109)">Leica D-LUX (Typ 109)</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-98" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="LEICA" model="D-LUX (Typ 109)" mode="1:1">
+ <ID make="Leica" model="D-LUX (Typ 109)">Leica D-LUX (Typ 109)</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-144" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LX1" mode="16:9">
+ <ID make="Panasonic" model="DMC-LX1">Panasonic DMC-LX1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="6" y="0" width="-16" height="0"/>
+ <Sensor black="0" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LX1">
+ <ID make="Panasonic" model="DMC-LX1">Panasonic DMC-LX1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LX100">
+ <ID make="Panasonic" model="DMC-LX100">Panasonic DMC-LX100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LX100" mode="4:3">
+ <ID make="Panasonic" model="DMC-LX100">Panasonic DMC-LX100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-16" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LX100" mode="16:9">
+ <ID make="Panasonic" model="DMC-LX100">Panasonic DMC-LX100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-96" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LX100" mode="3:2">
+ <ID make="Panasonic" model="DMC-LX100">Panasonic DMC-LX100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-80" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-LX100" mode="1:1">
+ <ID make="Panasonic" model="DMC-LX100">Panasonic DMC-LX100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-144" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ60">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="145" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ60" mode="3:2">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="145" white="3971"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ60" mode="16:9">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="145" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ60" mode="1:1">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-8" height="0"/>
+ <Sensor black="145" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ60" mode="4:3">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="145" white="3956"/>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ61">
+ <ID make="Panasonic" model="DMC-TZ61">Panasonic DMC-ZS40</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="145" white="3971"/>
+ <Aliases>
+ <Alias>DMC-ZS40</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ61" mode="4:3">
+ <ID make="Panasonic" model="DMC-TZ61">Panasonic DMC-ZS40</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-126" height="0"/>
+ <Sensor black="146" white="3971"/>
+ <Aliases>
+ <Alias>DMC-ZS40</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ61" mode="3:2">
+ <ID make="Panasonic" model="DMC-TZ61">Panasonic DMC-ZS40</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-126" height="0"/>
+ <Sensor black="146" white="3971"/>
+ <Aliases>
+ <Alias>DMC-ZS40</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ61" mode="1:1">
+ <ID make="Panasonic" model="DMC-TZ61">Panasonic DMC-ZS40</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-6" height="0"/>
+ <Sensor black="146" white="3971"/>
+ <Aliases>
+ <Alias>DMC-ZS40</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ61" mode="16:9">
+ <ID make="Panasonic" model="DMC-TZ61">Panasonic DMC-ZS40</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-126" height="0"/>
+ <Sensor black="146" white="3971"/>
+ <Aliases>
+ <Alias>DMC-ZS40</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ71">
+ <ID make="Panasonic" model="DMC-TZ71">Panasonic DMC-ZS50</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="143" white="3971"/>
+ <Aliases>
+ <Alias>DMC-ZS50</Alias>
+ <Alias>DMC-TZ70</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ71" mode="4:3">
+ <ID make="Panasonic" model="DMC-TZ71">Panasonic DMC-ZS50</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="143" white="3971"/>
+ <Aliases>
+ <Alias>DMC-ZS50</Alias>
+ <Alias>DMC-TZ70</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ71" mode="3:2">
+ <ID make="Panasonic" model="DMC-TZ71">Panasonic DMC-ZS50</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="142" white="3971"/>
+ <Aliases>
+ <Alias>DMC-ZS50</Alias>
+ <Alias>DMC-TZ70</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ71" mode="16:9">
+ <ID make="Panasonic" model="DMC-TZ71">Panasonic DMC-ZS50</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="143" white="3971"/>
+ <Aliases>
+ <Alias>DMC-ZS50</Alias>
+ <Alias>DMC-TZ70</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ71" mode="1:1">
+ <ID make="Panasonic" model="DMC-TZ71">Panasonic DMC-ZS50</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-16" height="0"/>
+ <Sensor black="143" white="3971"/>
+ <Aliases>
+ <Alias>DMC-ZS50</Alias>
+ <Alias>DMC-TZ70</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ81">
+ <ID make="Panasonic" model="DMC-TZ81">Panasonic DMC-ZS60</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="142" white="4095"/>
+ <Aliases>
+ <Alias>DMC-ZS60</Alias>
+ <Alias>DMC-TZ80</Alias>
+ <Alias>DMC-TZ85</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ81" mode="4:3">
+ <ID make="Panasonic" model="DMC-TZ81">Panasonic DMC-ZS60</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="142" white="4095"/>
+ <Aliases>
+ <Alias>DMC-ZS60</Alias>
+ <Alias>DMC-TZ80</Alias>
+ <Alias>DMC-TZ85</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ100">
+ <ID make="Panasonic" model="DMC-TZ100">Panasonic DMC-ZS100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="142" white="4095"/>
+ <Aliases>
+ <Alias>DMC-ZS110</Alias>
+ <Alias>DMC-TZ101</Alias>
+ <Alias>DMC-TZ110</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DMC-TZ100" mode="3:2">
+ <ID make="Panasonic" model="DMC-TZ100">Panasonic DMC-ZS100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="142" white="4095"/>
+ <Aliases>
+ <Alias>DMC-ZS110</Alias>
+ <Alias>DMC-TZ101</Alias>
+ <Alias>DMC-TZ110</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DC-FZ82">
+ <ID make="Panasonic" model="DC-FZ82">Panasonic DC-FZ82</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Aliases>
+ <Alias>DMC-FZ80</Alias>
+ <Alias>DMC-FZ85</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DC-FZ82" mode="4:3">
+ <ID make="Panasonic" model="DC-FZ82">Panasonic DC-FZ82</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="143" white="4095"/>
+ <Aliases>
+ <Alias>DMC-FZ80</Alias>
+ <Alias>DMC-FZ85</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DC-GH5">
+ <ID make="Panasonic" model="DC-GH5">Panasonic DC-GH5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-56" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DC-GH5" mode="4:3">
+ <ID make="Panasonic" model="DC-GH5">Panasonic DC-GH5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-56" height="0"/>
+ <Sensor black="143" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DC-G9">
+ <ID make="Panasonic" model="DC-G9">Panasonic DC-G9</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-58" height="0"/>
+ <Sensor black="148" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DC-G9" mode="4:3">
+ <ID make="Panasonic" model="DC-G9">Panasonic DC-G9</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-58" height="0"/>
+ <Sensor black="148" white="4095"/>
+ </Camera>
+ <Camera make="Panasonic" model="DC-TZ90">
+ <ID make="Panasonic" model="DC-TZ90">Panasonic DC-ZS70</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-64" height="0"/>
+ <Sensor black="139" white="4095"/>
+ <Aliases>
+ <Alias>DC-ZS70</Alias>
+ <Alias>DC-FZ91</Alias>
+ <Alias>DC-FZ92</Alias>
+ <Alias>DC-FZ93</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Panasonic" model="DC-TZ90" mode="4:3">
+ <ID make="Panasonic" model="DC-TZ90">Panasonic DC-ZS70</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-64" height="0"/>
+ <Sensor black="139" white="4095"/>
+ <Aliases>
+ <Alias>DC-ZS70</Alias>
+ <Alias>DC-FZ91</Alias>
+ <Alias>DC-FZ92</Alias>
+ <Alias>DC-FZ93</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="PENTAX Corporation" model="PENTAX K100D">
+ <ID make="Pentax" model="K100D">Pentax K100D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3040" height="2024"/>
+ <Sensor black="127" white="3950"/>
+ </Camera>
+ <Camera make="PENTAX Corporation" model="PENTAX K110D">
+ <ID make="Pentax" model="K110D">Pentax K110D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="127" white="4095"/>
+ </Camera>
+ <Camera make="PENTAX Corporation" model="PENTAX K100D Super">
+ <ID make="Pentax" model="K100D Super">Pentax K100D Super</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="127" white="4095"/>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K100D">
+ <ID make="Pentax" model="K100D">Pentax K100D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3040" height="2024"/>
+ <Sensor black="127" white="3950"/>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K110D">
+ <ID make="Pentax" model="K110D">Pentax K110D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="127" white="4095"/>
+ </Camera>
+ <Camera make="PENTAX Corporation" model="PENTAX *ist D">
+ <ID make="Pentax" model="*ist D">Pentax *ist D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="128" white="4095"/>
+ </Camera>
+ <Camera make="PENTAX Corporation" model="PENTAX *ist DL">
+ <ID make="Pentax" model="*ist DL">Pentax *ist DL</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="128" white="4095"/>
+ </Camera>
+ <Camera make="PENTAX Corporation" model="PENTAX *ist DL2">
+ <ID make="Pentax" model="*ist DL2">Pentax *ist DL2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="127" white="3950"/>
+ </Camera>
+ <Camera make="PENTAX Corporation" model="PENTAX *ist DS">
+ <ID make="Pentax" model="*ist DS">Pentax *ist DS</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="-2"/>
+ <Sensor black="128" white="3950"/>
+ </Camera>
+ <Camera make="PENTAX Corporation" model="PENTAX K10D">
+ <ID make="Pentax" model="K10D">Pentax K10D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3888" height="2608"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="PENTAX Corporation" model="PENTAX K20D">
+ <ID make="Pentax" model="K20D">Pentax K20D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4688" height="3124"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K20D">
+ <ID make="Pentax" model="K20D">Pentax K20D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4688" height="3124"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="PENTAX Corporation" model="PENTAX K200D">
+ <ID make="Pentax" model="K200D">Pentax K200D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3880" height="2604"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="RICOH IMAGING COMPANY, LTD." model="PENTAX K-S1">
+ <ID make="Pentax" model="K-S1">Pentax K-S1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-12" height="0"/>
+ <Sensor black="32" white="4062"/>
+ </Camera>
+ <Camera make="RICOH IMAGING COMPANY, LTD." model="PENTAX K-S2">
+ <ID make="Pentax" model="K-S2">Pentax K-S2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-12" height="0"/>
+ <Sensor black="0" white="3839"/>
+ </Camera>
+ <Camera make="RICOH IMAGING COMPANY, LTD." model="PENTAX K-70">
+ <ID make="Pentax" model="K-70">PENTAX K-70</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="58" y="30" width="0" height="-14"/>
+ <Sensor black="64" white="16319"/>
+ </Camera>
+ <Camera make="RICOH IMAGING COMPANY, LTD." model="PENTAX K-1">
+ <ID make="Pentax" model="K-1">Pentax K-1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="4" y="18" width="-10" height="-2"/>
+ <Sensor black="64" white="16316"/>
+ </Camera>
+ <Camera make="RICOH IMAGING COMPANY, LTD." model="PENTAX K-3">
+ <ID make="Pentax" model="K-3">Pentax K-3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="4" y="0" width="-36" height="0"/>
+ <Sensor black="1" white="15868"/>
+ </Camera>
+ <Camera make="RICOH IMAGING COMPANY, LTD." model="PENTAX K-3 II">
+ <ID make="Pentax" model="K-3 II">PENTAX K-3 II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="4" y="0" width="-36" height="0"/>
+ <Sensor black="1" white="15865"/>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-5" decoder_version="2">
+ <ID make="Pentax" model="K-5">PENTAX K-5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="12" y="0" width="-34" height="0"/>
+ <Sensor black="512" white="16383"/>
+ <BlackAreas>
+ <Vertical x="0" width="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-5" mode="dng">
+ <ID make="Pentax" model="K-5">PENTAX K-5</ID>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-5 II" decoder_version="2">
+ <ID make="Pentax" model="K-5 II">PENTAX K-5 II</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="12" y="0" width="-34" height="0"/>
+ <Sensor black="512" white="16383"/>
+ <BlackAreas>
+ <Vertical x="0" width="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-5 II s" decoder_version="2">
+ <ID make="Pentax" model="K-5 II s">PENTAX K-5 II s</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="12" y="0" width="-34" height="0"/>
+ <Sensor black="512" white="15863"/>
+ <BlackAreas>
+ <Vertical x="0" width="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-7">
+ <ID make="Pentax" model="K-7">PENTAX K-7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4672" height="3104"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-m">
+ <ID make="Pentax" model="K-m">Pentax K-m</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3900" height="2616"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-x">
+ <ID make="Pentax" model="K-x">PENTAX K-x</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-44" height="-2"/>
+ <Sensor black="41" white="4095"/>
+ <BlackAreas>
+ <Vertical x="4310" width="40"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-r" decoder_version="3">
+ <ID make="Pentax" model="K-r">PENTAX K-r</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="2" y="2" width="-44" height="0"/>
+ <Sensor black="64" white="4000"/>
+ </Camera>
+ <Camera make="RICOH IMAGING COMPANY, LTD." model="PENTAX KP">
+ <ID make="Pentax" model="KP">Pentax KP</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="60" y="32" width="-28" height="-4"/>
+ <Sensor black="128" white="16254"/>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K200D">
+ <ID make="Pentax" model="K200D">Pentax K200D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-42" height="-10"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K2000">
+ <ID make="Pentax" model="K2000">Pentax K2000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3900" height="2616"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SAMSUNG" model="EX2F">
+ <ID make="Samsung" model="EX2F">Samsung EX2F</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="22" y="12" width="-148" height="-18"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SAMSUNG" model="EX1">
+ <ID make="Samsung" model="EX1">Samsung EX1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="2" width="-8" height="-22"/>
+ <Sensor black="0" white="16383"/>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX1">
+ <ID make="Samsung" model="NX1">Samsung NX1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="1024" white="16100" iso_min="51200"/>
+ <Sensor black="512" white="16100" iso_min="8000" iso_max="25600"/>
+ <Sensor black="128" white="16100"/>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX1" mode="12bit">
+ <ID make="Samsung" model="NX1">Samsung NX1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="128" white="4000" iso_min="8000"/>
+ <Sensor black="32" white="4000"/>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX5">
+ <ID make="Samsung" model="NX5">Samsung NX5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="17" y="8" width="4602" height="3068"/>
+ <Sensor black="0" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX10">
+ <ID make="Samsung" model="NX10">Samsung NX10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="17" y="8" width="4602" height="3068"/>
+ <Sensor black="0" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="8"/>
+ <Horizontal y="0" height="2"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX11">
+ <ID make="Samsung" model="NX11">Samsung NX11</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="17" y="8" width="4602" height="3068"/>
+ <Sensor black="0" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="8"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX100">
+ <ID make="Samsung" model="NX100">Samsung NX100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="17" y="8" width="4602" height="3068"/>
+ <Sensor black="0" white="4095"/>
+ <BlackAreas>
+ <Vertical x="0" width="8"/>
+ <Horizontal y="0" height="2"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX1000" decoder_version="2">
+ <ID make="Samsung" model="NX1000">Samsung NX1000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="89" y="17" width="-71" height="-55"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="msb_override" value="false"/>
+ </Hints>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX1100" decoder_version="2">
+ <ID make="Samsung" model="NX1100">Samsung NX1100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="89" y="17" width="-71" height="-55"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="msb_override" value="false"/>
+ </Hints>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX20" decoder_version="2">
+ <ID make="Samsung" model="NX20">Samsung NX20</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="89" y="17" width="-71" height="-55"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="msb_override" value="false"/>
+ </Hints>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX200" decoder_version="2">
+ <ID make="Samsung" model="NX200">Samsung NX200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="89" y="17" width="-71" height="-55"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="msb_override" value="false"/>
+ </Hints>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX210" decoder_version="2">
+ <ID make="Samsung" model="NX210">Samsung NX210</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="89" y="17" width="-71" height="-55"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="msb_override" value="false"/>
+ </Hints>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX2000" decoder_version="3">
+ <ID make="Samsung" model="NX2000">Samsung NX2000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="45" y="25" width="-11" height="-29"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX30" decoder_version="3">
+ <ID make="Samsung" model="NX30">Samsung NX30</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="45" y="25" width="-11" height="-29"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX300" decoder_version="3">
+ <ID make="Samsung" model="NX300">Samsung NX300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="45" y="25" width="-11" height="-29"/>
+ <Sensor black="0" white="4095"/>
+ <Aliases>
+ <Alias>NX300M</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX3000">
+ <ID make="Samsung" model="NX3000">Samsung NX3000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="96" y="42" width="-32" height="-24"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX500">
+ <ID make="Samsung" model="NX500">Samsung NX500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="1024" white="16100" iso_min="51200"/>
+ <Sensor black="512" white="16100" iso_min="8000" iso_max="25600"/>
+ <Sensor black="128" white="16100"/>
+ </Camera>
+ <Camera make="SAMSUNG" model="NX500" mode="12bit">
+ <ID make="Samsung" model="NX500">Samsung NX500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="128" white="4000" iso_min="8000"/>
+ <Sensor black="32" white="4000"/>
+ </Camera>
+ <Camera make="SAMSUNG" model="EK-GN120" decoder_version="3">
+ <ID make="Samsung" model="EK-GN120">Samsung EK-GN120</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="45" y="25" width="-11" height="-29"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SAMSUNG" model="WB2000">
+ <ID make="Samsung" model="WB2000">Samsung WB2000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="2" width="-10" height="-2"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SONY" model="DSC-RX10">
+ <ID make="Sony" model="DSC-RX10">Sony DSC-RX10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-8" height="0"/>
+ <Sensor black="800" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="DSC-RX10M2">
+ <ID make="Sony" model="DSC-RX10M2">Sony DSC-RX10M2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-8" height="0"/>
+ <Sensor black="800" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="DSC-RX10M3">
+ <ID make="Sony" model="DSC-RX10M3">Sony DSC-RX10M3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-8" height="0"/>
+ <Sensor black="800" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="DSC-RX100">
+ <ID make="Sony" model="DSC-RX100">Sony DSC-RX100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-12" height="0"/>
+ <Sensor black="800" white="16620"/>
+ </Camera>
+ <Camera make="SONY" model="DSC-RX100M2">
+ <ID make="Sony" model="DSC-RX100M2">Sony DSC-RX100M2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-12" height="0"/>
+ <Sensor black="800" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="DSC-RX100M3">
+ <ID make="Sony" model="DSC-RX100M3">Sony DSC-RX100M3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-12" height="0"/>
+ <Sensor black="800" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="DSC-RX100M4">
+ <ID make="Sony" model="DSC-RX100M4">Sony DSC-RX100M4</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="800" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="DSC-RX100M5">
+ <ID make="Sony" model="DSC-RX100M5">Sony DSC-RX100M5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-8" height="0"/>
+ <Sensor black="800" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="DSC-RX1R">
+ <ID make="Sony" model="DSC-RX1R">Sony DSC-RX1R</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-16" height="0"/>
+ <Sensor black="512" white="33192" iso_list="50"/>
+ <Sensor black="512" white="16596"/>
+ <BlackAreas>
+ <Vertical x="6032" width="14"/>
+ </BlackAreas>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A100" decoder_version="1">
+ <ID make="Sony" model="DSLR-A100">Sony DSLR-A100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-1" height="-2"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A200">
+ <ID make="Sony" model="DSLR-A200">Sony DSLR-A200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3878" height="2600"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A230">
+ <ID make="Sony" model="DSLR-A230">Sony DSLR-A230</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A290">
+ <ID make="Sony" model="DSLR-A290">Sony DSLR-A290</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A300">
+ <ID make="Sony" model="DSLR-A300">Sony DSLR-A300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3878" height="2600"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A330">
+ <ID make="Sony" model="DSLR-A330">Sony DSLR-A330</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="3878" height="2600"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A350">
+ <ID make="Sony" model="DSLR-A350">Sony DSLR-A350</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4599" height="3064"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A380">
+ <ID make="Sony" model="DSLR-A380">Sony DSLR-A380</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A390">
+ <ID make="Sony" model="DSLR-A390">Sony DSLR-A390</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A450">
+ <ID make="Sony" model="DSLR-A450">Sony DSLR-A450</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="500" white="16000"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A500">
+ <ID make="Sony" model="DSLR-A500">Sony DSLR-A500</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="1">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="0" y="0">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="500" white="16600"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A550">
+ <ID make="Sony" model="DSLR-A550">Sony DSLR-A550</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="1">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="0" y="0">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="512" white="16372"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A560">
+ <ID make="Sony" model="DSLR-A560">Sony DSLR-A560</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="1">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="0" y="0">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="476" white="16596"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A580">
+ <ID make="Sony" model="DSLR-A580">Sony DSLR-A580</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="1">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="0" y="0">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-2" height="-2"/>
+ <Sensor black="520" white="16596"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A700">
+ <ID make="Sony" model="DSLR-A700">Sony DSLR-A700</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="1">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="0" y="0">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="4288" height="2856"/>
+ <Sensor black="520" white="16383"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A850">
+ <ID make="Sony" model="DSLR-A850">Sony DSLR-A850</ID>
+ <CFA width="2" height="2">
+ <Color x="1" y="1">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="0" y="0">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="6080" height="4048"/>
+ <Sensor black="500" white="15000"/>
+ </Camera>
+ <Camera make="SONY" model="DSLR-A900">
+ <ID make="Sony" model="DSLR-A900">Sony DSLR-A900</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="6080" height="4048"/>
+ <Sensor black="520" white="16383"/>
+ </Camera>
+ <Camera make="SONY" model="NEX-3">
+ <ID make="Sony" model="NEX-3">Sony NEX-3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="520" white="16360"/>
+ </Camera>
+ <Camera make="SONY" model="NEX-3N">
+ <ID make="Sony" model="NEX-3N">Sony NEX-3N</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-10" height="0"/>
+ <Sensor black="520" white="16596"/>
+ </Camera>
+ <Camera make="SONY" model="NEX-5">
+ <ID make="Sony" model="NEX-5">Sony NEX-5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="520" white="16383"/>
+ </Camera>
+ <Camera make="SONY" model="NEX-5N">
+ <ID make="Sony" model="NEX-5N">Sony NEX-5N</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-12" height="0"/>
+ <Sensor black="520" white="16596"/>
+ </Camera>
+ <Camera make="SONY" model="NEX-5R">
+ <ID make="Sony" model="NEX-5R">Sony NEX-5R</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-12" height="0"/>
+ <Sensor black="520" white="16596"/>
+ </Camera>
+ <Camera make="SONY" model="NEX-5T">
+ <ID make="Sony" model="NEX-5T">Sony NEX-5T</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-12" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="NEX-6">
+ <ID make="Sony" model="NEX-6">Sony NEX-6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-16" height="0"/>
+ <Sensor black="520" white="16596"/>
+ </Camera>
+ <!-- Measured on images from https://github.com/klauspost/rawspeed/issues/78 -->
+ <Camera make="SONY" model="NEX-7">
+ <ID make="Sony" model="NEX-7">Sony NEX-7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-26" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="NEX-C3">
+ <ID make="Sony" model="NEX-C3">Sony NEX-C3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="520" white="16596"/>
+ </Camera>
+ <Camera make="SONY" model="NEX-F3">
+ <ID make="Sony" model="NEX-F3">Sony NEX-F3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="520" white="16360"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-3000">
+ <ID make="Sony" model="ILCE-3000">Sony ILCE-3000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-34" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-3500">
+ <ID make="Sony" model="ILCE-3500">Sony ILCE-3500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-34" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-5000">
+ <ID make="Sony" model="ILCE-5000">Sony ILCE-5000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-34" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-5100">
+ <ID make="Sony" model="ILCE-5100">Sony ILCE-5100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-26" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-6000">
+ <ID make="Sony" model="ILCE-6000">Sony ILCE-6000</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-28" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-6300">
+ <ID make="Sony" model="ILCE-6300">Sony ILCE-6300</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-28" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-6500">
+ <ID make="Sony" model="ILCE-6500">Sony ILCE-6500</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-28" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-7">
+ <ID make="Sony" model="ILCE-7">Sony ILCE-7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-26" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-7M2">
+ <ID make="Sony" model="ILCE-7M2">Sony ILCE-7M2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-26" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-7R">
+ <ID make="Sony" model="ILCE-7R">Sony ILCE-7R</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-26" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-7RM2">
+ <ID make="Sony" model="ILCE-7RM2">Sony ILCE-7RM2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-7RM3">
+ <ID make="Sony" model="ILCE-7RM3">Sony ILCE-7RM3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="512" white="16383"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-7S">
+ <ID make="Sony" model="ILCE-7S">Sony ILCE-7S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-7SM2">
+ <ID make="Sony" model="ILCE-7SM2">Sony ILCE-7SM2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCE-9">
+ <ID make="Sony" model="ILCE-9">Sony ILCE-9</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="512" white="16383"/>
+ </Camera>
+ <Camera make="SONY" model="DSC-RX1">
+ <ID make="Sony" model="DSC-RX1">Sony DSC-RX1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-18" height="0"/>
+ <Sensor black="520" white="16628"/>
+ </Camera>
+ <Camera make="SONY" model="SLT-A33">
+ <ID make="Sony" model="SLT-A33">Sony SLT-A33</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="520" white="16596"/>
+ </Camera>
+ <Camera make="SONY" model="SLT-A35">
+ <ID make="Sony" model="SLT-A35">Sony SLT-A35</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="545" white="16596"/>
+ </Camera>
+ <Camera make="SONY" model="SLT-A37">
+ <ID make="Sony" model="SLT-A37">Sony SLT-A37</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-10" height="0"/>
+ <Sensor black="520" white="16500"/>
+ </Camera>
+ <Camera make="SONY" model="SLT-A55">
+ <ID make="Sony" model="SLT-A55">Sony SLT-A55</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="520" white="16596"/>
+ <Aliases>
+ <Alias id="SLT-A55">SLT-A55V</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="SONY" model="SLT-A57">
+ <ID make="Sony" model="SLT-A57">Sony SLT-A57</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="512" white="16596"/>
+ </Camera>
+ <Camera make="SONY" model="SLT-A58">
+ <ID make="Sony" model="SLT-A58">Sony SLT-A58</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-36" height="0"/>
+ <Sensor black="520" white="16596"/>
+ </Camera>
+ <Camera make="SONY" model="SLT-A65">
+ <ID make="Sony" model="SLT-A65">Sony SLT-A65</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-30" height="0"/>
+ <Sensor black="520" white="16596"/>
+ <Aliases>
+ <Alias id="SLT-A65">SLT-A65V</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="SONY" model="SLT-A77">
+ <ID make="Sony" model="SLT-A77">Sony SLT-A77</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-28" height="0"/>
+ <Sensor black="520" white="16596"/>
+ <Aliases>
+ <Alias id="SLT-A77">SLT-A77V</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="SONY" model="ILCA-77M2">
+ <ID make="Sony" model="ILCA-77M2">Sony ILCA-77M2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-26" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCA-68">
+ <ID make="Sony" model="ILCA-68">Sony ILCA-68</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="ILCA-99M2">
+ <ID make="Sony" model="ILCA-99M2">Sony ILCA-99M2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-32" height="0"/>
+ <Sensor black="512" white="16300"/>
+ </Camera>
+ <Camera make="SONY" model="SLT-A99">
+ <ID make="Sony" model="SLT-A99">Sony SLT-A99</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-28" height="0"/>
+ <Sensor black="520" white="16596"/>
+ <Aliases>
+ <Alias id="SLT-A99">SLT-A99V</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Sinar Photography AG" model="Sinar Hy6/ Sinarback eXact" mode="dng">
+ <ID make="Sinar" model="Hy6">Sinar Hy6</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="0"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S6000fd">
+ <ID make="Fujifilm" model="FinePix S6000fd">Fujifilm FinePix S6000fd</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15872"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S100FS">
+ <ID make="Fujifilm" model="FinePix S100FS">Fujifilm FinePix S100FS</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="64" y="0" width="-64" height="0"/>
+ <Sensor black="512" white="16383"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S200EXR">
+ <ID make="Fujifilm" model="FinePix S200EXR">Fujifilm FinePix S200EXR</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="28" y="0" width="-28" height="0"/>
+ <Sensor black="519" white="16250"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix F600EXR">
+ <ID make="Fujifilm" model="FinePix F600EXR">Fujifilm FinePix F600EXR</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="34" y="0" width="-32" height="0"/>
+ <Sensor black="256" white="3900"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix F700">
+ <ID make="Fujifilm" model="FinePix F700">Fujifilm FinePix F700</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="16" y="0" width="-16" height="0"/>
+ <Sensor black="0" white="16383"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ <Hint name="double_width_unpacked" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix F900EXR">
+ <ID make="Fujifilm" model="FinePix F900EXR">Fujifilm FinePix F900EXR</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-64" height="0"/>
+ <Sensor black="256" white="3900"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix E550">
+ <ID make="Fujifilm" model="FinePix E550">Fujifilm FinePix E550</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15875"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="IS-1">
+ <ID make="Fujifilm" model="IS-1">Fujifilm IS-1</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="32" y="0" width="-32" height="0"/>
+ <Sensor black="0" white="15872"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S3Pro">
+ <ID make="Fujifilm" model="FinePix S3Pro">Fujifilm FinePix S3Pro</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="32" y="2" width="-32" height="-2"/>
+ <Sensor black="0" white="15872"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S5Pro">
+ <ID make="Fujifilm" model="FinePix S5Pro">Fujifilm FinePix S5Pro</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="32" y="2" width="-32" height="-2"/>
+ <Sensor black="0" white="15872"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S5600">
+ <ID make="Fujifilm" model="FinePix S5600">Fujifilm FinePix S5600</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="30" y="0" width="-30" height="0"/>
+ <Sensor black="0" white="15872"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix E900">
+ <ID make="Fujifilm" model="FinePix E900">Fujifilm FinePix E900</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="32" y="0" width="-32" height="0"/>
+ <Sensor black="0" white="15872"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePixS2Pro">
+ <ID make="Fujifilm" model="FinePix S2Pro">Fujifilm FinePix S2Pro</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="32" y="32" width="-32" height="-32"/>
+ <Sensor black="128" white="4095"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S5000">
+ <ID make="Fujifilm" model="FinePix S5000">Fujifilm FinePix S5000</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="24" y="4" width="-24" height="-4"/>
+ <Sensor black="0" white="15872"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S5200">
+ <ID make="Fujifilm" model="FinePix S5200">Fujifilm FinePix S5200</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="30" y="4" width="-30" height="-4"/>
+ <Sensor black="0" white="15872"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S5500">
+ <ID make="Fujifilm" model="FinePix S5500">Fujifilm FinePix S5500</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15872"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S6500fd">
+ <ID make="Fujifilm" model="FinePix S6500fd">Fujifilm FinePix S6500fd</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="64" y="0" width="-64" height="0"/>
+ <Sensor black="0" white="15872"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S9500">
+ <ID make="Fujifilm" model="FinePix S9500">Fujifilm FinePix S9500</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="32" y="0" width="-32" height="0"/>
+ <Sensor black="0" white="15872"/>
+ <Aliases>
+ <Alias>FinePix S9000</Alias>
+ </Aliases>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S9600">
+ <ID make="Fujifilm" model="FinePix S9600">Fujifilm FinePix S9600</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="32" y="0" width="-32" height="0"/>
+ <Sensor black="0" white="15872"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix S9600fd">
+ <ID make="Fujifilm" model="FinePix S9600fd">Fujifilm FinePix S9600fd</ID>
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="64" y="0" width="-64" height="0"/>
+ <Sensor black="0" white="15872"/>
+ <Hints>
+ <Hint name="fuji_rotate" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix HS10 HS11">
+ <ID make="Fujifilm" model="FinePix HS10 HS11">Fujifilm FinePix HS10 HS11</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="50" white="3900"/>
+ <Hints>
+ <Hint name="jpeg32_bitorder" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix HS20EXR">
+ <ID make="Fujifilm" model="FinePix HS20EXR">Fujifilm FinePix HS20EXR</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="34" y="0" width="-32" height="0"/>
+ <Sensor black="256" white="3900"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix HS30EXR">
+ <ID make="Fujifilm" model="FinePix HS30EXR">Fujifilm FinePix HS30EXR</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="34" y="0" width="-32" height="0"/>
+ <Sensor black="258" white="3900"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix HS50EXR">
+ <ID make="Fujifilm" model="FinePix HS50EXR">Fujifilm FinePix HS50EXR</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-64" height="0"/>
+ <Sensor black="256" white="3900"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="FinePix X100">
+ <ID make="Fujifilm" model="FinePix X100">Fujifilm FinePix X100</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="73" y="1" width="-73" height="-1"/>
+ <Sensor black="254" white="4000"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X10">
+ <ID make="Fujifilm" model="FinePix X10">Fujifilm FinePix X10</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="48" y="0" width="-48" height="0"/>
+ <Sensor black="256" white="4000"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-S1">
+ <ID make="Fujifilm" model="X-S1">Fujifilm X-S1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="48" y="0" width="-48" height="0"/>
+ <Sensor black="260" white="4000"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="GFX 50S">
+ <ID make="Fujifilm" model="GFX 50S">Fujifilm GFX 50S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-936" height="0"/>
+ <Sensor black="65" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="GFX 50S" mode="compressed">
+ <ID make="Fujifilm" model="GFX 50S">Fujifilm GFX 50S</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-936" height="0"/>
+ <Sensor black="65" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-Pro1">
+ <ID make="Fujifilm" model="X-Pro1">Fujifilm X-Pro1</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GGRGGB</ColorRow>
+ <ColorRow y="1">GGBGGR</ColorRow>
+ <ColorRow y="2">BRGRBG</ColorRow>
+ <ColorRow y="3">GGBGGR</ColorRow>
+ <ColorRow y="4">GGRGGB</ColorRow>
+ <ColorRow y="5">RBGBRG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-168" height="0"/>
+ <Sensor black="256" white="4094"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-Pro2">
+ <ID make="Fujifilm" model="X-Pro2">Fujifilm X-Pro2</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-Pro2" mode="compressed">
+ <ID make="Fujifilm" model="X-Pro2">Fujifilm X-Pro2</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GGRGGB</ColorRow>
+ <ColorRow y="1">GGBGGR</ColorRow>
+ <ColorRow y="2">BRGRBG</ColorRow>
+ <ColorRow y="3">GGBGGR</ColorRow>
+ <ColorRow y="4">GGRGGB</ColorRow>
+ <ColorRow y="5">RBGBRG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="12" width="-16" height="-12"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X70">
+ <ID make="Fujifilm" model="X70">Fujifilm X70</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="4" y="0" width="-52" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="XF1">
+ <ID make="Fujifilm" model="XF1">Fujifilm XF1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="48" y="0" width="-48" height="0"/>
+ <Sensor black="257" white="4000"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-E1">
+ <ID make="Fujifilm" model="X-E1">Fujifilm X-E1</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GGRGGB</ColorRow>
+ <ColorRow y="1">GGBGGR</ColorRow>
+ <ColorRow y="2">BRGRBG</ColorRow>
+ <ColorRow y="3">GGBGGR</ColorRow>
+ <ColorRow y="4">GGRGGB</ColorRow>
+ <ColorRow y="5">RBGBRG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-168" height="0"/>
+ <Sensor black="255" white="4094"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X20">
+ <ID make="Fujifilm" model="X20">Fujifilm X20</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GBGGRG</ColorRow>
+ <ColorRow y="1">RGRBGB</ColorRow>
+ <ColorRow y="2">GBGGRG</ColorRow>
+ <ColorRow y="3">GRGGBG</ColorRow>
+ <ColorRow y="4">BGBRGR</ColorRow>
+ <ColorRow y="5">GRGGBG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-64" height="0"/>
+ <Sensor black="257" white="4094"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X30">
+ <ID make="Fujifilm" model="X30">Fujifilm X30</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GBGGRG</ColorRow>
+ <ColorRow y="1">RGRBGB</ColorRow>
+ <ColorRow y="2">GBGGRG</ColorRow>
+ <ColorRow y="3">GRGGBG</ColorRow>
+ <ColorRow y="4">BGBRGR</ColorRow>
+ <ColorRow y="5">GRGGBG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-64" height="0"/>
+ <Sensor black="257" white="4094"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X100F">
+ <ID make="Fujifilm" model="X100F">Fujifilm X100F</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-126" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X100F" mode="compressed">
+ <ID make="Fujifilm" model="X100F">Fujifilm X100F</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GGRGGB</ColorRow>
+ <ColorRow y="1">GGBGGR</ColorRow>
+ <ColorRow y="2">BRGRBG</ColorRow>
+ <ColorRow y="3">GGBGGR</ColorRow>
+ <ColorRow y="4">GGRGGB</ColorRow>
+ <ColorRow y="5">RBGBRG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="12" width="-16" height="-12"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X100S">
+ <ID make="Fujifilm" model="X100S">Fujifilm X100S</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="4" y="0" width="-52" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X100T">
+ <ID make="Fujifilm" model="X100T">Fujifilm X100T</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="4" y="0" width="-52" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-M1">
+ <ID make="Fujifilm" model="X-M1">Fujifilm X-M1</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GGRGGB</ColorRow>
+ <ColorRow y="1">GGBGGR</ColorRow>
+ <ColorRow y="2">BRGRBG</ColorRow>
+ <ColorRow y="3">GGBGGR</ColorRow>
+ <ColorRow y="4">GGRGGB</ColorRow>
+ <ColorRow y="5">RBGBRG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-168" height="0"/>
+ <Sensor black="256" white="4094"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-A1">
+ <ID make="Fujifilm" model="X-A1">Fujifilm X-A1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-168" height="0"/>
+ <Sensor black="256" white="4094"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-A2">
+ <ID make="Fujifilm" model="X-A2">Fujifilm X-A2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-168" height="0"/>
+ <Sensor black="256" white="4094"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-A3">
+ <ID make="Fujifilm" model="X-A3">Fujifilm X-A3</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ <Hints>
+ <Hint name="jpeg32_bitorder" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="FUJIFILM" model="XQ1">
+ <ID make="Fujifilm" model="XQ1">Fujifilm XQ1</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GBGGRG</ColorRow>
+ <ColorRow y="1">RGRBGB</ColorRow>
+ <ColorRow y="2">GBGGRG</ColorRow>
+ <ColorRow y="3">GRGGBG</ColorRow>
+ <ColorRow y="4">BGBRGR</ColorRow>
+ <ColorRow y="5">GRGGBG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-64" height="0"/>
+ <Sensor black="257" white="4094"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="XQ2">
+ <ID make="Fujifilm" model="XQ2">Fujifilm XQ2</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GBGGRG</ColorRow>
+ <ColorRow y="1">RGRBGB</ColorRow>
+ <ColorRow y="2">GBGGRG</ColorRow>
+ <ColorRow y="3">GRGGBG</ColorRow>
+ <ColorRow y="4">BGBRGR</ColorRow>
+ <ColorRow y="5">GRGGBG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-64" height="0"/>
+ <Sensor black="257" white="4094"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-E2">
+ <ID make="Fujifilm" model="X-E2">Fujifilm X-E2</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="4" y="0" width="-52" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-E3">
+ <ID make="Fujifilm" model="X-E3">Fujifilm X-E3</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-128" height="0"/>
+ <Sensor black="1023" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-E3" mode="compressed">
+ <ID make="Fujifilm" model="X-E3">Fujifilm X-E3</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GGRGGB</ColorRow>
+ <ColorRow y="1">GGBGGR</ColorRow>
+ <ColorRow y="2">BRGRBG</ColorRow>
+ <ColorRow y="3">GGBGGR</ColorRow>
+ <ColorRow y="4">GGRGGB</ColorRow>
+ <ColorRow y="5">RBGBRG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="18" width="-24" height="-12"/>
+ <Sensor black="1023" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-E2S">
+ <ID make="Fujifilm" model="X-E2S">Fujifilm X-E2S</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="4" y="0" width="-52" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-T1">
+ <ID make="Fujifilm" model="X-T1">Fujifilm X-T1</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="4" y="0" width="-52" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-T2">
+ <ID make="Fujifilm" model="X-T2">Fujifilm X-T2</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-132" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-T2" mode="compressed">
+ <ID make="Fujifilm" model="X-T2">Fujifilm X-T2</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GGRGGB</ColorRow>
+ <ColorRow y="1">GGBGGR</ColorRow>
+ <ColorRow y="2">BRGRBG</ColorRow>
+ <ColorRow y="3">GGBGGR</ColorRow>
+ <ColorRow y="4">GGRGGB</ColorRow>
+ <ColorRow y="5">RBGBRG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="12" width="-16" height="-12"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-T10">
+ <ID make="Fujifilm" model="X-T10">Fujifilm X-T10</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="4" y="0" width="-52" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-T20">
+ <ID make="Fujifilm" model="X-T20">Fujifilm X-T20</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">RBGBRG</ColorRow>
+ <ColorRow y="1">GGRGGB</ColorRow>
+ <ColorRow y="2">GGBGGR</ColorRow>
+ <ColorRow y="3">BRGRBG</ColorRow>
+ <ColorRow y="4">GGBGGR</ColorRow>
+ <ColorRow y="5">GGRGGB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-126" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="FUJIFILM" model="X-T20" mode="compressed">
+ <ID make="Fujifilm" model="X-T20">Fujifilm X-T20</ID>
+ <CFA2 width="6" height="6">
+ <ColorRow y="0">GGRGGB</ColorRow>
+ <ColorRow y="1">GGBGGR</ColorRow>
+ <ColorRow y="2">BRGRBG</ColorRow>
+ <ColorRow y="3">GGBGGR</ColorRow>
+ <ColorRow y="4">GGRGGB</ColorRow>
+ <ColorRow y="5">RBGBRG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="12" width="-16" height="-12"/>
+ <Sensor black="1024" white="16383"/>
+ </Camera>
+ <Camera make="KONICA MINOLTA" model="DYNAX 5D">
+ <ID make="Minolta" model="Dynax 5D">Konica Minolta Maxxum 5D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Aliases>
+ <Alias id="Maxxum 5D">MAXXUM 5D</Alias>
+ <Alias id="Alpha 5D">ALPHA 5D</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="KONICA MINOLTA" model="DYNAX 7D">
+ <ID make="Minolta" model="Dynax 7D">Konica Minolta Maxxum 7D</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Aliases>
+ <Alias id="Maxxum 7D">MAXXUM 7D</Alias>
+ <Alias id="Alpha 7D">ALPHA 7D</Alias>
+ </Aliases>
+ </Camera>
+ <Camera make="Minolta Co., Ltd." model="DiMAGE A1">
+ <ID make="Minolta" model="DiMAGE A1">Minolta DiMAGE A1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3965"/>
+ </Camera>
+ <Camera make="Konica Minolta Camera, Inc." model="DiMAGE A2">
+ <ID make="Minolta" model="DiMAGE A2">Konica Minolta DiMAGE A2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3965"/>
+ </Camera>
+ <Camera make="KONICA MINOLTA" model="DiMAGE A200">
+ <ID make="Minolta" model="DiMAGE A200">Konica Minolta DiMAGE A200</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3965"/>
+ <Hints>
+ <Hint name="swapped_wb" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Minolta Co., Ltd." model="DiMAGE 5">
+ <ID make="Minolta" model="DiMAGE 5">Minolta DiMAGE 5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3965"/>
+ </Camera>
+ <Camera make="Minolta Co., Ltd." model="DiMAGE 7">
+ <ID make="Minolta" model="DiMAGE 7">Minolta DiMAGE 7</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3965"/>
+ </Camera>
+ <Camera make="Minolta Co., Ltd." model="DiMAGE 7i">
+ <ID make="Minolta" model="DiMAGE 7i">Minolta DiMAGE 7i</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3965"/>
+ </Camera>
+ <Camera make="Minolta Co., Ltd." model="DiMAGE 7Hi">
+ <ID make="Minolta" model="DiMAGE 7Hi">Minolta DiMAGE 7Hi</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3965"/>
+ </Camera>
+ <Camera make="SONY" model="DSC-F828">
+ <ID make="Sony" model="DSC-F828">Sony DSC-F828</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">YELLOW</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="5" y="0" width="-67" height="0"/>
+ <Sensor black="495" white="16383"/>
+ <Hints>
+ <Hint name="srf_format" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="SONY" model="DSC-R1">
+ <ID make="Sony" model="DSC-R1">Sony DSC-R1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="-60" height="0"/>
+ <Sensor black="511" white="16383"/>
+ <Hints>
+ <Hint name="sr2_format" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="Mamiya-OP Co.,Ltd." model="MAMIYA ZD">
+ <ID make="Mamiya" model="ZD">Mamiya ZD</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4000"/>
+ </Camera>
+ <Camera make="Creo/Leaf" model="Leaf Aptus 22(LF3779 )/Hasselblad H1">
+ <ID make="Leaf" model="Aptus 22">Leaf Aptus 22</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="16191"/>
+ </Camera>
+ <Camera make="Leaf" model="Leaf Aptus 75(LI400146 )/Large Format" supported="no">
+ <ID make="Leaf" model="Aptus 75">Leaf Aptus 75</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="16191"/>
+ </Camera>
+ <Camera make="Leaf" model="Credo 40">
+ <ID make="Leaf" model="Credo 40">Leaf Credo 40</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="42" y="8" width="-20" height="-48"/>
+ <Sensor black="0" white="16383"/>
+ </Camera>
+ <Camera make="Leaf" model="Credo 60">
+ <ID make="Leaf" model="Credo 60">Leaf Credo 60</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="36" y="6" width="-16" height="-46"/>
+ <Sensor black="0" white="16383"/>
+ </Camera>
+ <Camera make="Leaf" model="Credo 80">
+ <ID make="Leaf" model="Credo 80">Leaf Credo 80</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="36" y="8" width="-16" height="-48"/>
+ <Sensor black="0" white="16383"/>
+ </Camera>
+ <Camera make="Leaf" model="Leaf Aptus-II 5(LI300059 )/Mamiya 645 AFD">
+ <ID make="Leaf" model="Aptus-II 5">Leaf Aptus-II 5</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15000"/>
+ </Camera>
+ <Camera make="Leaf" model="Leaf Aptus-II 8(LI300247 )/Mamiya 645 AFD" supported="no">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">BLUE</Color>
+ <Color x="0" y="1">RED</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15000"/>
+ </Camera>
+ <Camera make="Leaf" model="Leaf AFi-II 7(BT12701 )/Leaf AFi" supported="no">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15000"/>
+ </Camera>
+ <Camera make="Leaf" model="Leaf Aptus-II 10(LI300019 )/Phase One 645DF" supported="no">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15000"/>
+ </Camera>
+ <Camera make="Leaf" model="Leaf Aptus-II 10R( )/Large Format" supported="no">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15000"/>
+ </Camera>
+ <Camera make="Leaf" model="Leaf Aptus-II 12(LI301306 )/Phase One 645DF/645AF" supported="no">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="15000"/>
+ </Camera>
+ <Camera make="Phase One A/S" model="IQ140">
+ <ID make="Phase One" model="IQ140">Phase One IQ140</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="42" y="8" width="-20" height="-54"/>
+ <Sensor black="0" white="65535"/>
+ </Camera>
+ <Camera make="Phase One A/S" model="IQ250">
+ <ID make="Phase One" model="IQ250">Phase One IQ250</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="92" y="108" width="0" height="0"/>
+ <Sensor black="1024" white="65535"/>
+ </Camera>
+ <Camera make="Kodak" model="DCS Pro SLR/n">
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3700"/>
+ </Camera>
+ <Camera make="KODAK" model="DCS460D FILE VERSION 3">
+ <ID make="Kodak" model="DCS460D">Kodak DCS460</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="3" y="0" width="-3" height="0"/>
+ <Sensor black="7" white="6664"/>
+ </Camera>
+ <Camera make="Kodak" model="DCS560C">
+ <ID make="Kodak" model="DCS560C">Kodak DCS560C</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="KODAK" model="EOSDCS1B FILE VERSION 3">
+ <ID make="Kodak" model="EOS DCS 1">Kodak EOSDCS1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">GREEN</Color>
+ <Color x="1" y="0">RED</Color>
+ <Color x="0" y="1">BLUE</Color>
+ <Color x="1" y="1">GREEN</Color>
+ </CFA>
+ <Crop x="3" y="0" width="-3" height="0"/>
+ <Sensor black="19" white="7638"/>
+ </Camera>
+ <Camera make="EASTMAN KODAK COMPANY" model="KODAK P880 ZOOM DIGITAL CAMERA">
+ <ID make="Kodak" model="P880">Kodak P880</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ </Camera>
+ <Camera make="Eastman Kodak Company" model="Kodak Digital Science DC50 Zoom Camera" supported="no">
+ <ID make="Kodak" model="DC50">Kodak Digital Science DC50 Zoom Camera</ID>
+ </Camera>
+ <Camera make="Eastman Kodak Company" model="Kodak DC120 ZOOM Digital Camera" supported="no">
+ <ID make="Kodak" model="DC120">Kodak DC120 ZOOM Digital Camera</ID>
+ </Camera>
+ <Camera make="EASTMAN KODAK COMPANY" model="KODAK EasyShare Z980 Digital Camera">
+ <ID make="Kodak" model="EasyShare Z980">Kodak Z980</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="easyshare_offset_hack" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="EASTMAN KODAK COMPANY" model="KODAK EASYSHARE Z1015 IS DIGITAL CAMERA">
+ <ID make="Kodak" model="Z1015 IS">Kodak Z1015 IS</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">BLUE</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">RED</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="easyshare_offset_hack" value=""/>
+ </Hints>
+ </Camera>
+ <Camera make="SEIKO EPSON CORP." model="R-D1">
+ <ID make="Epson" model="R-D1">Epson R-D1</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="63" white="4095"/>
+ </Camera>
+ <Camera make="Hasselblad" model="Hasselblad 500 mech.">
+ <ID make="Hasselblad" model="CFV">Hasselblad 16-Uncoated</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="32767"/>
+ </Camera>
+ <Camera make="Hasselblad" model="Hasselblad H3D">
+ <ID make="Hasselblad" model="H3D">Hasselblad 39-Coated</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="31456"/>
+ </Camera>
+ <Camera make="Hasselblad" model="Flash Sync">
+ <ID make="Hasselblad" model="CF132">Hasselblad 22-Uncoated</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="62914"/>
+ </Camera>
+ <Camera make="RICOH IMAGING COMPANY, LTD." model="PENTAX 645Z" mode="dng">
+ <ID make="Pentax" model="645Z">PENTAX 645Z</ID>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX 645D" mode="dng">
+ <ID make="Pentax" model="645D">PENTAX 645D</ID>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-01" mode="dng">
+ <ID make="Pentax" model="K-01">PENTAX K-01</ID>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-30" mode="dng">
+ <ID make="Pentax" model="K-30">PENTAX K-30</ID>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-50" mode="dng">
+ <ID make="Pentax" model="K-50">PENTAX K-50</ID>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-500" mode="dng">
+ <ID make="Pentax" model="K-500">PENTAX K-500</ID>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX Q" mode="dng">
+ <ID make="Pentax" model="Q">PENTAX Q</ID>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX Q7" mode="dng">
+ <ID make="Pentax" model="Q7">PENTAX Q7</ID>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX Q10" mode="dng">
+ <ID make="Pentax" model="Q10">PENTAX Q10</ID>
+ </Camera>
+ <Camera make="PENTAX RICOH IMAGING" model="PENTAX MX-1" mode="dng">
+ <ID make="Pentax" model="MX-1">PENTAX MX-1</ID>
+ </Camera>
+ <Camera make="Leica Camera AG" model="M8 Digital Camera" mode="dng">
+ <ID make="Leica" model="M8">M8 Digital Camera</ID>
+ </Camera>
+ <Camera make="Leica Camera AG" model="LEICA M (Typ 240)" mode="dng">
+ <ID make="Leica" model="M (Typ 240)">LEICA M (Typ 240)</ID>
+ </Camera>
+ <Camera make="LEICA CAMERA AG" model="LEICA X2" mode="dng">
+ <ID make="Leica" model="X2">LEICA X2</ID>
+ </Camera>
+ <Camera make="RICOH IMAGING COMPANY, LTD." model="GR" mode="dng">
+ <ID make="Ricoh" model="GR">GR</ID>
+ </Camera>
+ <Camera make="RICOH" model="GR DIGITAL 2" mode="dng">
+ <ID make="Ricoh" model="GR II">Ricoh GR DIGITAL 2</ID>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot A720 IS" mode="dng">
+ <ID make="Canon" model="PowerShot A720 IS">Canon PowerShot A720 IS</ID>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot SX40 HS" mode="dng">
+ <ID make="Canon" model="PowerShot SX40 HS">Canon PowerShot SX40 HS</ID>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot SX100 IS" mode="dng">
+ <ID make="Canon" model="PowerShot SX100 IS">Canon PowerShot SX100 IS</ID>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot SX130 IS" mode="dng">
+ <ID make="Canon" model="PowerShot SX130 IS">Canon PowerShot SX130 IS</ID>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot SX260 HS" mode="dng">
+ <ID make="Canon" model="PowerShot SX260 HS">Canon PowerShot SX260 HS</ID>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot SX510 HS" mode="dng">
+ <ID make="Canon" model="PowerShot SX510 HS">Canon PowerShot SX510 HS</ID>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot A3200 IS" mode="dng">
+ <ID make="Canon" model="PowerShot A3200 IS">Canon PowerShot A3200 IS</ID>
+ </Camera>
+ <Camera make="Canon" model="Canon PowerShot SD450" mode="dng">
+ <ID make="Canon" model="PowerShot SD450">Canon PowerShot SD450</ID>
+ </Camera>
+ <Camera make="OnePlus" model="One A0001" mode="dng">
+ <ID make="OnePlus" model="One">OnePlus One</ID>
+ </Camera>
+ <Camera make="SAMSUNG DIGITAL IMA" model="SAMSUNG GX20" mode="dng">
+ <ID make="Samsung" model="GX20">Samsung GX20</ID>
+ </Camera>
+ <Camera make="samsung" model="SM-G920F">
+ <ID make="Samsung" model="G920F">Samsung G920F</ID>
+ </Camera>
+ <Camera make="samsung" model="SM-G935F">
+ <ID make="Samsung" model="G935F">Samsung G935F</ID>
+ </Camera>
+ <Camera make="SAMSUNG TECHWIN Co." model="SAMSUNG GX10">
+ <ID make="Samsung" model="GX10">Samsung GX10</ID>
+ </Camera>
+ <Camera make="SAMSUNG TECHWIN Co." model="SAMSUNG GX20">
+ <ID make="Samsung" model="GX20">Samsung GX20</ID>
+ </Camera>
+ <Camera make="Nokia" model="Lumia 1020" mode="dng">
+ <ID make="Nokia" model="Lumia 1020">Nokia Lumia 1020</ID>
+ </Camera>
+ <Camera make="PENTAX" model="PENTAX K-r" mode="dng">
+ <ID make="Pentax" model="K-r">PENTAX K-r</ID>
+ </Camera>
+ <Camera make="PENTAX Corporation" model="PENTAX K10D" mode="dng">
+ <ID make="Pentax" model="K10D">PENTAX K10D</ID>
+ </Camera>
+ <Camera make="Nikon" model="LS-5000" mode="dng">
+ <ID make="Nikon" model="LS-5000">Nikon LS-5000</ID>
+ </Camera>
+ <Camera make="SIGMA" model="SIGMA DP1" mode="dng" supported="no">
+ <ID make="Sigma" model="DP1">Sigma DP1</ID>
+ </Camera>
+ <Camera make="SIGMA" model="SIGMA DP1 Merrill" mode="dng" supported="no">
+ <ID make="Sigma" model="DP1 Merrill">Sigma DP1 Merrill</ID>
+ </Camera>
+ <Camera make="LGE" model="Nexus 5X" mode="dng">
+ <ID make="LG" model="Nexus 5X">LG Nexus 5X</ID>
+ </Camera>
+ <Camera make="LGE" model="LG-D855" mode="dng">
+ <ID make="LG" model="D855">LG D855</ID>
+ </Camera>
+ <Camera make="LGE" model="LG-US996" mode="dng">
+ <ID make="LG" model="US996">LG US996</ID>
+ </Camera>
+ <Camera make="LG Mobile" model="LG-H815" mode="dng">
+ <ID make="LG" model="H815">LG H815</ID>
+ </Camera>
+ <Camera make="LG Mobile" model="VS995" mode="dng">
+ <ID make="LG" model="VS995">LG VS995</ID>
+ </Camera>
+ <!-- CHDK Cameras -->
+ <Camera make="AVT" model="F-080C" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="786432"/>
+ <Hint name="full_width" value="1024"/>
+ <Hint name="full_height" value="768"/>
+ </Hints>
+ </Camera>
+ <Camera make="AVT" model="F-145C" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="1447680"/>
+ <Hint name="full_width" value="1392"/>
+ <Hint name="full_height" value="1040"/>
+ </Hints>
+ </Camera>
+ <Camera make="AVT" model="F-201C" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="1920000"/>
+ <Hint name="full_width" value="1600"/>
+ <Hint name="full_height" value="1200"/>
+ </Hints>
+ </Camera>
+ <Camera make="AVT" model="F-510C" supported="no" mode="chdk-a">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="5067304"/>
+ <Hint name="full_width" value="2588"/>
+ <Hint name="full_height" value="1958"/>
+ </Hints>
+ </Camera>
+ <Camera make="AVT" model="F-510C" supported="no" mode="chdk-b">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="5067316"/>
+ <Hint name="full_width" value="2588"/>
+ <Hint name="full_height" value="1958"/>
+ <Hint name="offset" value="12"/>
+ </Hints>
+ </Camera>
+ <Camera make="AVT" model="F-510C" supported="no" mode="chdk-c">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="10134608"/>
+ <Hint name="full_width" value="2588"/>
+ <Hint name="full_height" value="1958"/>
+ </Hints>
+ </Camera>
+ <Camera make="AVT" model="F-510C" supported="no" mode="chdk-d">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="10134620"/>
+ <Hint name="full_width" value="2588"/>
+ <Hint name="full_height" value="1958"/>
+ <Hint name="offset" value="12"/>
+ </Hints>
+ </Camera>
+ <Camera make="AVT" model="F-810C" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="16157136"/>
+ <Hint name="full_width" value="3272"/>
+ <Hint name="full_height" value="2469"/>
+ </Hints>
+ </Camera>
+ <Camera make="AgfaPhoto" model="DC-833m" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="15980544"/>
+ <Hint name="full_width" value="3264"/>
+ <Hint name="full_height" value="2448"/>
+ </Hints>
+ </Camera>
+ <Camera make="Alcatel" model="5035D" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="9631728"/>
+ <Hint name="full_width" value="2532"/>
+ <Hint name="full_height" value="1902"/>
+ </Hints>
+ </Camera>
+ <Camera make="Baumer" model="TXG14" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GR</ColorRow>
+ <ColorRow y="1">BG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="2868726"/>
+ <Hint name="full_width" value="1384"/>
+ <Hint name="full_height" value="1036"/>
+ <Hint name="offset" value="1078"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot SD300" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="12" y="12" width="-44" height="-2"/>
+ <Sensor black="0" white="1023"/>
+ <Hints>
+ <Hint name="filesize" value="5298000"/>
+ <Hint name="full_width" value="2400"/>
+ <Hint name="full_height" value="1766"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot A460" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="4" y="4" width="-44" height="-4"/>
+ <Sensor black="0" white="1023"/>
+ <Hints>
+ <Hint name="filesize" value="6553440"/>
+ <Hint name="full_width" value="2664"/>
+ <Hint name="full_height" value="1968"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot A610" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="12" y="8" width="-44" height="0"/>
+ <Sensor black="0" white="1023"/>
+ <BlackAreas>
+ <Vertical x="2632" width="40"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="filesize" value="6573120"/>
+ <Hint name="full_width" value="2672"/>
+ <Hint name="full_height" value="1968"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot A530" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="10" y="6" width="-42" height="-2"/>
+ <Sensor black="0" white="1023"/>
+ <Hints>
+ <Hint name="filesize" value="6653280"/>
+ <Hint name="full_width" value="2672"/>
+ <Hint name="full_height" value="1992"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot S3 IS" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="44" y="8" width="-4" height="0"/>
+ <Sensor black="0" white="1023"/>
+ <BlackAreas>
+ <Vertical x="0" width="40"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="filesize" value="7710960"/>
+ <Hint name="full_width" value="2888"/>
+ <Hint name="full_height" value="2136"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot A620" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="36" y="12" width="-4" height="0"/>
+ <Sensor black="0" white="1023"/>
+ <BlackAreas>
+ <Vertical x="0" width="30"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="filesize" value="9219600"/>
+ <Hint name="full_width" value="3152"/>
+ <Hint name="full_height" value="2340"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot A470" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GR</ColorRow>
+ <ColorRow y="1">BG</ColorRow>
+ </CFA2>
+ <Crop x="12" y="7" width="-44" height="-13"/>
+ <Sensor black="0" white="1023"/>
+ <Hints>
+ <Hint name="filesize" value="9243240"/>
+ <Hint name="full_width" value="3152"/>
+ <Hint name="full_height" value="2346"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot A720 IS" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="6" y="5" width="-32" height="-3"/>
+ <Sensor black="0" white="1023"/>
+ <BlackAreas>
+ <Vertical x="3306" width="30"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="filesize" value="10341600"/>
+ <Hint name="full_width" value="3336"/>
+ <Hint name="full_height" value="2480"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot A630" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="12" y="6" width="-44" height="-6"/>
+ <Sensor black="0" white="1023"/>
+ <BlackAreas>
+ <Vertical x="0" width="30"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="filesize" value="10383120"/>
+ <Hint name="full_width" value="3344"/>
+ <Hint name="full_height" value="2484"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot A640" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="12" y="6" width="-52" height="-6"/>
+ <Sensor black="0" white="1023"/>
+ <BlackAreas>
+ <Vertical x="3686" width="50"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="filesize" value="12945240"/>
+ <Hint name="full_width" value="3736"/>
+ <Hint name="full_height" value="2772"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot A650" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="48" y="12" width="-24" height="-12"/>
+ <Sensor black="0" white="1023"/>
+ <BlackAreas>
+ <Vertical x="0" width="45"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="filesize" value="15636240"/>
+ <Hint name="full_width" value="4104"/>
+ <Hint name="full_height" value="3048"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot SX110 IS" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="6" y="12" width="-30" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <BlackAreas>
+ <Vertical x="3690" width="30"/>
+ </BlackAreas>
+ <Hints>
+ <Hint name="filesize" value="15467760"/>
+ <Hint name="full_width" value="3720"/>
+ <Hint name="full_height" value="2772"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot SX120 IS" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="12" y="9" width="-44" height="-9"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="15534576"/>
+ <Hint name="full_width" value="3728"/>
+ <Hint name="full_height" value="2778"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot SX20 IS" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="24" y="12" width="-24" height="-12"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="18653760"/>
+ <Hint name="full_width" value="4080"/>
+ <Hint name="full_height" value="3048"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot SX220 HS" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="92" y="16" width="-4" height="-1"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="19131120"/>
+ <Hint name="full_width" value="4168"/>
+ <Hint name="full_height" value="3060"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot SX30 IS" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">BG</ColorRow>
+ <ColorRow y="1">GR</ColorRow>
+ </CFA2>
+ <Crop x="25" y="10" width="-73" height="-12"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="21936096"/>
+ <Hint name="full_width" value="4464"/>
+ <Hint name="full_height" value="3276"/>
+ </Hints>
+ </Camera>
+ <Camera make="Canon" model="PowerShot A3300 IS" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="8" y="16" width="-56" height="-8"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="24724224"/>
+ <Hint name="full_width" value="4704"/>
+ <Hint name="full_height" value="3504"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="QV-2000UX" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="2" width="0" height="-1"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="1976352"/>
+ <Hint name="full_width" value="1632"/>
+ <Hint name="full_height" value="1211"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="QV-3*00EX" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-10" height="-1"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="3217760"/>
+ <Hint name="full_width" value="2080"/>
+ <Hint name="full_height" value="1547"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="QV-5700" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-9" height="0"/>
+ <Sensor black="0" white="1023"/>
+ <Hints>
+ <Hint name="filesize" value="6218368"/>
+ <Hint name="full_width" value="2585"/>
+ <Hint name="full_height" value="1924"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-Z60" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">BG</ColorRow>
+ <ColorRow y="1">GR</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-34" height="-36"/>
+ <Sensor black="0" white="1023"/>
+ <Hints>
+ <Hint name="filesize" value="7816704"/>
+ <Hint name="full_width" value="2867"/>
+ <Hint name="full_height" value="2181"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-S20" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-1" height="0"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="2937856"/>
+ <Hint name="full_width" value="1621"/>
+ <Hint name="full_height" value="1208"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-S100" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-32" height="-34"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="4948608"/>
+ <Hint name="full_width" value="2090"/>
+ <Hint name="full_height" value="1578"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="QV-R41" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="2" y="0" width="-32" height="0"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="6054400"/>
+ <Hint name="full_width" value="2346"/>
+ <Hint name="full_height" value="1720"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-P505" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="7426656"/>
+ <Hint name="full_width" value="2568"/>
+ <Hint name="full_height" value="1928"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="QV-R51" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-22" height="0"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="7530816"/>
+ <Hint name="full_width" value="2602"/>
+ <Hint name="full_height" value="1929"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-Z50" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-32" height="0"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="7542528"/>
+ <Hint name="full_width" value="2602"/>
+ <Hint name="full_height" value="1932"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-Z500" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">BG</ColorRow>
+ <ColorRow y="1">GR</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-25" height="0"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="7562048"/>
+ <Hint name="full_width" value="2602"/>
+ <Hint name="full_height" value="1937"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-Z55" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-32" height="-26"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="7753344"/>
+ <Hint name="full_width" value="2602"/>
+ <Hint name="full_height" value="1986"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-P600" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-14" height="-30"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="9313536"/>
+ <Hint name="full_width" value="2858"/>
+ <Hint name="full_height" value="2172"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-Z750" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-27" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="10834368"/>
+ <Hint name="full_width" value="3114"/>
+ <Hint name="full_height" value="2319"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-Z75" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-25" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="10843712"/>
+ <Hint name="full_width" value="3114"/>
+ <Hint name="full_height" value="2321"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-P700" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-32" height="-32"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="10979200"/>
+ <Hint name="full_width" value="3114"/>
+ <Hint name="full_height" value="2350"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-Z850" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-6" height="-30"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="12310144"/>
+ <Hint name="full_width" value="3285"/>
+ <Hint name="full_height" value="2498"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-Z8" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-47" height="-35"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="12489984"/>
+ <Hint name="full_width" value="3328"/>
+ <Hint name="full_height" value="2502"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-Z1050" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-82" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="15499264"/>
+ <Hint name="full_width" value="3754"/>
+ <Hint name="full_height" value="2752"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="EX-ZR100" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-24" height="0"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="18702336"/>
+ <Hint name="full_width" value="4096"/>
+ <Hint name="full_height" value="3044"/>
+ </Hints>
+ </Camera>
+ <Camera make="Casio" model="QV-4000" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="7684000"/>
+ <Hint name="full_width" value="2260"/>
+ <Hint name="full_height" value="1700"/>
+ </Hints>
+ </Camera>
+ <Camera make="Creative" model="PC-CAM 600" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GR</ColorRow>
+ <ColorRow y="1">BG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="1" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="787456"/>
+ <Hint name="full_width" value="1024"/>
+ <Hint name="full_height" value="769"/>
+ </Hints>
+ </Camera>
+ <Camera make="DJI" model="" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="28829184"/>
+ <Hint name="full_width" value="4384"/>
+ <Hint name="full_height" value="3288"/>
+ </Hints>
+ </Camera>
+ <Camera make="Matrix" model="" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="15151104"/>
+ <Hint name="full_width" value="4608"/>
+ <Hint name="full_height" value="3288"/>
+ </Hints>
+ </Camera>
+ <Camera make="Foculus" model="531C" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GR</ColorRow>
+ <ColorRow y="1">BG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="3840000"/>
+ <Hint name="full_width" value="1600"/>
+ <Hint name="full_height" value="1200"/>
+ </Hints>
+ </Camera>
+ <Camera make="Generic" model="" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="307200"/>
+ <Hint name="full_width" value="640"/>
+ <Hint name="full_height" value="480"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="DC20" supported="no" mode="chdk-a">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GR</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="1" y="1" width="-6" height="-1"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="62464"/>
+ <Hint name="full_width" value="256"/>
+ <Hint name="full_height" value="244"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="DC20" supported="no" mode="chdk-b">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GR</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="1" y="1" width="-10" height="-1"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="124928"/>
+ <Hint name="full_width" value="512"/>
+ <Hint name="full_height" value="244"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="DCS200" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="52" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="1652736"/>
+ <Hint name="full_width" value="1536"/>
+ <Hint name="full_height" value="1076"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="C330" supported="no" mode="chdk-a">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="1" y="33" width="-1" height="-2"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="4159302"/>
+ <Hint name="full_width" value="2338"/>
+ <Hint name="full_height" value="1779"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="C330" supported="no" mode="chdk-b">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="1" y="33" width="-1" height="-2"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="4162462"/>
+ <Hint name="full_width" value="2338"/>
+ <Hint name="full_height" value="1779"/>
+ <Hint name="offset" value="3160"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="C603" supported="no" mode="chdk-a">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="6163328"/>
+ <Hint name="full_width" value="2864"/>
+ <Hint name="full_height" value="2152"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="C603" supported="no" mode="chdk-b">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="6166488"/>
+ <Hint name="full_width" value="2864"/>
+ <Hint name="full_height" value="2152"/>
+ <Hint name="offset" value="3160"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="C603" supported="no" mode="chdk-c">
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="460800"/>
+ <Hint name="full_width" value="640"/>
+ <Hint name="full_height" value="480"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="C603" supported="no" mode="chdk-d">
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="9116448"/>
+ <Hint name="full_width" value="2848"/>
+ <Hint name="full_height" value="2134"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="12MP" supported="no" mode="chdk-a">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GR</ColorRow>
+ <ColorRow y="1">BG</ColorRow>
+ </CFA2>
+ <Crop x="2" y="0" width="0" height="-13"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="12241200"/>
+ <Hint name="full_width" value="4040"/>
+ <Hint name="full_height" value="3030"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="12MP" supported="no" mode="chdk-b">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GR</ColorRow>
+ <ColorRow y="1">BG</ColorRow>
+ </CFA2>
+ <Crop x="2" y="0" width="0" height="-13"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="12272756"/>
+ <Hint name="full_width" value="4040"/>
+ <Hint name="full_height" value="3030"/>
+ <Hint name="offset" value="31556"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="12MP" supported="no" mode="chdk-c">
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="18000000"/>
+ <Hint name="full_width" value="4000"/>
+ <Hint name="full_height" value="3000"/>
+ </Hints>
+ </Camera>
+ <Camera make="Kodak" model="KAI-0340" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="3" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="614400"/>
+ <Hint name="full_width" value="640"/>
+ <Hint name="full_height" value="480"/>
+ </Hints>
+ </Camera>
+ <Camera make="Micron" model="2010" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">BG</ColorRow>
+ <ColorRow y="1">GR</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="3884928"/>
+ <Hint name="full_width" value="1608"/>
+ <Hint name="full_height" value="1207"/>
+ <Hint name="offset" value="3212"/>
+ </Hints>
+ </Camera>
+ <Camera make="Minolta" model="RD175" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="63"/>
+ <Hints>
+ <Hint name="filesize" value="1138688"/>
+ <Hint name="full_width" value="1534"/>
+ <Hint name="full_height" value="986"/>
+ <Hint name="offset" value="513"/>
+ </Hints>
+ </Camera>
+ <Camera make="Nikon" model="E900" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">BG</ColorRow>
+ <ColorRow y="1">GR</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-18" height="-6"/>
+ <Sensor black="0" white="1008"/>
+ <Hints>
+ <Hint name="filesize" value="1581060"/>
+ <Hint name="full_width" value="1305"/>
+ <Hint name="full_height" value="969"/>
+ </Hints>
+ </Camera>
+ <Camera make="Nikon" model="E950" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GR</ColorRow>
+ <ColorRow y="1">BG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-22" height="-1"/>
+ <Sensor black="0" white="992"/>
+ <Hints>
+ <Hint name="filesize" value="2465792"/>
+ <Hint name="full_width" value="1638"/>
+ <Hint name="full_height" value="1204"/>
+ </Hints>
+ </Camera>
+ <Camera make="Nikon" model="E2100" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="-7"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="2940928"/>
+ <Hint name="full_width" value="1616"/>
+ <Hint name="full_height" value="1213"/>
+ </Hints>
+ </Camera>
+ <Camera make="Nikon" model="E990" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="-1"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="4771840"/>
+ <Hint name="full_width" value="2064"/>
+ <Hint name="full_height" value="1541"/>
+ </Hints>
+ </Camera>
+ <Camera make="Nikon" model="E3700" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="4775936"/>
+ <Hint name="full_width" value="2064"/>
+ <Hint name="full_height" value="1542"/>
+ </Hints>
+ </Camera>
+ <Camera make="Nikon" model="E4500" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="-1"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="5865472"/>
+ <Hint name="full_width" value="2288"/>
+ <Hint name="full_height" value="1709"/>
+ </Hints>
+ </Camera>
+ <Camera make="Nikon" model="E4300" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">BG</ColorRow>
+ <ColorRow y="1">GR</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="5869568"/>
+ <Hint name="full_width" value="2288"/>
+ <Hint name="full_height" value="1710"/>
+ </Hints>
+ </Camera>
+ <Camera make="Nikon" model="E5000" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="-1"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="7438336"/>
+ <Hint name="full_width" value="2576"/>
+ <Hint name="full_height" value="1925"/>
+ </Hints>
+ </Camera>
+ <Camera make="Nikon" model="COOLPIX S6" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="8998912"/>
+ <Hint name="full_width" value="2832"/>
+ <Hint name="full_height" value="2118"/>
+ </Hints>
+ </Camera>
+ <Camera make="Olympus" model="C770UZ" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">BG</ColorRow>
+ <ColorRow y="1">GR</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="5939200"/>
+ <Hint name="full_width" value="2304"/>
+ <Hint name="full_height" value="1718"/>
+ </Hints>
+ </Camera>
+ <Camera make="Pentax" model="Optio S" supported="no" mode="chdk-a">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="3178560"/>
+ <Hint name="full_width" value="2064"/>
+ <Hint name="full_height" value="1540"/>
+ </Hints>
+ </Camera>
+ <Camera make="Pentax" model="Optio S" supported="no" mode="chdk-b">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-22" height="0"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="4841984"/>
+ <Hint name="full_width" value="2090"/>
+ <Hint name="full_height" value="1544"/>
+ </Hints>
+ </Camera>
+ <Camera make="Pentax" model="Optio S4" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-22" height="0"/>
+ <Sensor black="0" white="3968"/>
+ <Hints>
+ <Hint name="filesize" value="6114240"/>
+ <Hint name="full_width" value="2346"/>
+ <Hint name="full_height" value="1737"/>
+ </Hints>
+ </Camera>
+ <Camera make="Pentax" model="Optio 750Z" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="-21"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="10702848"/>
+ <Hint name="full_width" value="3072"/>
+ <Hint name="full_height" value="2322"/>
+ </Hints>
+ </Camera>
+ <Camera make="Pixelink" model="A782" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="13248000"/>
+ <Hint name="full_width" value="2208"/>
+ <Hint name="full_height" value="3000"/>
+ </Hints>
+ </Camera>
+ <Camera make="RoverShot" model="3320AF" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="6291456"/>
+ <Hint name="full_width" value="2048"/>
+ <Hint name="full_height" value="1536"/>
+ </Hints>
+ </Camera>
+ <Camera make="ST Micro" model="STV680 VGA" supported="no" mode="chdk">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">BG</ColorRow>
+ <ColorRow y="1">GR</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="311696"/>
+ <Hint name="full_width" value="644"/>
+ <Hint name="full_height" value="484"/>
+ </Hints>
+ </Camera>
+ <Camera make="Samsung" model="S85" supported="no" mode="chdk-a">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-24" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="16098048"/>
+ <Hint name="full_width" value="3288"/>
+ <Hint name="full_height" value="2448"/>
+ </Hints>
+ </Camera>
+ <Camera make="Samsung" model="S85" supported="no" mode="chdk-b">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-48" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="16215552"/>
+ <Hint name="full_width" value="3312"/>
+ <Hint name="full_height" value="2448"/>
+ </Hints>
+ </Camera>
+ <Camera make="Samsung" model="WB550" supported="no" mode="chdk-a">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65504"/>
+ <Hints>
+ <Hint name="filesize" value="20487168"/>
+ <Hint name="full_width" value="3648"/>
+ <Hint name="full_height" value="2808"/>
+ </Hints>
+ </Camera>
+ <Camera make="Samsung" model="WB550" supported="no" mode="chdk-b">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">RG</ColorRow>
+ <ColorRow y="1">GB</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65504"/>
+ <Hints>
+ <Hint name="filesize" value="24000000"/>
+ <Hint name="full_width" value="4000"/>
+ <Hint name="full_height" value="3000"/>
+ </Hints>
+ </Camera>
+ <Camera make="Sinar" model="" supported="no" mode="chdk-a">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="12582980"/>
+ <Hint name="full_width" value="3072"/>
+ <Hint name="full_height" value="2048"/>
+ <Hint name="offset" value="68"/>
+ </Hints>
+ </Camera>
+ <Camera make="Sinar" model="" supported="no" mode="chdk-b">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="33292868"/>
+ <Hint name="full_width" value="4080"/>
+ <Hint name="full_height" value="4080"/>
+ <Hint name="offset" value="68"/>
+ </Hints>
+ </Camera>
+ <Camera make="Sinar" model="" supported="no" mode="chdk-c">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GB</ColorRow>
+ <ColorRow y="1">RG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="44390468"/>
+ <Hint name="full_width" value="4080"/>
+ <Hint name="full_height" value="5440"/>
+ <Hint name="offset" value="68"/>
+ </Hints>
+ </Camera>
+ <Camera make="Sony" model="XCD-SX910CR" supported="no" mode="chdk-a">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GR</ColorRow>
+ <ColorRow y="1">BG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-1" height="0"/>
+ <Sensor black="0" white="255"/>
+ <Hints>
+ <Hint name="filesize" value="1409024"/>
+ <Hint name="full_width" value="1376"/>
+ <Hint name="full_height" value="1024"/>
+ </Hints>
+ </Camera>
+ <Camera make="Sony" model="XCD-SX910CR" supported="no" mode="chdk-b">
+ <CFA2 width="2" height="2">
+ <ColorRow y="0">GR</ColorRow>
+ <ColorRow y="1">BG</ColorRow>
+ </CFA2>
+ <Crop x="0" y="0" width="-1" height="0"/>
+ <Sensor black="0" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="2818048"/>
+ <Hint name="full_width" value="1376"/>
+ <Hint name="full_height" value="1024"/>
+ </Hints>
+ </Camera>
+ <Camera make="GITUP" model="GIT2" mode="chdk-a">
+ <ID make="GITUP" model="GIT2">GITUP GIT2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="3200" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="31850496"/>
+ <Hint name="full_width" value="4608"/>
+ <Hint name="full_height" value="3456"/>
+ </Hints>
+ </Camera>
+ <Camera make="GITUP" model="GIT2" mode="chdk-b">
+ <ID make="GITUP" model="GIT2">GITUP GIT2</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="3200" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="23887872"/>
+ <Hint name="full_width" value="4608"/>
+ <Hint name="full_height" value="2592"/>
+ </Hints>
+ </Camera>
+ <Camera make="GITUP" model="GIT2P" mode="chdk-a">
+ <ID make="GITUP" model="GIT2P">GITUP GIT2P</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="4160" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="32257024"/>
+ <Hint name="full_width" value="4624"/>
+ <Hint name="full_height" value="3488"/>
+ </Hints>
+ </Camera>
+ <Camera make="GITUP" model="GIT2P" mode="chdk-b">
+ <ID make="GITUP" model="GIT2P">GITUP GIT2P</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="4160" white="65535"/>
+ <Hints>
+ <Hint name="filesize" value="24192768"/>
+ <Hint name="full_width" value="4624"/>
+ <Hint name="full_height" value="2616"/>
+ </Hints>
+ </Camera>
+ <Camera make="Paralenz" model="Dive Camera" mode="chdk">
+ <ID make="Paralenz" model="Dive Camera">Paralenz Dive Camera</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="1024" white="16383"/>
+ <Hints>
+ <Hint name="filesize" value="16588800"/>
+ <Hint name="full_width" value="3840"/>
+ <Hint name="full_height" value="2160"/>
+ </Hints>
+ </Camera>
+ <!-- Clashes with GITUP GIT2P chdk-b.
+ I have idea how the problem can be resolved.
+ <Camera make="Sjcam" model="Sjcam SJ6 LEGEND" mode="chdk-a">
+ <ID make="Sjcam" model="SJ6 LEGEND">Sjcam SJ6 LEGEND</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="24192768"/>
+ <Hint name="full_width" value="4624"/>
+ <Hint name="full_height" value="3488"/>
+ <Hint name="order" value="plain"/>
+ </Hints>
+ </Camera>
+ -->
+ <Camera make="Sjcam" model="Sjcam SJ6 LEGEND" mode="chdk-b">
+ <ID make="Sjcam" model="SJ6 LEGEND">Sjcam SJ6 LEGEND</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="18325296"/>
+ <Hint name="full_width" value="4024"/>
+ <Hint name="full_height" value="3036"/>
+ <Hint name="order" value="plain"/>
+ </Hints>
+ </Camera>
+ <Camera make="Sjcam" model="Sjcam SJ6 LEGEND" mode="chdk-c">
+ <ID make="Sjcam" model="SJ6 LEGEND">Sjcam SJ6 LEGEND</ID>
+ <CFA width="2" height="2">
+ <Color x="0" y="0">RED</Color>
+ <Color x="1" y="0">GREEN</Color>
+ <Color x="0" y="1">GREEN</Color>
+ <Color x="1" y="1">BLUE</Color>
+ </CFA>
+ <Crop x="0" y="0" width="0" height="0"/>
+ <Sensor black="0" white="4095"/>
+ <Hints>
+ <Hint name="filesize" value="15972480"/>
+ <Hint name="full_width" value="3760"/>
+ <Hint name="full_height" value="2832"/>
+ <Hint name="order" value="plain"/>
+ </Hints>
+ </Camera>
+</Cameras>
+<!--
+vim: tabstop=8 shiftwidth=8 softtabstop=8
+kate: tab-width: 8; replace-tabs off; indent-width 8; tab-indents: on;
+kate: indent-mode xml; remove-trailing-spaces modified;
+-->
diff --git a/src/external/rawspeed/data/cameras.xsd b/src/external/rawspeed/data/cameras.xsd
new file mode 100644
index 000000000..b1abea637
--- /dev/null
+++ b/src/external/rawspeed/data/cameras.xsd
@@ -0,0 +1,501 @@
+<?xml version="1.0"?>
+<!--
+ License: CC-BY-SA 3.0
+
+ This work is licensed under a
+ Creative Commons Attribution-ShareAlike 3.0 Unported License.
+
+ See more at:
+ http://creativecommons.org/licenses/by-sa/3.0/
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified">
+ <xs:simpleType name="IDTypeType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-zA-Z0-9 \-*()]{2,38}"/>
+ <xs:minLength value="2"/>
+ <xs:maxLength value="38"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="IDTypeMakeType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-zA-Z ]{2,10}"/>
+ <xs:minLength value="2"/>
+ <xs:maxLength value="10"/>
+ <xs:enumeration value="Canon"/>
+ <xs:enumeration value="Epson"/>
+ <xs:enumeration value="Fujifilm"/>
+ <xs:enumeration value="GITUP"/>
+ <xs:enumeration value="Hasselblad"/>
+ <xs:enumeration value="Kodak"/>
+ <xs:enumeration value="LG"/>
+ <xs:enumeration value="Leaf"/>
+ <xs:enumeration value="Leica"/>
+ <xs:enumeration value="Mamiya"/>
+ <xs:enumeration value="Minolta"/>
+ <xs:enumeration value="Nikon"/>
+ <xs:enumeration value="Nokia"/>
+ <xs:enumeration value="Olympus"/>
+ <xs:enumeration value="OnePlus"/>
+ <xs:enumeration value="Panasonic"/>
+ <xs:enumeration value="Paralenz"/>
+ <xs:enumeration value="Pentax"/>
+ <xs:enumeration value="Phase One"/>
+ <xs:enumeration value="Ricoh"/>
+ <xs:enumeration value="Samsung"/>
+ <xs:enumeration value="Sigma"/>
+ <xs:enumeration value="Sinar"/>
+ <xs:enumeration value="Sjcam"/>
+ <xs:enumeration value="Sony"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="IDTypeModelType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-zA-Z0-9 \-*()]{1,22}"/>
+ <xs:minLength value="1"/>
+ <xs:maxLength value="22"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="IDType">
+ <xs:simpleContent>
+ <xs:extension base="IDTypeType">
+ <xs:attribute type="IDTypeMakeType" name="make" use="required"/>
+ <xs:attribute type="IDTypeModelType" name="model" use="required"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:simpleType name="ColorTypeType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[A-Z_]{3,10}"/>
+ <xs:minLength value="3"/>
+ <xs:maxLength value="10"/>
+ <xs:enumeration value="BLUE"/>
+ <xs:enumeration value="CYAN"/>
+ <xs:enumeration value="FUJI_GREEN"/>
+ <xs:enumeration value="GREEN"/>
+ <xs:enumeration value="MAGENTA"/>
+ <xs:enumeration value="RED"/>
+ <xs:enumeration value="YELLOW"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ColorTypeXType">
+ <xs:restriction base="xs:unsignedByte">
+ <xs:pattern value="[0-2]{1,1}"/>
+ <xs:minInclusive value="0"/>
+ <xs:maxInclusive value="2"/>
+ <xs:enumeration value="0"/>
+ <xs:enumeration value="1"/>
+ <xs:enumeration value="2"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ColorTypeYType">
+ <xs:restriction base="xs:unsignedByte">
+ <xs:pattern value="[0-2]{1,1}"/>
+ <xs:minInclusive value="0"/>
+ <xs:maxInclusive value="2"/>
+ <xs:enumeration value="0"/>
+ <xs:enumeration value="1"/>
+ <xs:enumeration value="2"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="ColorType">
+ <xs:simpleContent>
+ <xs:extension base="ColorTypeType">
+ <xs:attribute type="ColorTypeXType" name="x" use="required"/>
+ <xs:attribute type="ColorTypeYType" name="y" use="required"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:simpleType name="CFATypeWidthType">
+ <xs:restriction base="xs:unsignedByte">
+ <xs:pattern value="[2]{1,1}"/>
+ <xs:minInclusive value="2"/>
+ <xs:maxInclusive value="2"/>
+ <xs:enumeration value="2"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="CFATypeHeightType">
+ <xs:restriction base="xs:unsignedByte">
+ <xs:pattern value="[2]{1,1}"/>
+ <xs:minInclusive value="2"/>
+ <xs:maxInclusive value="2"/>
+ <xs:enumeration value="2"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="CFAType">
+ <xs:sequence>
+ <xs:element type="ColorType" name="Color" minOccurs="4" maxOccurs="4"/>
+ </xs:sequence>
+ <xs:attribute type="CFATypeWidthType" name="width" use="required"/>
+ <xs:attribute type="CFATypeHeightType" name="height" use="required"/>
+ </xs:complexType>
+ <xs:simpleType name="ColorRowTypeType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[RGB]{2,2}([RGB]{4,4})?"/>
+ <xs:minLength value="2"/>
+ <xs:maxLength value="6"/>
+ <xs:enumeration value="BG"/>
+ <xs:enumeration value="BGBRGR"/>
+ <xs:enumeration value="BGGRGG"/>
+ <xs:enumeration value="BRGRBG"/>
+ <xs:enumeration value="GB"/>
+ <xs:enumeration value="GBGGRG"/>
+ <xs:enumeration value="GBRGRB"/>
+ <xs:enumeration value="GGBGGR"/>
+ <xs:enumeration value="GGRGGB"/>
+ <xs:enumeration value="GR"/>
+ <xs:enumeration value="GRBGBR"/>
+ <xs:enumeration value="GRGGBG"/>
+ <xs:enumeration value="RBGBRG"/>
+ <xs:enumeration value="RG"/>
+ <xs:enumeration value="RGGBGG"/>
+ <xs:enumeration value="RGRBGB"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="ColorRowTypeTypeYType">
+ <xs:restriction base="xs:unsignedByte">
+ <xs:pattern value="[0-6]{1,1}"/>
+ <xs:minInclusive value="0"/>
+ <xs:maxInclusive value="6"/>
+ <xs:enumeration value="0"/>
+ <xs:enumeration value="1"/>
+ <xs:enumeration value="2"/>
+ <xs:enumeration value="3"/>
+ <xs:enumeration value="4"/>
+ <xs:enumeration value="5"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="ColorRowType">
+ <xs:simpleContent>
+ <xs:extension base="ColorRowTypeType">
+ <xs:attribute type="ColorRowTypeTypeYType" name="y" use="required"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:simpleType name="CFA2TypeWidthType">
+ <xs:restriction base="xs:unsignedByte">
+ <xs:pattern value="[26]{1,1}"/>
+ <xs:minInclusive value="2"/>
+ <xs:maxInclusive value="6"/>
+ <xs:enumeration value="2"/>
+ <xs:enumeration value="6"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="CFA2TypeHeightType">
+ <xs:restriction base="xs:unsignedByte">
+ <xs:pattern value="[26]{1,1}"/>
+ <xs:minInclusive value="2"/>
+ <xs:maxInclusive value="6"/>
+ <xs:enumeration value="2"/>
+ <xs:enumeration value="6"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="CFA2Type">
+ <xs:sequence>
+ <xs:choice>
+ <xs:element type="ColorRowType" name="ColorRow" minOccurs="2" maxOccurs="2"/>
+ <xs:element type="ColorRowType" name="ColorRow" minOccurs="6" maxOccurs="6"/>
+ </xs:choice>
+ </xs:sequence>
+ <xs:attribute type="CFA2TypeWidthType" name="width" use="required"/>
+ <xs:attribute type="CFA2TypeHeightType" name="height" use="required"/>
+ </xs:complexType>
+ <xs:simpleType name="CropTypeSizeOrNegOffset">
+ <xs:union>
+ <xs:simpleType>
+ <xs:restriction base="xs:unsignedShort">
+ <xs:minInclusive value="1296"/>
+ <xs:maxInclusive value="6080"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType>
+ <xs:restriction base="xs:short">
+ <xs:minInclusive value="-936"/>
+ <xs:maxInclusive value="0"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:union>
+ </xs:simpleType>
+ <xs:complexType name="CropType">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute type="xs:unsignedShort" name="x" use="required"/>
+ <xs:attribute type="xs:unsignedByte" name="y" use="required"/>
+ <xs:attribute type="CropTypeSizeOrNegOffset" name="width" use="required"/>
+ <xs:attribute type="CropTypeSizeOrNegOffset" name="height" use="required"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:simpleType name="IsoType">
+ <xs:restriction base="xs:unsignedInt">
+ <xs:pattern value="[0-9]{1,6}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="IsoList">
+ <xs:restriction>
+ <xs:simpleType>
+ <xs:list itemType="IsoType"/>
+ </xs:simpleType>
+ <xs:minLength value="1"/>
+ <xs:maxLength value="12"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="SensorTypeIsoListType">
+ <xs:restriction base="IsoList">
+ <xs:pattern value="[0-9]{2,6}( [0-9]{3,6}){0,11}"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:attributeGroup name="SensorTypeIsoLimitsType">
+ <xs:attribute type="IsoType" name="iso_min"/>
+ <xs:attribute type="IsoType" name="iso_max"/>
+ </xs:attributeGroup>
+ <xs:complexType name="SensorType">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute type="xs:unsignedShort" name="black" use="required"/>
+ <xs:attribute type="xs:unsignedShort" name="white" use="required"/>
+ <xs:attribute type="SensorTypeIsoListType" name="iso_list"/>
+ <xs:attributeGroup ref="SensorTypeIsoLimitsType"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:complexType name="VerticalType">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute type="xs:unsignedShort" name="x" use="required"/>
+ <xs:attribute type="xs:unsignedShort" name="width" use="required"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:complexType name="HorizontalType">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute type="xs:unsignedShort" name="y" use="required"/>
+ <xs:attribute type="xs:unsignedByte" name="height" use="required"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:complexType name="BlackAreasType">
+ <xs:sequence>
+ <xs:choice minOccurs="1" maxOccurs="2">
+ <xs:element type="VerticalType" name="Vertical" minOccurs="1" maxOccurs="2"/>
+ <xs:element type="HorizontalType" name="Horizontal" minOccurs="1" maxOccurs="2"/>
+ </xs:choice>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="AliasTypeType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-zA-Z0-9 \-,]{6,27}"/>
+ <xs:minLength value="6"/>
+ <xs:maxLength value="27"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="AliasTypeIdType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-zA-Z0-9 \-]{7,21}"/>
+ <xs:minLength value="7"/>
+ <xs:maxLength value="21"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="AliasType">
+ <xs:simpleContent>
+ <xs:extension base="AliasTypeType">
+ <xs:attribute type="AliasTypeIdType" name="id"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:complexType name="AliasesType">
+ <xs:sequence>
+ <xs:element type="AliasType" name="Alias" minOccurs="1" maxOccurs="4"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="HintTypeNameType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-zA-Z0-9_]{5,26}"/>
+ <xs:minLength value="4"/>
+ <xs:maxLength value="26"/>
+ <xs:enumeration value="coolpixmangled"/>
+ <xs:enumeration value="coolpixsplit"/>
+ <xs:enumeration value="double_width_unpacked"/>
+ <xs:enumeration value="easyshare_offset_hack"/>
+ <xs:enumeration value="filesize"/>
+ <xs:enumeration value="force_uncompressed"/>
+ <xs:enumeration value="fuji_rotate"/>
+ <xs:enumeration value="full_height"/>
+ <xs:enumeration value="full_width"/>
+ <xs:enumeration value="invert_sraw_wb"/>
+ <xs:enumeration value="jpeg32_bitorder"/>
+ <xs:enumeration value="msb_override"/>
+ <xs:enumeration value="nikon_wb_adjustment"/>
+ <xs:enumeration value="no_decompressed_lowbits"/>
+ <xs:enumeration value="offset"/>
+ <xs:enumeration value="order"/>
+ <xs:enumeration value="packed_with_control"/>
+ <xs:enumeration value="pixel_aspect_ratio"/>
+ <xs:enumeration value="real_bpp"/>
+ <xs:enumeration value="sr2_format"/>
+ <xs:enumeration value="sraw_40d"/>
+ <xs:enumeration value="sraw_new"/>
+ <xs:enumeration value="srf_format"/>
+ <xs:enumeration value="swapped_wb"/>
+ <xs:enumeration value="wb_mangle"/>
+ <xs:enumeration value="wb_offset"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="HintType">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute type="HintTypeNameType" name="name" use="required"/>
+ <xs:attribute type="xs:string" name="value" use="required"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+ <xs:complexType name="HintsType">
+ <xs:sequence>
+ <xs:element type="HintType" name="Hint" minOccurs="1" maxOccurs="4"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:simpleType name="CameraMakeType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-zA-Z \-,./]{3,27}"/>
+ <xs:minLength value="3"/>
+ <xs:maxLength value="27"/>
+ <xs:enumeration value="ARRI"/>
+ <xs:enumeration value="AVT"/>
+ <xs:enumeration value="AgfaPhoto"/>
+ <xs:enumeration value="Alcatel"/>
+ <xs:enumeration value="Baumer"/>
+ <xs:enumeration value="Canon"/>
+ <xs:enumeration value="Casio"/>
+ <xs:enumeration value="Creative"/>
+ <xs:enumeration value="Creo/Leaf"/>
+ <xs:enumeration value="DJI"/>
+ <xs:enumeration value="EASTMAN KODAK COMPANY"/>
+ <xs:enumeration value="Eastman Kodak Company"/>
+ <xs:enumeration value="FUJIFILM"/>
+ <xs:enumeration value="Foculus"/>
+ <xs:enumeration value="GITUP"/>
+ <xs:enumeration value="Generic"/>
+ <xs:enumeration value="Hasselblad"/>
+ <xs:enumeration value="KODAK"/>
+ <xs:enumeration value="KONICA MINOLTA"/>
+ <xs:enumeration value="Kodak"/>
+ <xs:enumeration value="Konica Minolta Camera, Inc."/>
+ <xs:enumeration value="LEICA CAMERA AG"/>
+ <xs:enumeration value="LEICA"/>
+ <xs:enumeration value="LG Mobile"/>
+ <xs:enumeration value="LGE"/>
+ <xs:enumeration value="Leaf"/>
+ <xs:enumeration value="Leica Camera AG"/>
+ <xs:enumeration value="Mamiya-OP Co.,Ltd."/>
+ <xs:enumeration value="Matrix"/>
+ <xs:enumeration value="Micron"/>
+ <xs:enumeration value="Minolta Co., Ltd."/>
+ <xs:enumeration value="Minolta"/>
+ <xs:enumeration value="NIKON CORPORATION"/>
+ <xs:enumeration value="NIKON"/>
+ <xs:enumeration value="Nikon"/>
+ <xs:enumeration value="Nokia"/>
+ <xs:enumeration value="OLYMPUS CORPORATION"/>
+ <xs:enumeration value="OLYMPUS IMAGING CORP."/>
+ <xs:enumeration value="OLYMPUS OPTICAL CO.,LTD"/>
+ <xs:enumeration value="Olympus"/>
+ <xs:enumeration value="OnePlus"/>
+ <xs:enumeration value="PENTAX Corporation"/>
+ <xs:enumeration value="PENTAX RICOH IMAGING"/>
+ <xs:enumeration value="PENTAX"/>
+ <xs:enumeration value="Panasonic"/>
+ <xs:enumeration value="Paralenz"/>
+ <xs:enumeration value="Pentax"/>
+ <xs:enumeration value="Phase One A/S"/>
+ <xs:enumeration value="Pixelink"/>
+ <xs:enumeration value="RICOH IMAGING COMPANY, LTD."/>
+ <xs:enumeration value="RICOH"/>
+ <xs:enumeration value="RoverShot"/>
+ <xs:enumeration value="SAMSUNG DIGITAL IMA"/>
+ <xs:enumeration value="SAMSUNG TECHWIN Co."/>
+ <xs:enumeration value="SAMSUNG"/>
+ <xs:enumeration value="SEIKO EPSON CORP."/>
+ <xs:enumeration value="SIGMA"/>
+ <xs:enumeration value="SONY"/>
+ <xs:enumeration value="ST Micro"/>
+ <xs:enumeration value="Samsung"/>
+ <xs:enumeration value="Sinar Photography AG"/>
+ <xs:enumeration value="Sinar"/>
+ <xs:enumeration value="Sjcam"/>
+ <xs:enumeration value="Sony"/>
+ <xs:enumeration value="samsung"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="CameraModelType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-zA-Z0-9 \-().,/*]{0,51}"/>
+ <xs:minLength value="0"/>
+ <xs:maxLength value="51"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="CameraTypeModeType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="[a-zA-Z0-9:\-x]{3,29}"/>
+ <xs:minLength value="3"/>
+ <xs:maxLength value="29"/>
+ <xs:enumeration value="12bit"/>
+ <xs:enumeration value="12bit-compressed"/>
+ <xs:enumeration value="12bit-uncompressed"/>
+ <xs:enumeration value="14bit-compressed"/>
+ <xs:enumeration value="14bit-uncompressed"/>
+ <xs:enumeration value="16:9"/>
+ <xs:enumeration value="1:1"/>
+ <xs:enumeration value="3:2"/>
+ <xs:enumeration value="4:3"/>
+ <xs:enumeration value="7424x4924-14bit-uncompressed"/>
+ <xs:enumeration value="chdk"/>
+ <xs:enumeration value="chdk-a"/>
+ <xs:enumeration value="chdk-b"/>
+ <xs:enumeration value="chdk-c"/>
+ <xs:enumeration value="chdk-d"/>
+ <xs:enumeration value="dng"/>
+ <xs:enumeration value="sNEF-uncompressed"/>
+ <xs:enumeration value="sRaw1"/>
+ <xs:enumeration value="sRaw2"/>
+ <xs:enumeration value="compressed"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:simpleType name="CameraTypeSupportedType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="no"/>
+ <xs:minLength value="2"/>
+ <xs:maxLength value="2"/>
+ <xs:enumeration value="no"/>
+ </xs:restriction>
+ </xs:simpleType>
+ <xs:complexType name="CameraType">
+ <xs:sequence>
+ <xs:element type="IDType" name="ID" minOccurs="0" maxOccurs="1"/>
+ <xs:choice>
+ <xs:element type="CFAType" name="CFA" minOccurs="0" maxOccurs="1"/>
+ <xs:element type="CFA2Type" name="CFA2" minOccurs="0" maxOccurs="1"/>
+ </xs:choice>
+ <xs:element type="CropType" name="Crop" minOccurs="0" maxOccurs="1"/>
+ <xs:element type="SensorType" name="Sensor" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element type="BlackAreasType" name="BlackAreas" minOccurs="0" maxOccurs="1"/>
+ <xs:element type="AliasesType" name="Aliases" minOccurs="0" maxOccurs="1"/>
+ <xs:element type="HintsType" name="Hints" minOccurs="0" maxOccurs="1"/>
+ </xs:sequence>
+ <xs:attribute type="CameraMakeType" name="make" use="required"/>
+ <xs:attribute type="CameraModelType" name="model" use="required"/>
+ <xs:attribute type="xs:unsignedByte" name="decoder_version"/>
+ <xs:attribute type="CameraTypeModeType" name="mode"/>
+ <xs:attribute type="CameraTypeSupportedType" name="supported"/>
+ </xs:complexType>
+ <xs:complexType name="CamerasType">
+ <xs:sequence>
+ <xs:element type="CameraType" name="Camera" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:element name="Cameras" type="CamerasType"/>
+</xs:schema>
+<!--
+vim: tabstop=2 shiftwidth=2 softtabstop=2 expandtab
+kate: tab-width: 2; indent-width 2; replace-tabs on; tab-indents: off;
+kate: indent-mode xml; remove-trailing-spaces modified;
+-->
diff --git a/src/external/rawspeed/data/showcameras.xsl b/src/external/rawspeed/data/showcameras.xsl
new file mode 100644
index 000000000..4ec817af3
--- /dev/null
+++ b/src/external/rawspeed/data/showcameras.xsl
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+<xsl:output method = "html" indent = "yes" />
+<xsl:template match="/">
+
+<html>
+ <head>
+ <title>Known RawSpeed Cameras</title>
+ <style type="text/css">
+ body {
+ font-family:Verdana;font-size:12pt;background-color:#ffffff;
+ }
+ h1 {
+ font-size:16pt;padding:0px;padding-top:8px;padding-bottom:8px;
+ }
+ h2 {
+ background-color:teal;color:white;padding:8px;font-size:13pt;
+ }
+ span.param {
+ font-style:italic;color:#666;
+ }
+ div.text {
+ margin-left:20px;margin-bottom:15px;font-size:10pt;margin-top:0px;line-height:120%;
+ }
+ div.toptext {
+ margin-bottom:15px;font-size:10pt;margin-top:0px;line-height:120%;
+ }
+ </style>
+ </head>
+
+ <body>
+ <h1>The <xsl:value-of select="count(Cameras/Camera)"/> Known RawSpeed Cameras and Modes</h1>
+ <xsl:for-each select="Cameras/Camera">
+ <xsl:sort data-type = "text" select = "concat(@make,@model)"/>
+ <h2>
+ <span style="font-weight:bold"><xsl:value-of select="@make"/></span>
+ - <xsl:value-of select="@model"/>
+ <xsl:if test="@mode != ''">, Mode: <span style="font-style:italic;"><xsl:value-of select="@mode"/></span></xsl:if>
+ </h2>
+ <div class="text">
+ <xsl:if test="Aliases">
+ <xsl:for-each select="Aliases/Alias">
+ Also known as: <span class="param">&quot;<xsl:value-of select="."/>&quot;</span><br/>
+ </xsl:for-each>
+ <br/>
+ </xsl:if>
+ <xsl:variable name = "supported" ><xsl:value-of select="@supported"/></xsl:variable>
+ <xsl:if test ="$supported = 'no'">Supported: <span style="color:red;font-style:italic;">No.</span></xsl:if>
+ <xsl:if test ="not($supported = 'no')">Supported: <span style="color:green;font-style:italic;">Yes.</span>
+ <br/><br/>
+ Crop Top,Left: <span class="param"><xsl:value-of select="Crop/@x"/>,<xsl:value-of select="Crop/@y"/> pixels.</span>
+ <br/>
+ <xsl:if test ="Crop/@height &gt; 0">
+ Cropped Image Size: <span class="param"><xsl:value-of select="Crop/@width"/>x<xsl:value-of select="Crop/@height"/></span> pixels.
+ </xsl:if>
+ <xsl:if test ="Crop/@height &lt; 1">
+ Crop Right,Bottom: <span class="param"><xsl:value-of select="-(Crop/@width)"/>,<xsl:value-of select="-(Crop/@height)"/></span> pixels.
+ </xsl:if>
+ <br/>
+ <xsl:for-each select="Sensor">
+ Sensor,
+ <xsl:choose>
+ <xsl:when test ="@iso_min != ''">
+ <xsl:if test ="@iso_max = ''">
+ ISO <xsl:value-of select="@iso_min"/> - Maximum ISO
+ </xsl:if>
+ <xsl:if test ="@iso_max != ''">
+ ISO <xsl:value-of select="@iso_min"/> - <xsl:value-of select="@iso_max"/>
+ </xsl:if>
+ </xsl:when>
+ <xsl:when test ="@iso_max != ''">
+ ISO 0 - <xsl:value-of select="@iso_max"/>
+ </xsl:when>
+ <xsl:when test ="@iso_list != ''">
+ at ISO <xsl:value-of select="@iso_list"/>
+ </xsl:when>
+ <xsl:otherwise>
+ default values
+ </xsl:otherwise>
+ </xsl:choose>
+ - Black: <span class="param"><xsl:value-of select="@black"/></span>, White:
+ <span class="param"><xsl:value-of select="@white"/>.</span>
+ <br/>
+ </xsl:for-each>
+ <xsl:if test="CFA"><br/>
+ Uncropped Sensor Colors Positions:<br/>
+ <xsl:for-each select="CFA/Color">
+ <xsl:sort data-type = "number" select = "@y*2+@x"/>
+ <xsl:variable name = "color" ><xsl:value-of select="."/></xsl:variable>
+ <xsl:if test="position()=last()-1"><br/></xsl:if>
+ <xsl:if test ="$color = 'RED'"><span class="param" style="color:red;">[<xsl:copy-of select="$color" />]</span></xsl:if>
+ <xsl:if test ="$color = 'GREEN'"><span class="param" style="color:green;">[<xsl:copy-of select="$color" />]</span></xsl:if>
+ <xsl:if test ="$color = 'BLUE'"><span class="param" style="color:blue;">[<xsl:copy-of select="$color" />]</span></xsl:if>
+ </xsl:for-each>
+ <br/><br/>
+ </xsl:if>
+ <xsl:if test="CFA2"><br/>
+ Uncropped Sensor Colors Positions:<br/>
+ <xsl:for-each select="CFA2/Color">
+ <xsl:sort data-type = "number" select = "@y*2+@x"/>
+ <xsl:variable name = "color" ><xsl:value-of select="."/></xsl:variable>
+ <xsl:if test="position()=last()-1"><br/></xsl:if>
+ <xsl:if test ="$color = 'RED'"><span class="param" style="color:red;">[<xsl:copy-of select="$color" />]</span></xsl:if>
+ <xsl:if test ="$color = 'GREEN'"><span class="param" style="color:green;">[<xsl:copy-of select="$color" />]</span></xsl:if>
+ <xsl:if test ="$color = 'BLUE'"><span class="param" style="color:blue;">[<xsl:copy-of select="$color" />]</span></xsl:if>
+ </xsl:for-each>
+ <xsl:for-each select="CFA2/ColorRow">
+ <xsl:sort data-type = "number" select = "@y"/>
+ <xsl:value-of select="."/>
+ <br/>
+ </xsl:for-each>
+ <br/>
+ </xsl:if>
+ <xsl:for-each select="BlackAreas/Horizontal">
+ Horizontal Black Area at Y = <span class="param"><xsl:value-of select="@y"/></span>, height is <span class="param"><xsl:value-of select="@height"/> pixels.</span><br/>
+ </xsl:for-each>
+ <xsl:for-each select="BlackAreas/Vertical">
+ Vertical Black Area at X = <span class="param"><xsl:value-of select="@x"/></span>, width is <span class="param"><xsl:value-of select="@width"/> pixels.</span><br/>
+ </xsl:for-each>
+ <xsl:for-each select="Hints/Hint">
+ Decoder Hint: <span class="param">&quot;<xsl:value-of select="@name"/>&quot;</span>:<span class="param">&quot;<xsl:value-of select="@value"/>&quot;</span> <br/>
+ </xsl:for-each>
+ </xsl:if>
+ </div>
+ </xsl:for-each>
+ <div class="toptext">There is a total of <xsl:value-of select="count(Cameras/Camera[not(@model=preceding-sibling::Camera/@model)]/@model)"/> unique cameras.</div>
+
+ </body>
+</html>
+
+</xsl:template>
+</xsl:stylesheet>
diff --git a/src/external/rawspeed/docs/CMakeLists.txt b/src/external/rawspeed/docs/CMakeLists.txt
new file mode 100644
index 000000000..2fe2b92db
--- /dev/null
+++ b/src/external/rawspeed/docs/CMakeLists.txt
@@ -0,0 +1,78 @@
+if(NOT BUILD_DOCS)
+ return()
+endif()
+
+add_custom_target(docs)
+
+message(STATUS "Looking for Doxygen")
+message(STATUS "Looking for dot")
+find_package(Doxygen REQUIRED)
+
+if(NOT DOXYGEN_FOUND)
+ message(SEND_ERROR "Looking for Doxygen - failed")
+else()
+ message(STATUS "Looking for Doxygen - found")
+endif()
+
+if(NOT DOXYGEN_DOT_FOUND)
+ message(SEND_ERROR "Looking for dot - failed")
+else()
+ message(STATUS "Looking for dot - found")
+endif()
+
+if(NOT DOXYGEN_FOUND OR NOT DOXYGEN_DOT_FOUND)
+ message(SEND_ERROR "Will not be able to build docs. You can pass -DBUILD_DOCS=OFF to disable build of documentation.")
+ return()
+else()
+ message(STATUS "Will be able to build doxygen docs")
+endif()
+
+SET_PACKAGE_PROPERTIES(Doxygen PROPERTIES
+ URL http://www.doxygen.org
+ DESCRIPTION "API Documentation generation system for C, C++"
+ PURPOSE "Used for generating the automatic API documentation from sources"
+)
+
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in" "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" @ONLY)
+
+add_custom_target(doxygen
+ "${DOXYGEN_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+ COMMENT "Generating API documentation with Doxygen"
+ VERBATIM
+ USES_TERMINAL
+)
+
+add_custom_target(
+ doxygen-clean
+ COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/html/doxygen"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+ COMMENT "Removing Doxygen-generated HTML API documentation"
+)
+
+add_dependencies(docs doxygen)
+
+message(STATUS "Looking for Sphinx")
+find_package(Sphinx REQUIRED)
+if(NOT Sphinx_FOUND)
+ message(SEND_ERROR "Looking for Sphinx - failed")
+else()
+ message(STATUS "Looking for Sphinx - found")
+endif()
+
+add_custom_target(sphinx
+ "${SPHINX_BUILD_PATH}" -b html -a -c "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/html"
+ WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+ COMMENT "Generating documentation with Sphinx"
+ VERBATIM
+ USES_TERMINAL
+)
+
+add_custom_target(
+ docs-clean
+ COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/html"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+ COMMENT "Removing generated HTML documentation (both sphinx and doxygen)"
+)
+
+add_dependencies(docs sphinx)
diff --git a/src/external/rawspeed/docs/CameraSupport.rst b/src/external/rawspeed/docs/CameraSupport.rst
new file mode 100644
index 000000000..027b8262e
--- /dev/null
+++ b/src/external/rawspeed/docs/CameraSupport.rst
@@ -0,0 +1,94 @@
+================================================================================
+Camera Support
+================================================================================
+
+.. exec::
+ from xml.dom.minidom import parse
+ import xml.dom.minidom
+
+ DOMTree = xml.dom.minidom.parse("data/cameras.xml")
+ cameras = DOMTree.documentElement.getElementsByTagName("Camera")
+
+ unique_makes = dict()
+
+ for camera in cameras:
+ make = ''
+ model = ''
+
+ if len(camera.getElementsByTagName('ID')) > 0:
+ ID = camera.getElementsByTagName('ID')[0]
+ make = ID.getAttribute("make")
+ model = ID.getAttribute("model")
+ else:
+ make = camera.getAttribute("make")
+ model = camera.getAttribute("model")
+
+ unique_makes[make] = unique_makes.get(make, dict())
+ unique_makes[make][model] = unique_makes[make].get(model, dict())
+ unique_makes[make][model]['modes'] = unique_makes[
+ make][model].get('modes', set())
+ unique_makes[make][model]['aliases'] = unique_makes[
+ make][model].get('aliases', set())
+
+ mode = camera.getAttribute("mode")
+ if mode == '':
+ mode = 'Default mode'
+ if camera.hasAttribute("supported") and camera.getAttribute("supported") == 'no':
+ mode += " - *unsupported*"
+
+ unique_makes[make][model]['modes'].add(mode)
+
+ for alias in camera.getElementsByTagName('Alias'):
+ if alias.getAttribute("id") != '':
+ unique_makes[make][model][
+ 'aliases'].add(alias.getAttribute("id"))
+ else:
+ unique_makes[make][model][
+ 'aliases'].add(alias.childNodes[0].data)
+
+ from collections import OrderedDict
+
+ unique_makes = OrderedDict(sorted(unique_makes.items()))
+
+ print("There are %i known camera makers, " % len(unique_makes))
+
+ count_unique_makesmodels = 0
+ for make, models in unique_makes.items():
+ count_unique_makesmodels += len(models)
+
+ print("%i known unique camera models.\n" % count_unique_makesmodels)
+
+ print(
+ "Any support is impossible without the samples.\nCurrently, |rpu-button-cameras| cameras have samples, with total count of |rpu-button-samples| unique samples. **Please contribute samples**!\n\n")
+
+ for make, models in unique_makes.items():
+ print(make)
+ print('=' * len(make), "\n")
+
+ print("Known cameras: ", len(models), "\n")
+
+ models = OrderedDict(sorted(models.items()))
+ for model, content in models.items():
+ if len(content['modes']) > 1 or 'Default mode' in content['modes']:
+ print("* ", model, "\n")
+ else:
+ print("* ", model, " - *unsupported*\n")
+
+ if len(content['modes']) > 1:
+ print(" modes:\n")
+ for mode in content['modes']:
+ print(" * ", mode, "\n")
+
+ if len(content['aliases']) > 1:
+ print(" aliases:\n")
+ for alias in content['aliases']:
+ print(" * ", alias, "\n")
+
+ print("\n\n")
+
+
+.. |rpu-button-cameras| image:: https://raw.pixls.us/button-cameras.svg
+ :target: https://raw.pixls.us/
+
+.. |rpu-button-samples| image:: https://raw.pixls.us/button-samples.svg
+ :target: https://raw.pixls.us/
diff --git a/src/external/rawspeed/docs/Doxyfile.in b/src/external/rawspeed/docs/Doxyfile.in
new file mode 100644
index 000000000..0a0dc9376
--- /dev/null
+++ b/src/external/rawspeed/docs/Doxyfile.in
@@ -0,0 +1,2497 @@
+# Doxyfile 1.8.13
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = RawSpeed
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = @PACKAGE_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "fast raw decoding library"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/html/
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = YES
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = YES
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@/src/
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH = @PROJECT_SOURCE_DIR@/src/librawspeed/
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 0.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 0
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = YES
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = YES
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = YES
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = @PROJECT_SOURCE_DIR@ \
+ @PROJECT_BINARY_DIR@
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py \
+ *.pyw \
+ *.f90 \
+ *.f95 \
+ *.f03 \
+ *.f08 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE = @CMAKE_BINARY_DIR@ \
+ @PROJECT_BINARY_DIR@ \
+ *.md \
+ *.markdown
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = YES
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS = -xc++ \
+ -std=c++11
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = doxygen
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = YES
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = YES
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH = @DOXYGEN_DOT_PATH@
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/src/external/rawspeed/docs/Doxygen.rst b/src/external/rawspeed/docs/Doxygen.rst
new file mode 100644
index 000000000..0ae15e428
--- /dev/null
+++ b/src/external/rawspeed/docs/Doxygen.rst
@@ -0,0 +1,8 @@
+================================================================================
+Doxygen
+================================================================================
+
+.. meta::
+ :http-equiv=refresh: 0; url=doxygen/
+
+`The Doxygen-based documentation is available here <doxygen/>`_
diff --git a/src/external/rawspeed/docs/conf.py b/src/external/rawspeed/docs/conf.py
new file mode 100644
index 000000000..629d3e756
--- /dev/null
+++ b/src/external/rawspeed/docs/conf.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# RawSpeed documentation build configuration file, created by
+# sphinx-quickstart on Mon Aug 14 18:30:09 2017.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+
+import os
+import sys
+sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = ['sphinx.ext.githubpages', 'sphinx-pyexec']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'RawSpeed'
+copyright = '2009-2016 Klaus Post, 2016-2017 Roman Lebedev'
+author = '(c) Authors'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = ''
+# The full version, including alpha/beta/rc tags.
+release = ''
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = []
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'sphinx_rtd_theme'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
diff --git a/src/external/rawspeed/docs/index.rst b/src/external/rawspeed/docs/index.rst
new file mode 100644
index 000000000..0d1407590
--- /dev/null
+++ b/src/external/rawspeed/docs/index.rst
@@ -0,0 +1,23 @@
+.. RawSpeed documentation master file, created by
+ sphinx-quickstart on Mon Aug 14 18:30:09 2017.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to RawSpeed's documentation!
+====================================
+
+.. toctree::
+ :maxdepth: 2
+ :hidden:
+
+ self
+ CameraSupport
+ Doxygen
+
+.. include:: ../README.rst
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/src/external/rawspeed/docs/sphinx-pyexec.py b/src/external/rawspeed/docs/sphinx-pyexec.py
new file mode 100644
index 000000000..25fb8f790
--- /dev/null
+++ b/src/external/rawspeed/docs/sphinx-pyexec.py
@@ -0,0 +1,53 @@
+try:
+ from StringIO import StringIO
+except ImportError:
+ from io import StringIO
+
+import sys
+from docutils.parsers.rst import Directive
+from docutils import nodes
+from sphinx.util import nested_parse_with_titles
+from docutils.statemachine import StringList
+
+
+class ExecDirective(Directive):
+ has_content = True
+ required_arguments = 0
+
+ def execute_code(cls, code):
+ codeOut = StringIO()
+ codeErr = StringIO()
+
+ sys.stdout = codeOut
+ sys.stderr = codeErr
+
+ exec(code)
+
+ sys.stdout = sys.__stdout__
+ sys.stderr = sys.__stderr__
+
+ results = list()
+ results.append(codeOut.getvalue())
+ results.append(codeErr.getvalue())
+ results = ''.join(results)
+
+ return results
+
+ def run(self):
+ self.assert_has_content()
+
+ code = '\n'.join(self.content)
+ code_results = self.execute_code(code)
+
+ sl = StringList(code_results.replace("\r", "").split("\n"))
+
+ node = nodes.paragraph()
+ nested_parse_with_titles(self.state, sl, node)
+
+ output = []
+ output.append(node)
+ return output
+
+
+def setup(app):
+ app.add_directive('exec', ExecDirective)
diff --git a/src/external/rawspeed/fuzz/CMakeLists.txt b/src/external/rawspeed/fuzz/CMakeLists.txt
new file mode 100644
index 000000000..0f3cac4c7
--- /dev/null
+++ b/src/external/rawspeed/fuzz/CMakeLists.txt
@@ -0,0 +1,73 @@
+file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/all-fuzzers.txt" ALL_EXPECTED_FUZZERS)
+list(SORT ALL_EXPECTED_FUZZERS)
+
+set(ALL_FUZZERS "" CACHE INTERNAL "" FORCE)
+
+if(CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
+ # want all the symbols.
+ add_library(rawspeed_fuzz STATIC) # SHARED, but crashes due to global constructors/destructors
+else()
+ add_library(rawspeed_fuzz STATIC)
+endif()
+
+target_link_libraries(rawspeed_fuzz PUBLIC rawspeed)
+
+macro(add_fuzz_target__base fuzzer)
+ target_link_libraries(${fuzzer} PUBLIC rawspeed)
+ target_link_libraries(${fuzzer} PUBLIC rawspeed_fuzz)
+
+ list(APPEND ALL_FUZZERS "${fuzzer}")
+ set(ALL_FUZZERS "${ALL_FUZZERS}" CACHE INTERNAL "" FORCE)
+
+ add_test(NAME fuzzers/${fuzzer} COMMAND ${fuzzer} -help=1)
+endmacro()
+
+if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_BUILD_TYPE STREQUAL "FUZZ"))
+ message(WARNING "For fuzzets to function, compiler must be Clang, and build type must be FUZZ.")
+
+ target_sources(rawspeed_fuzz PRIVATE
+ "${CMAKE_CURRENT_SOURCE_DIR}/libFuzzer_dummy_main.cpp"
+ )
+
+ if(WITH_OPENMP AND OPENMP_FOUND AND TARGET OpenMP::OpenMP)
+ target_link_libraries(rawspeed_fuzz PUBLIC OpenMP::OpenMP)
+ endif()
+
+ macro(add_fuzz_target fuzzer)
+ add_fuzz_target__base(${fuzzer})
+ endmacro()
+else()
+ if(NOT LIB_FUZZING_ENGINE)
+ # specialhandling: oss-fuzz provides all the needed flags already.
+ target_compile_options(rawspeed_fuzz INTERFACE "-fsanitize=fuzzer")
+ target_link_libraries (rawspeed_fuzz INTERFACE "-fsanitize=fuzzer")
+ else()
+ message(STATUS "LIB_FUZZING_ENGINE override option is passed, not setting special compiler flags.")
+ find_package(LibFuzzingEngine REQUIRED)
+ target_link_libraries(rawspeed_fuzz PUBLIC LibFuzzingEngine)
+ endif()
+
+ add_feature_info("Fuzzing" ON "will be actually able to do the fuzzing")
+
+ file(GLOB FUZZ_DICT "common.dict")
+
+ macro(add_fuzz_target fuzzer)
+ add_fuzz_target__base(${fuzzer})
+
+ install(TARGETS ${fuzzer} DESTINATION "${CMAKE_INSTALL_BINDIR}")
+ install(FILES "${FUZZ_DICT}" DESTINATION "${CMAKE_INSTALL_BINDIR}" RENAME "${fuzzer}.dict")
+ endmacro()
+endif()
+
+add_custom_target(fuzzers ALL)
+
+add_subdirectory(librawspeed)
+add_subdirectory(rawspeed)
+
+add_subdirectory(corpora)
+
+list(SORT ALL_FUZZERS)
+if(NOT "${ALL_FUZZERS}" STREQUAL "${ALL_EXPECTED_FUZZERS}")
+ message(SEND_ERROR "Actual list of fuzzers does not match the expected list: "
+ "${ALL_FUZZERS} vs ${ALL_EXPECTED_FUZZERS}")
+endif()
diff --git a/src/external/rawspeed/fuzz/all-fuzzers.txt b/src/external/rawspeed/fuzz/all-fuzzers.txt
new file mode 100644
index 000000000..d8872b1cf
--- /dev/null
+++ b/src/external/rawspeed/fuzz/all-fuzzers.txt
@@ -0,0 +1,51 @@
+CiffParserFuzzer-GetDecoder
+CiffParserFuzzer-GetDecoder-Decode
+Cr2DecompressorFuzzer
+CrwDecompressorFuzzer
+DummyLJpegDecompressorFuzzer
+FiffParserFuzzer-GetDecoder
+FiffParserFuzzer-GetDecoder-Decode
+FujiDecompressorFuzzer
+HasselbladDecompressorFuzzer
+HuffmanTableFuzzer-BitPumpJPEG-FullDecode
+HuffmanTableFuzzer-BitPumpJPEG-NoFullDecode
+HuffmanTableFuzzer-BitPumpLSB-FullDecode
+HuffmanTableFuzzer-BitPumpLSB-NoFullDecode
+HuffmanTableFuzzer-BitPumpMSB-FullDecode
+HuffmanTableFuzzer-BitPumpMSB-NoFullDecode
+HuffmanTableFuzzer-BitPumpMSB16-FullDecode
+HuffmanTableFuzzer-BitPumpMSB16-NoFullDecode
+HuffmanTableFuzzer-BitPumpMSB32-FullDecode
+HuffmanTableFuzzer-BitPumpMSB32-NoFullDecode
+KodakDecompressorFuzzer
+LJpegDecompressorFuzzer
+NikonDecompressorFuzzer
+OlympusDecompressorFuzzer
+PanasonicDecompressorFuzzer
+PentaxDecompressorFuzzer
+RawParserFuzzer-GetDecoder
+RawParserFuzzer-GetDecoder-Decode
+RawSpeedFuzzer
+SamsungV0DecompressorFuzzer
+SamsungV1DecompressorFuzzer
+SamsungV2DecompressorFuzzer
+SonyArw1DecompressorFuzzer
+SonyArw2DecompressorFuzzer
+TiffDecoderFuzzer-ArwDecoder
+TiffDecoderFuzzer-Cr2Decoder
+TiffDecoderFuzzer-DcrDecoder
+TiffDecoderFuzzer-DcsDecoder
+TiffDecoderFuzzer-DngDecoder
+TiffDecoderFuzzer-ErfDecoder
+TiffDecoderFuzzer-IiqDecoder
+TiffDecoderFuzzer-KdcDecoder
+TiffDecoderFuzzer-MefDecoder
+TiffDecoderFuzzer-MosDecoder
+TiffDecoderFuzzer-NefDecoder
+TiffDecoderFuzzer-OrfDecoder
+TiffDecoderFuzzer-PefDecoder
+TiffDecoderFuzzer-Rw2Decoder
+TiffDecoderFuzzer-SrwDecoder
+TiffDecoderFuzzer-ThreefrDecoder
+TiffParserFuzzer-GetDecoder
+TiffParserFuzzer-GetDecoder-Decode
diff --git a/src/external/rawspeed/fuzz/common.dict b/src/external/rawspeed/fuzz/common.dict
new file mode 100644
index 000000000..a25f75e7a
--- /dev/null
+++ b/src/external/rawspeed/fuzz/common.dict
@@ -0,0 +1,136 @@
+# this file contains all the simple/same words manually extracted from the code.
+
+# MRW
+"\x00\x4D\x52\x4D"
+"PRD"
+"WBG"
+"TTF"
+
+# ARI
+"ARRI\x12\x34\x56\x78"
+
+# RAF
+"FUJIFILMCCD-RAW "
+"FUJIFILM"
+
+# TIFF endianness
+"II"
+"MM"
+
+# TIFF magic
+"42"
+
+# ORF
+"\x4F\x52"
+"\x53\x52"
+
+# RW2
+"\x55"
+
+# TIFF
+"Adobe"
+
+# TIFF makernotes
+"MakN"
+"AOC\x00"
+"PENTAX"
+"Pentax makernote"
+"FUJIFILM\x0c\x00\x00\x00"
+"Nikon\x00\x02"
+"Nikon makernote"
+"OLYMPUS"
+"OLYMP"
+"EPSON"
+"Exif"
+"Panosonic makernote"
+"SAMSUNG"
+
+# MOS
+"Leaf"
+"Phase One A/S"
+"Camera Library"
+
+# CR2
+"Canon"
+"Kodak"
+"DCS560C"
+
+# NEF
+"NIKON CORPORATION"
+"NIKON"
+"NIKON D100 "
+
+# ORF
+"OLYMPUS IMAGING CORP."
+"OLYMPUS CORPORATION"
+"OLYMPUS OPTICAL CO.,LTD"
+
+# ARW
+"SONY"
+"DSLR-A100"
+
+# PEF
+"PENTAX Corporation"
+"RICOH IMAGING COMPANY, LTD."
+"PENTAX"
+
+# RW2
+"Panasonic"
+"LEICA"
+
+# SRW
+"SAMSUNG"
+
+# MEF
+"Mamiya-OP Co.,Ltd."
+
+# DCR
+"Kodak"
+
+# DCS
+"KODAK"
+
+# KDC
+"EASTMAN KODAK COMPANY"
+
+# ERF
+"SEIKO EPSON CORP."
+
+# threefr
+"Hasselblad"
+
+# X3f
+"\x62\x56\x4F\x46"
+
+# autogenerated make list
+"Canon"
+"DJI"
+"Eastman Kodak Company"
+"FUJIFILM"
+"GoPro"
+"HUAWEI"
+"Hasselblad"
+"KODAK"
+"Kodak"
+"LEICA CAMERA AG"
+"Leica Camera AG"
+"Mamiya-OP Co.,Ltd."
+"Minolta Co.,Ltd."
+"NIKON"
+"NIKON CORPORATION"
+"Nikon"
+"OLYMPUS CORPORATION"
+"OLYMPUS IMAGING CORP."
+"OLYMPUS OPTICAL CO.,LTD"
+"OnePlus"
+"PENTAX"
+"PENTAX Corporation"
+"Panasonic"
+"RICOH"
+"RICOH IMAGING COMPANY, LTD."
+"SAMSUNG"
+"SAMSUNG DIGITAL IMA"
+"SEIKO EPSON CORP."
+"SONY"
+"Yuneec"
+"samsung"
diff --git a/src/external/rawspeed/fuzz/corpora/CMakeLists.txt b/src/external/rawspeed/fuzz/corpora/CMakeLists.txt
new file mode 100644
index 000000000..528606d93
--- /dev/null
+++ b/src/external/rawspeed/fuzz/corpora/CMakeLists.txt
@@ -0,0 +1,24 @@
+file(GLOB_RECURSE CORPORA_ROOTS FOLLOW_SYMLINKS "${CMAKE_CURRENT_SOURCE_DIR}/**/timestamp.txt")
+foreach(TOP_CORPORA_DIR ${CORPORA_ROOTS})
+ get_filename_component(TOP_CORPORA_DIRS "${TOP_CORPORA_DIR}" DIRECTORY)
+ file(GLOB CORPORAS FOLLOW_SYMLINKS "${TOP_CORPORA_DIRS}/*")
+
+ foreach(CORPORA ${CORPORAS})
+ if(IS_DIRECTORY "${CORPORA}")
+ get_filename_component(dirname "${CORPORA}" NAME)
+ list(FIND ALL_FUZZERS "${dirname}" IsFuzzerName)
+
+ if(NOT IsFuzzerName EQUAL -1)
+ # get all the files
+ file(GLOB_RECURSE CORPUSES RELATIVE "${CORPORA}" FOLLOW_SYMLINKS "${CORPORA}/*")
+
+ set(test "corpora/${dirname}")
+ add_test(NAME ${test}
+ COMMAND ${dirname} ${CORPUSES}
+ WORKING_DIRECTORY "${CORPORA}")
+ set_tests_properties(${test} PROPERTIES DEPENDS ${dirname})
+ set_tests_properties(${test} PROPERTIES TIMEOUT 300)
+ endif()
+ endif()
+ endforeach()
+endforeach()
diff --git a/src/external/rawspeed/fuzz/libFuzzer_dummy_main.cpp b/src/external/rawspeed/fuzz/libFuzzer_dummy_main.cpp
new file mode 100644
index 000000000..fc6ab6b18
--- /dev/null
+++ b/src/external/rawspeed/fuzz/libFuzzer_dummy_main.cpp
@@ -0,0 +1,73 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "io/Buffer.h" // for Buffer
+#include "io/FileIOException.h" // for FileIOException
+#include "io/FileReader.h" // for FileReader
+#include <cstdint> // for uint8_t
+#include <cstdlib> // for EXIT_SUCCESS, size_t
+#include <iostream> // for operator<<, cout, ostream
+#include <memory> // for unique_ptr
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+static int usage() {
+ std::cout << "This is just a placeholder.\nFor fuzzers to actually function, "
+ "you need to build rawspeed with clang compiler, with FUZZ "
+ "build type.\n";
+
+ return EXIT_SUCCESS;
+}
+
+static void process(const char* filename) noexcept {
+ rawspeed::FileReader reader(filename);
+ std::unique_ptr<const rawspeed::Buffer> buf;
+
+ try {
+ buf = reader.readFile();
+ } catch (rawspeed::FileIOException&) {
+ // failed to read the file for some reason.
+ // just ignore it.
+ return;
+ }
+
+ LLVMFuzzerTestOneInput(buf->getData(0, buf->getSize()), buf->getSize());
+}
+
+int main(int argc, char** argv) {
+ if (1 == argc || (2 == argc && std::string("-help=1") == argv[1]))
+ return usage();
+
+#ifdef _OPENMP
+ const auto corpusCount = argc - 1;
+ auto chunkSize = (corpusCount / (10 * omp_get_num_threads()));
+ if (chunkSize <= 1)
+ chunkSize = 1;
+#pragma omp parallel for default(shared) schedule(dynamic, chunkSize)
+#endif
+ for (int i = 1; i < argc; ++i)
+ process(argv[i]);
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/CMakeLists.txt b/src/external/rawspeed/fuzz/librawspeed/CMakeLists.txt
new file mode 100644
index 000000000..026593fdf
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/CMakeLists.txt
@@ -0,0 +1,6 @@
+target_include_directories(rawspeed_fuzz PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
+
+add_subdirectory(decoders)
+add_subdirectory(decompressors)
+add_subdirectory(fuzz)
+add_subdirectory(parsers)
diff --git a/src/external/rawspeed/fuzz/librawspeed/decoders/CMakeLists.txt b/src/external/rawspeed/fuzz/librawspeed/decoders/CMakeLists.txt
new file mode 100644
index 000000000..067ed8af0
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decoders/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(TiffDecoders)
diff --git a/src/external/rawspeed/fuzz/librawspeed/decoders/TiffDecoders/CMakeLists.txt b/src/external/rawspeed/fuzz/librawspeed/decoders/TiffDecoders/CMakeLists.txt
new file mode 100644
index 000000000..04d9f8692
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decoders/TiffDecoders/CMakeLists.txt
@@ -0,0 +1,40 @@
+add_custom_target(TiffBasedDecoderFuzzers ALL)
+add_dependencies(fuzzers TiffBasedDecoderFuzzers)
+
+function(add_decoder {decoder})
+ set(fuzzer "TiffDecoderFuzzer-${decoder}")
+
+ add_executable(${fuzzer} main.cpp)
+ target_compile_definitions(${fuzzer}
+ PRIVATE
+ -DDECODER=${decoder}
+ )
+
+ add_fuzz_target(${fuzzer})
+
+ add_dependencies(TiffBasedDecoderFuzzers ${fuzzer})
+endfunction()
+
+# see TiffParser::Map[]
+set(DECODERS
+ "ArwDecoder"
+ "Cr2Decoder"
+ "DcrDecoder"
+ "DcsDecoder"
+ "DngDecoder"
+ "ErfDecoder"
+ "IiqDecoder"
+ "KdcDecoder"
+ "MefDecoder"
+ "MosDecoder"
+ "NefDecoder"
+ "OrfDecoder"
+ "PefDecoder"
+ "Rw2Decoder"
+ "SrwDecoder"
+ "ThreefrDecoder"
+)
+
+foreach(decoder IN LISTS DECODERS)
+ add_decoder(${decoder})
+endforeach()
diff --git a/src/external/rawspeed/fuzz/librawspeed/decoders/TiffDecoders/main.cpp b/src/external/rawspeed/fuzz/librawspeed/decoders/TiffDecoders/main.cpp
new file mode 100644
index 000000000..2ca62c82e
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decoders/TiffDecoders/main.cpp
@@ -0,0 +1,84 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef DECODER
+#error DECODER must be defined
+#endif
+
+#include "common/RawspeedException.h" // for RawspeedException
+#include "decoders/ArwDecoder.h" // IWYU pragma: keep
+#include "decoders/Cr2Decoder.h" // IWYU pragma: keep
+#include "decoders/DcrDecoder.h" // IWYU pragma: keep
+#include "decoders/DcsDecoder.h" // IWYU pragma: keep
+#include "decoders/DngDecoder.h" // IWYU pragma: keep
+#include "decoders/ErfDecoder.h" // IWYU pragma: keep
+#include "decoders/IiqDecoder.h" // IWYU pragma: keep
+#include "decoders/KdcDecoder.h" // IWYU pragma: keep
+#include "decoders/MefDecoder.h" // IWYU pragma: keep
+#include "decoders/MosDecoder.h" // IWYU pragma: keep
+#include "decoders/NefDecoder.h" // IWYU pragma: keep
+#include "decoders/OrfDecoder.h" // IWYU pragma: keep
+#include "decoders/PefDecoder.h" // IWYU pragma: keep
+#include "decoders/RafDecoder.h" // IWYU pragma: keep
+#include "decoders/Rw2Decoder.h" // IWYU pragma: keep
+#include "decoders/SrwDecoder.h" // IWYU pragma: keep
+#include "decoders/ThreefrDecoder.h" // IWYU pragma: keep
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "metadata/CameraMetaData.h" // for CameraMetaData
+#include "parsers/TiffParser.h" // for TiffParser
+#include <algorithm> // for move
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+#include <memory> // for unique_ptr
+
+static const rawspeed::CameraMetaData metadata{};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+using rawspeed::DECODER;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer buffer(Data, Size);
+ auto ifd = rawspeed::TiffParser::parse(buffer);
+
+ // ATM do not care if this is the appropriate decoder.
+ // only check that the check does not crash.
+ (void)DECODER::isAppropriateDecoder(ifd.get(), &buffer);
+
+ auto decoder = std::make_unique<DECODER>(std::move(ifd), &buffer);
+
+ decoder->applyCrop = false;
+ decoder->interpolateBadPixels = false;
+ decoder->failOnUnknown = false;
+ // decoder->checkSupport(&metadata);
+
+ decoder->decodeRaw();
+ decoder->decodeMetaData(&metadata);
+
+ } catch (rawspeed::RawspeedException&) {
+ return 0;
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/CMakeLists.txt b/src/external/rawspeed/fuzz/librawspeed/decompressors/CMakeLists.txt
new file mode 100644
index 000000000..50bf046ae
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/CMakeLists.txt
@@ -0,0 +1,33 @@
+macro(add_simple_fuzzer name)
+ set(TheFuzzer "${name}Fuzzer")
+ add_executable(${TheFuzzer} "${name}.cpp")
+
+ add_fuzz_target(${TheFuzzer})
+
+ add_dependencies(fuzzers ${TheFuzzer})
+endmacro()
+
+add_subdirectory(HuffmanTable)
+
+set(DECOMPRESSORS
+ "Cr2Decompressor"
+ "CrwDecompressor"
+ "DummyLJpegDecompressor"
+ "FujiDecompressor"
+ "HasselbladDecompressor"
+ "KodakDecompressor"
+ "LJpegDecompressor"
+ "NikonDecompressor"
+ "OlympusDecompressor"
+ "PanasonicDecompressor"
+ "PentaxDecompressor"
+ "SamsungV0Decompressor"
+ "SamsungV1Decompressor"
+ "SamsungV2Decompressor"
+ "SonyArw1Decompressor"
+ "SonyArw2Decompressor"
+)
+
+foreach(decompressor IN LISTS DECOMPRESSORS)
+ add_simple_fuzzer(${decompressor})
+endforeach()
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/Cr2Decompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/Cr2Decompressor.cpp
new file mode 100644
index 000000000..90ddc041e
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/Cr2Decompressor.cpp
@@ -0,0 +1,65 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/Cr2Decompressor.h" // for Cr2Decompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::
+#include <algorithm> // for generate_n, fill_n
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+#include <iterator> // for back_insert_iterator
+#include <vector> // for vector
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ using slice_type = int;
+ std::vector<slice_type> slicesWidths;
+ const unsigned sliceCount = bs.getU32();
+ bs.check(sliceCount, sizeof(slice_type));
+ slicesWidths.reserve(sliceCount);
+ std::generate_n(std::back_inserter(slicesWidths), sliceCount,
+ [&bs]() -> slice_type { return bs.get<slice_type>(); });
+
+ rawspeed::Cr2Decompressor c(bs, mRaw);
+ mRaw->createData();
+ c.decode(std::move(slicesWidths));
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/CrwDecompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/CrwDecompressor.cpp
new file mode 100644
index 000000000..21c0dcb3d
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/CrwDecompressor.cpp
@@ -0,0 +1,59 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/CrwDecompressor.h" // for CrwDecompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ const rawspeed::uint32 dec_table = bs.getU32();
+ const rawspeed::uint32 lowbits = bs.getU32();
+
+ rawspeed::Buffer mFile = bs.getBuffer(bs.getRemainSize());
+
+ rawspeed::CrwDecompressor c(mRaw, dec_table, lowbits, &mFile);
+ mRaw->createData();
+ c.decompress();
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/DummyLJpegDecompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/DummyLJpegDecompressor.cpp
new file mode 100644
index 000000000..38b525677
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/DummyLJpegDecompressor.cpp
@@ -0,0 +1,70 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "decompressors/AbstractLJpegDecompressor.h" // for AbstractLJpegDe...
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endi...
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+namespace {
+
+class DummyLJpegDecompressor final
+ : public rawspeed::AbstractLJpegDecompressor {
+ void decodeScan() override {}
+
+public:
+ DummyLJpegDecompressor(const rawspeed::ByteStream& bs,
+ const rawspeed::RawImage& img)
+ : AbstractLJpegDecompressor(bs, img) {}
+
+ void decode() { AbstractLJpegDecompressor::decode(); }
+};
+
+} // namespace
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ DummyLJpegDecompressor d(bs, mRaw);
+ d.decode();
+ mRaw->createData();
+
+ // no image data was actually be decoded, so don't check for initialization
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/FujiDecompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/FujiDecompressor.cpp
new file mode 100644
index 000000000..92bb96e7c
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/FujiDecompressor.cpp
@@ -0,0 +1,55 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/FujiDecompressor.h" // for FujiDecompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+ mRaw->cfa = CreateCFA(&bs);
+
+ rawspeed::FujiDecompressor f(mRaw, bs.getStream(bs.getRemainSize()));
+ mRaw->createData();
+ f.decompress();
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/HasselbladDecompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/HasselbladDecompressor.cpp
new file mode 100644
index 000000000..204c0cba7
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/HasselbladDecompressor.cpp
@@ -0,0 +1,56 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/HasselbladDecompressor.h" // for HasselbladDecompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianne...
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ const auto pixelBaseOffset = bs.get<int>();
+
+ rawspeed::HasselbladDecompressor h(bs, mRaw);
+ mRaw->createData();
+ h.decode(pixelBaseOffset);
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/HuffmanTable/CMakeLists.txt b/src/external/rawspeed/fuzz/librawspeed/decompressors/HuffmanTable/CMakeLists.txt
new file mode 100644
index 000000000..9213c2cbc
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/HuffmanTable/CMakeLists.txt
@@ -0,0 +1,29 @@
+add_custom_target(HuffmanTableFuzzers ALL)
+add_dependencies(fuzzers HuffmanTableFuzzers)
+
+set(FullDecode true)
+set(NoFullDecode false)
+
+function(add_ht_fuzzer pump decode)
+ set(fuzzer "HuffmanTableFuzzer-${pump}-${decode}")
+
+ add_executable(${fuzzer} main.cpp)
+ target_compile_definitions(${fuzzer}
+ PRIVATE
+ -DPUMP=${pump}
+ -DFULLDECODE=${${decode}}
+ )
+
+ add_fuzz_target(${fuzzer})
+
+ add_dependencies(HuffmanTableFuzzers ${fuzzer})
+endfunction()
+
+set(PUMPS "BitPumpLSB" "BitPumpMSB" "BitPumpMSB16" "BitPumpMSB32" "BitPumpJPEG")
+set(DECODE "FullDecode" "NoFullDecode")
+
+foreach(pump IN LISTS PUMPS)
+ foreach(decode IN LISTS DECODE)
+ add_ht_fuzzer(${pump} ${decode})
+ endforeach()
+endforeach()
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/HuffmanTable/main.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/HuffmanTable/main.cpp
new file mode 100644
index 000000000..0d75fd6e6
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/HuffmanTable/main.cpp
@@ -0,0 +1,88 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef PUMP
+#error PUMP must be defined to one of rawspeeds pumps
+#endif
+#ifndef FULLDECODE
+#error FULLDECODE must be defined as bool
+#endif
+
+#include "common/RawspeedException.h" // for RawspeedException
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/BitPumpJPEG.h" // IWYU pragma: keep
+#include "io/BitPumpLSB.h" // IWYU pragma: keep
+#include "io/BitPumpMSB.h" // IWYU pragma: keep
+#include "io/BitPumpMSB16.h" // IWYU pragma: keep
+#include "io/BitPumpMSB32.h" // IWYU pragma: keep
+#include "io/BitStream.h" // for BitStream
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::little
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+static rawspeed::HuffmanTable createHuffmanTable(rawspeed::ByteStream* bs) {
+ rawspeed::HuffmanTable ht;
+
+ // first 16 bytes are consumed as n-codes-per-length
+ const auto count = ht.setNCodesPerLength(bs->getBuffer(16));
+
+ // and then count more bytes consumed as code values
+ ht.setCodeValues(bs->getBuffer(count));
+
+ // and one more byte as 'fixDNGBug16' boolean
+ const auto bb = bs->getBuffer(1);
+ const bool fixDNGBug16 = bb[0] != 0;
+ ht.setup(FULLDECODE, fixDNGBug16);
+
+ return ht;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ const rawspeed::HuffmanTable ht = createHuffmanTable(&bs);
+
+ // should have consumed 16 bytes for n-codes-per-length,
+ // at *least* 1 byte as code value, and 1 byte as 'fixDNGBug16' boolean
+ assert(bs.getPosition() >= 18);
+
+ // FIXME: BitPumpJPEG timeouts
+ rawspeed::PUMP bits(bs);
+
+ while (true)
+ ht.decode<decltype(bits), FULLDECODE>(bits);
+ } catch (rawspeed::RawspeedException&) {
+ return 0;
+ }
+
+ __builtin_unreachable();
+}
+
+// for i in $(seq -w 0 64); do dd if=/dev/urandom bs=1024 count=1024 of=$i; done
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/KodakDecompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/KodakDecompressor.cpp
new file mode 100644
index 000000000..957632ed9
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/KodakDecompressor.cpp
@@ -0,0 +1,59 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/KodakDecompressor.h" // for SonyArw1Decompre...
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ const bool uncorrectedRawValues = bs.getU32();
+
+ rawspeed::KodakDecompressor k(mRaw, bs.getStream(bs.getRemainSize()),
+ uncorrectedRawValues);
+
+ mRaw->createData();
+
+ k.decompress();
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/LJpegDecompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/LJpegDecompressor.cpp
new file mode 100644
index 000000000..aa070a7ba
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/LJpegDecompressor.cpp
@@ -0,0 +1,61 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/LJpegDecompressor.h" // for LJpegDecompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianne...
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ const auto offsetX = bs.getU32();
+ const auto offsetY = bs.getU32();
+ const auto width = bs.getU32();
+ const auto height = bs.getU32();
+ const auto fixDng16Bug = bs.getU32();
+
+ rawspeed::LJpegDecompressor j(bs, mRaw);
+ mRaw->createData();
+ j.decode(offsetX, offsetY, width, height, fixDng16Bug);
+
+ // we can not check that all the image was initialized, because normally
+ // LJpegDecompressor decodes just some one tile/slice.
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/NikonDecompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/NikonDecompressor.cpp
new file mode 100644
index 000000000..9ddd4fec2
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/NikonDecompressor.cpp
@@ -0,0 +1,60 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/NikonDecompressor.h" // for NikonDecompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianne...
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ const auto bitsPS = bs.get<rawspeed::uint32>();
+ const auto uncorrectedRawValues = bs.get<rawspeed::uint32>();
+ const auto medataLength = bs.get<rawspeed::uint32>();
+ rawspeed::ByteStream metaData = bs.getStream(medataLength);
+ rawspeed::ByteStream rawData = bs.getStream(bs.getRemainSize());
+
+ rawspeed::NikonDecompressor n(mRaw, bitsPS);
+ mRaw->createData();
+ n.decompress(metaData, rawData, uncorrectedRawValues);
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/OlympusDecompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/OlympusDecompressor.cpp
new file mode 100644
index 000000000..4dde0b0eb
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/OlympusDecompressor.cpp
@@ -0,0 +1,56 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/OlympusDecompressor.h" // for OlympusDecompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ rawspeed::OlympusDecompressor o(mRaw);
+
+ mRaw->createData();
+
+ o.decompress(bs.getStream(bs.getRemainSize()));
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/PanasonicDecompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/PanasonicDecompressor.cpp
new file mode 100644
index 000000000..f3de18795
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/PanasonicDecompressor.cpp
@@ -0,0 +1,59 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/PanasonicDecompressor.h" // for PanasonicDecompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianne...
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ const auto zero_is_not_bad = bs.get<rawspeed::uint32>();
+ const auto load_flags = bs.get<rawspeed::uint32>();
+ rawspeed::ByteStream rawData = bs.getStream(bs.getRemainSize());
+
+ rawspeed::PanasonicDecompressor p(mRaw, rawData, zero_is_not_bad,
+ load_flags);
+ mRaw->createData();
+ p.decompress();
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/PentaxDecompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/PentaxDecompressor.cpp
new file mode 100644
index 000000000..0802c46d8
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/PentaxDecompressor.cpp
@@ -0,0 +1,66 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/PentaxDecompressor.h" // for PentaxDecompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianne...
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ rawspeed::ByteStream* metaData = nullptr;
+ rawspeed::ByteStream metaDataStream;
+
+ const bool haveMetadata = bs.get<rawspeed::uint32>();
+ if (haveMetadata) {
+ const auto medataLength = bs.get<rawspeed::uint32>();
+ metaDataStream = bs.getStream(medataLength);
+ metaData = &metaDataStream;
+ }
+
+ rawspeed::ByteStream rawData = bs.getStream(bs.getRemainSize());
+
+ rawspeed::PentaxDecompressor p(mRaw, metaData);
+ mRaw->createData();
+ p.decompress(rawData);
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV0Decompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV0Decompressor.cpp
new file mode 100644
index 000000000..532870bcd
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV0Decompressor.cpp
@@ -0,0 +1,58 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/SamsungV0Decompressor.h" // for SamsungV0Decompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianne...
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ const auto bsoLength = bs.get<rawspeed::uint32>();
+ rawspeed::ByteStream bso = bs.getStream(bsoLength);
+ rawspeed::ByteStream bsr = bs.getStream(bs.getRemainSize());
+
+ rawspeed::SamsungV0Decompressor p(mRaw, bso, bsr);
+ mRaw->createData();
+ p.decompress();
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV1Decompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV1Decompressor.cpp
new file mode 100644
index 000000000..59fc06eff
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV1Decompressor.cpp
@@ -0,0 +1,57 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/SamsungV1Decompressor.h" // for SamsungV1Decompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianne...
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ const auto bit = bs.get<rawspeed::uint32>();
+ rawspeed::ByteStream rawData = bs.getStream(bs.getRemainSize());
+
+ rawspeed::SamsungV1Decompressor p(mRaw, &rawData, bit);
+ mRaw->createData();
+ p.decompress();
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV2Decompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV2Decompressor.cpp
new file mode 100644
index 000000000..1687bcd72
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/SamsungV2Decompressor.cpp
@@ -0,0 +1,57 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/SamsungV2Decompressor.h" // for SamsungV2Decompressor
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianne...
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ const auto bit = bs.get<rawspeed::uint32>();
+ rawspeed::ByteStream rawData = bs.getStream(bs.getRemainSize());
+
+ rawspeed::SamsungV2Decompressor p(mRaw, rawData, bit);
+ mRaw->createData();
+ p.decompress();
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/SonyArw1Decompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/SonyArw1Decompressor.cpp
new file mode 100644
index 000000000..0b711796d
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/SonyArw1Decompressor.cpp
@@ -0,0 +1,56 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/SonyArw1Decompressor.h" // for SonyArw1Decompre...
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ rawspeed::SonyArw1Decompressor a(mRaw);
+
+ mRaw->createData();
+
+ a.decompress(bs.getStream(bs.getRemainSize()));
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/decompressors/SonyArw2Decompressor.cpp b/src/external/rawspeed/fuzz/librawspeed/decompressors/SonyArw2Decompressor.cpp
new file mode 100644
index 000000000..a1f9909ce
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/decompressors/SonyArw2Decompressor.cpp
@@ -0,0 +1,56 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/SonyArw2Decompressor.h" // for SonyArw1Decompre...
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "fuzz/Common.h" // for CreateRawImage
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ try {
+ const rawspeed::Buffer b(Data, Size);
+ const rawspeed::DataBuffer db(b, rawspeed::Endianness::little);
+ rawspeed::ByteStream bs(db);
+
+ rawspeed::RawImage mRaw(CreateRawImage(&bs));
+
+ rawspeed::SonyArw2Decompressor a(mRaw, bs.getStream(bs.getRemainSize()));
+
+ mRaw->createData();
+
+ a.decompress();
+
+ mRaw->checkMemIsInitialized();
+ } catch (rawspeed::RawspeedException&) {
+ // Exceptions are good, crashes are bad.
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/fuzz/CMakeLists.txt b/src/external/rawspeed/fuzz/librawspeed/fuzz/CMakeLists.txt
new file mode 100644
index 000000000..a6a801c21
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/fuzz/CMakeLists.txt
@@ -0,0 +1,9 @@
+FILE(GLOB RAWSPEED_FUZZ_SOURCES
+ "Common.cpp"
+ "Common.h"
+ "RawSpeed.cpp"
+)
+
+target_sources(rawspeed_fuzz PRIVATE
+ ${RAWSPEED_FUZZ_SOURCES}
+)
diff --git a/src/external/rawspeed/fuzz/librawspeed/fuzz/Common.cpp b/src/external/rawspeed/fuzz/librawspeed/fuzz/Common.cpp
new file mode 100644
index 000000000..e98cc6c2f
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/fuzz/Common.cpp
@@ -0,0 +1,77 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "fuzz/Common.h" // for CreateRawImage
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage
+#include "common/RawspeedException.h" // for RawspeedException
+#include "io/ByteStream.h" // for ByteStream
+#include "metadata/ColorFilterArray.h" // for ColorFilterArray
+#include <limits> // for numeric_limits
+
+rawspeed::RawImage CreateRawImage(rawspeed::ByteStream* bs) {
+ assert(bs);
+
+ const rawspeed::uint32 width = bs->getU32();
+ const rawspeed::uint32 height = bs->getU32();
+ const rawspeed::uint32 type = bs->getU32();
+ const rawspeed::uint32 cpp = bs->getU32();
+ const rawspeed::uint32 isCFA = bs->getU32();
+
+ if (type != rawspeed::TYPE_USHORT16 && type != rawspeed::TYPE_FLOAT32)
+ ThrowRSE("Unknown image type: %u", type);
+
+ rawspeed::RawImage mRaw(
+ rawspeed::RawImage::create(rawspeed::RawImageType(type)));
+
+ mRaw->dim = rawspeed::iPoint2D(width, height);
+ mRaw->setCpp(cpp);
+ mRaw->isCFA = isCFA;
+
+ return mRaw;
+};
+
+rawspeed::ColorFilterArray CreateCFA(rawspeed::ByteStream* bs) {
+ assert(bs);
+
+ const rawspeed::uint32 cfaWidth = bs->getU32();
+ const rawspeed::uint32 cfaHeight = bs->getU32();
+
+ rawspeed::ColorFilterArray cfa;
+
+ if (cfaHeight &&
+ cfaWidth > std::numeric_limits<decltype(cfaWidth)>::max() / cfaHeight)
+ ThrowIOE("Integer overflow when calculating CFA area");
+ bs->check(cfaWidth * cfaHeight, 4);
+
+ cfa.setSize(rawspeed::iPoint2D(cfaWidth, cfaHeight));
+
+ for (auto x = 0U; x < cfaWidth; x++) {
+ for (auto y = 0U; y < cfaHeight; y++) {
+ const rawspeed::uint32 color = bs->getU32();
+ if (color >= static_cast<rawspeed::uint32>(rawspeed::CFA_END))
+ ThrowRSE("Unknown color: %u", color);
+
+ cfa.setColorAt(rawspeed::iPoint2D(x, y), rawspeed::CFAColor(color));
+ }
+ }
+
+ return cfa;
+};
diff --git a/src/external/rawspeed/fuzz/librawspeed/fuzz/Common.h b/src/external/rawspeed/fuzz/librawspeed/fuzz/Common.h
new file mode 100644
index 000000000..665ca7124
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/fuzz/Common.h
@@ -0,0 +1,26 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/RawImage.h" // for RawImage
+#include "io/ByteStream.h" // for ByteStream
+#include "metadata/ColorFilterArray.h" // for ColorFilterArray
+
+rawspeed::RawImage CreateRawImage(rawspeed::ByteStream* bs);
+rawspeed::ColorFilterArray CreateCFA(rawspeed::ByteStream* bs);
diff --git a/src/external/rawspeed/fuzz/librawspeed/fuzz/RawSpeed.cpp b/src/external/rawspeed/fuzz/librawspeed/fuzz/RawSpeed.cpp
new file mode 100644
index 000000000..49f3bd649
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/fuzz/RawSpeed.cpp
@@ -0,0 +1,27 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2016-2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Common.h" // IWYU pragma: keep
+
+// define this function, it is only declared in rawspeed:
+// for fuzzing, do not want any threading.
+extern "C" int __attribute__((const)) rawspeed_get_number_of_processor_cores() {
+ return 1;
+}
diff --git a/src/external/rawspeed/fuzz/librawspeed/parsers/CMakeLists.txt b/src/external/rawspeed/fuzz/librawspeed/parsers/CMakeLists.txt
new file mode 100644
index 000000000..a4461dadb
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/parsers/CMakeLists.txt
@@ -0,0 +1,31 @@
+add_custom_target(ParserFuzzers ALL)
+add_dependencies(fuzzers ParserFuzzers)
+
+function(add_parser_fuzzer parser variant boolvar boolvar2)
+ set(fuzzer "${parser}Fuzzer${variant}")
+ add_executable(${fuzzer} main.cpp)
+ target_compile_definitions(${fuzzer}
+ PRIVATE
+ -DPARSER=${parser}
+ -DGETDECODER=${boolvar}
+ -DDECODE=${boolvar2}
+ )
+
+ add_fuzz_target(${fuzzer})
+
+ add_dependencies(ParserFuzzers ${fuzzer})
+endfunction()
+
+set(PARSERS
+ "Ciff"
+ "Fiff"
+ "Raw"
+ "Tiff"
+)
+
+foreach(parser IN LISTS PARSERS)
+ set(parser "${parser}Parser")
+ # add_parser_fuzzer(${parser} "" false false)
+ add_parser_fuzzer(${parser} "-GetDecoder" true false)
+ add_parser_fuzzer(${parser} "-GetDecoder-Decode" true true)
+endforeach()
diff --git a/src/external/rawspeed/fuzz/librawspeed/parsers/main.cpp b/src/external/rawspeed/fuzz/librawspeed/parsers/main.cpp
new file mode 100644
index 000000000..879581e55
--- /dev/null
+++ b/src/external/rawspeed/fuzz/librawspeed/parsers/main.cpp
@@ -0,0 +1,99 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifndef PARSER
+#error PARSER must be defined
+#endif
+
+#ifndef GETDECODER
+#error GETDECODER must be defined as bool
+#endif
+
+#ifndef DECODE
+#error DECODE must be defined as bool
+#endif
+
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/IOException.h" // for IOException
+#include "parsers/CiffParser.h" // IWYU pragma: keep
+#include "parsers/FiffParser.h" // IWYU pragma: keep
+#include "parsers/RawParser.h" // IWYU pragma: keep
+#include "parsers/RawParserException.h" // for RawParserException
+#include "parsers/TiffParser.h" // IWYU pragma: keep
+#include <cassert> // for assert
+#include <cstdint> // for uint8_t
+#include <cstdio> // for size_t
+
+#if GETDECODER
+#include "decoders/RawDecoder.h" // IWYU pragma: keep
+#include "decoders/RawDecoderException.h" // for RawDecoderException, ThrowRDE
+#if DECODE
+#include "common/RawspeedException.h" // for RawspeedException
+#include "metadata/CameraMetaData.h" // for CameraMetaData
+#include <memory> // for unique_ptr
+#endif
+#endif
+
+#if GETDECODER && DECODE
+static const rawspeed::CameraMetaData metadata{};
+#endif
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ assert(Data);
+
+ const rawspeed::Buffer buffer(Data, Size);
+
+ try {
+ rawspeed::PARSER parser(&buffer);
+
+#if GETDECODER
+#if DECODE
+ auto decoder =
+#endif
+ parser.getDecoder();
+#endif
+
+#if DECODE
+ decoder->applyCrop = false;
+ decoder->interpolateBadPixels = false;
+ decoder->failOnUnknown = false;
+ // decoder->checkSupport(&metadata);
+
+ decoder->decodeRaw();
+ decoder->decodeMetaData(&metadata);
+#endif
+ } catch (rawspeed::RawParserException&) {
+ return 0;
+#if GETDECODER
+ } catch (rawspeed::RawDecoderException&) {
+ return 0;
+#endif
+ } catch (rawspeed::IOException&) {
+ return 0;
+#if DECODE
+ } catch (rawspeed::RawspeedException&) {
+ return 0;
+#endif
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/fuzz/rawspeed/CMakeLists.txt b/src/external/rawspeed/fuzz/rawspeed/CMakeLists.txt
new file mode 100644
index 000000000..725d4da88
--- /dev/null
+++ b/src/external/rawspeed/fuzz/rawspeed/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_executable(RawSpeedFuzzer main.cpp)
+
+add_fuzz_target(RawSpeedFuzzer)
+
+add_dependencies(fuzzers RawSpeedFuzzer)
diff --git a/src/external/rawspeed/fuzz/rawspeed/main.cpp b/src/external/rawspeed/fuzz/rawspeed/main.cpp
new file mode 100644
index 000000000..76a3e2243
--- /dev/null
+++ b/src/external/rawspeed/fuzz/rawspeed/main.cpp
@@ -0,0 +1,50 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "RawSpeed-API.h" // for RawDecoder, RawParser, Buffer, CameraMetaData
+#include <cstddef> // for size_t
+#include <cstdint> // for uint8_t
+#include <memory> // for unique_ptr
+
+static const rawspeed::CameraMetaData metadata{};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ // static const CameraMetaData metadata(CMAKE_SOURCE_DIR "/data/cameras.xml");
+
+ try {
+ const rawspeed::Buffer buffer(Data, Size);
+ rawspeed::RawParser parser(&buffer);
+ auto decoder = parser.getDecoder(/*&metadata*/);
+
+ decoder->applyCrop = false;
+ decoder->interpolateBadPixels = false;
+ decoder->failOnUnknown = false;
+ // decoder->checkSupport(&metadata);
+
+ decoder->decodeRaw();
+ decoder->decodeMetaData(&metadata);
+ } catch (rawspeed::RawspeedException&) {
+ return 0;
+ }
+
+ return 0;
+}
diff --git a/src/external/rawspeed/src/CMakeLists.txt b/src/external/rawspeed/src/CMakeLists.txt
new file mode 100644
index 000000000..a57f01b00
--- /dev/null
+++ b/src/external/rawspeed/src/CMakeLists.txt
@@ -0,0 +1,17 @@
+add_library(rawspeed STATIC)
+
+include(src-dependencies)
+
+include(memory-align-alloc)
+include(thread-local)
+
+CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/rawspeedconfig.h")
+target_include_directories(rawspeed PUBLIC "${CMAKE_CURRENT_BINARY_DIR}")
+
+target_include_directories(rawspeed SYSTEM PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/external/")
+
+add_subdirectory(librawspeed)
+
+if(BUILD_TOOLS)
+ add_subdirectory(utilities)
+endif()
diff --git a/src/external/rawspeed/src/config.h.in b/src/external/rawspeed/src/config.h.in
new file mode 100644
index 000000000..05c8c6573
--- /dev/null
+++ b/src/external/rawspeed/src/config.h.in
@@ -0,0 +1,93 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2016-2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#if defined(__SSE2__)
+#cmakedefine WITH_SSE2
+#else
+/* #undef WITH_SSE2 */
+#endif
+
+#cmakedefine HAVE_PUGIXML
+
+#cmakedefine HAVE_PTHREAD
+
+#cmakedefine HAVE_PUGIXML
+
+#cmakedefine HAVE_ZLIB
+
+#cmakedefine HAVE_JPEG
+#cmakedefine HAVE_JPEG_MEM_SRC
+
+#cmakedefine HAVE_CXX_THREAD_LOCAL
+#cmakedefine HAVE_GCC_THREAD_LOCAL
+
+// which aligned memory allocation function is avaliable, if any?
+// only the first one found will be enabled
+#cmakedefine HAVE_POSIX_MEMALIGN
+#cmakedefine HAVE_ALIGNED_ALLOC
+#cmakedefine HAVE_MM_MALLOC
+#cmakedefine HAVE_ALIGNED_MALLOC
+
+#cmakedefine RAWSPEED_STANDALONE_BUILD
+#ifdef RAWSPEED_STANDALONE_BUILD
+#define CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@"
+#else
+// If rawspeed is being built as part of some larger build, we can not retain
+// the CMAKE_SOURCE_DIR, because that would affect the reproducible builds.
+#endif
+
+// see http://clang.llvm.org/docs/LanguageExtensions.html
+#ifndef __has_feature // Optional of course.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+#ifndef __has_extension
+#define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
+#endif
+
+// see https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+#include <sanitizer/asan_interface.h> // IWYU pragma: export
+#include <type_traits> // for remove_cv
+template <typename T> struct remove_all_const : std::remove_const<T> {};
+template <typename T> struct remove_all_const<T *> {
+ using type = typename remove_all_const<T>::type *;
+};
+template <typename T> struct remove_all_const<T *const> {
+ using type = typename remove_all_const<T>::type *;
+};
+#define ASAN_REGION_IS_POISONED(addr, size) \
+ __asan_region_is_poisoned( \
+ const_cast<remove_all_const<decltype(addr)>::type>(addr), /* NOLINT */ \
+ (size))
+#else
+#define ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
+#define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
+#define ASAN_REGION_IS_POISONED(addr, size) (0)
+#endif
+
+#if __has_feature(memory_sanitizer) || defined(__SANITIZE_MEMORY__)
+#include <sanitizer/msan_interface.h> // IWYU pragma: export
+#define MSAN_MEM_IS_INITIALIZED(addr, size) \
+ __msan_check_mem_is_initialized(addr, size)
+#else
+#define MSAN_MEM_IS_INITIALIZED(addr, size) (0)
+#endif
diff --git a/src/external/rawspeed/src/external/ThreadSafetyAnalysis.h b/src/external/rawspeed/src/external/ThreadSafetyAnalysis.h
new file mode 100644
index 000000000..2a0ae2681
--- /dev/null
+++ b/src/external/rawspeed/src/external/ThreadSafetyAnalysis.h
@@ -0,0 +1,128 @@
+#pragma once
+
+// see https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#mutexheader
+
+#ifndef THREAD_SAFETY_ANALYSIS_MUTEX_H
+#define THREAD_SAFETY_ANALYSIS_MUTEX_H
+
+// Enable thread safety attributes only with clang.
+// The attributes can be safely erased when compiling with other compilers.
+#if defined(__clang__) && (!defined(SWIG))
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
+#endif
+
+#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
+#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+#define ACQUIRED_BEFORE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+#define ACQUIRED_AFTER(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define REQUIRES(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
+
+#define REQUIRES_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
+
+#define ACQUIRE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
+
+#define ACQUIRE_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
+
+#define RELEASE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
+
+#define RELEASE_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
+
+#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
+
+#define ASSERT_SHARED_CAPABILITY(x) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
+
+#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+#define NO_THREAD_SAFETY_ANALYSIS \
+ THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
+
+#ifdef USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES
+// The original version of thread safety analysis the following attribute
+// definitions. These use a lock-based terminology. They are still in use
+// by existing thread safety code, and will continue to be supported.
+
+// Deprecated.
+#define PT_GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_var)
+
+// Deprecated.
+#define GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(guarded_var)
+
+// Replaced by REQUIRES
+#define EXCLUSIVE_LOCKS_REQUIRED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
+
+// Replaced by REQUIRES_SHARED
+#define SHARED_LOCKS_REQUIRED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
+
+// Replaced by CAPABILITY
+#define LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(lockable)
+
+// Replaced by SCOPED_CAPABILITY
+#define SCOPED_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+// Replaced by ACQUIRE
+#define EXCLUSIVE_LOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
+
+// Replaced by ACQUIRE_SHARED
+#define SHARED_LOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
+
+// Replaced by RELEASE and RELEASE_SHARED
+#define UNLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
+
+// Replaced by TRY_ACQUIRE
+#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
+
+// Replaced by TRY_ACQUIRE_SHARED
+#define SHARED_TRYLOCK_FUNCTION(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
+
+// Replaced by ASSERT_CAPABILITY
+#define ASSERT_EXCLUSIVE_LOCK(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
+
+// Replaced by ASSERT_SHARED_CAPABILITY
+#define ASSERT_SHARED_LOCK(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
+
+// Replaced by EXCLUDE_CAPABILITY.
+#define LOCKS_EXCLUDED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+// Replaced by RETURN_CAPABILITY
+#define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+#endif // USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES
+
+#endif // THREAD_SAFETY_ANALYSIS_MUTEX_H
diff --git a/src/external/rawspeed/src/librawspeed/CMakeLists.txt b/src/external/rawspeed/src/librawspeed/CMakeLists.txt
new file mode 100644
index 000000000..e422fde06
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_subdirectory(common)
+add_subdirectory(metadata)
+add_subdirectory(io)
+add_subdirectory(tiff)
+add_subdirectory(parsers)
+add_subdirectory(decompressors)
+add_subdirectory(interpolators)
+add_subdirectory(decoders)
+
+target_include_directories(rawspeed PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
diff --git a/src/external/rawspeed/src/librawspeed/README.md b/src/external/rawspeed/src/librawspeed/README.md
new file mode 100644
index 000000000..e23903f50
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/README.md
@@ -0,0 +1,243 @@
+# RawSpeed Developer Information
+
+## Include files
+
+All needed headers are available by including “RawSpeed-API.h”. You must have the pthread library and headers installed and available.
+
+RawSpeed uses pthreads, libjpeg ~~and libxml2~~, which is the only external requirements beside standard C/C++ libraries. As of v2, libxml is no longer required.
+
+You must implement a single function: “int rawspeed_get_number_of_processor_cores();”, which should return the maximum number of threads that should be used for decoding, if multithreaded decoding is possible.
+
+Everything is encapsulated on a “rawspeed” namespace. To avoid clutter the examples below assume you have a “using namespace rawspeed;” before using the code.
+
+## The Camera Definition file
+
+This file describes basic information about different cameras, so new cameras can be supported without code changes. See the separate documentation on the [Camera Definition File](/data/README.md).
+
+The camera definitions are read into the CameraMetaData object, which you can retain for re-use later. You initialize this data by doing
+
+```cpp
+static CameraMetaData *metadata = nullptr;
+if (nullptr == metadata)
+{
+ try {
+ metadata = new CameraMetaData("path_to_cameras.xml");
+ } catch (CameraMetadataException &e) {
+ // Reading metadata failed. e.what() will contain error message.
+ }
+}
+```
+
+The memory impact of this object is quite small, so you don’t have to free it every time. You can however delete and re-create it, if you know the metadata file has been updated.
+
+You can disable specific cameras in the xml file, or if you would want to do it in code, you can use:
+
+```cpp
+ // Disable specific camera
+ metadata.disableCamera("Canon", "Canon EOS 100D")
+
+ // Disable all cameras from maker:
+ metadata.disableCamera("Fuji")
+```
+
+## Using RawSpeed
+
+You need to have the file data in a Buffer object. This can either be created by supplying the file content in memory using Buffer(buffer_pointer, size_of_buffer), or use a “FileReader” object to read the content of a file, like this:
+
+```cpp
+FileReader reader(filename);
+Buffer* map = nullptr;
+try {
+ map = reader.readFile();
+} catch (FileIOException &e) {
+ // Handle errors
+}
+```
+
+The next step is to start decoding. The first step is to get a decoder:
+
+```cpp
+RawParser parser(map);
+RawDecoder *decoder = parser.getDecoder();
+```
+
+This will do basic parsing of the file, and return a decoder that is capable of decoding the image. If no decoder can be found or another error occurs a “RawDecoderException” object will be thrown. The next step is to determine whether the specific camera is supported:
+
+```cpp
+decoder->failOnUnknown = false;
+decoder->checkSupport(metadata);
+```
+
+The “failOnUnknown” property will indicate whether the decoder should refuse to decode unknown cameras. Otherwise RawSpeed will only refuse to decode the image, if it is confirmed that the camera type cannot be decoded correctly. If the image isn’t supported a “RawDecoderException” will be thrown.
+
+Reaching this point should be very fast in terms of CPU time, so the support check is very quick, if file data is quickly available. Next we decode the image:
+
+```cpp
+decoder->decodeRaw();
+decoder->decodeMetaData(metadata);
+RawImage raw = decoder->mRaw;
+```
+
+This will decode the image, and apply metadata information. The RawImage is at this point completely untouched Raw data, however the image has been cropped to the active image area in decodeMetaData. Error reporting is: If a fatal error occurs a RawDecoderException is thrown.
+
+Non-fatal errors are pushed into a "vector" array in the decoder object called "errors". With these types of errors, there WILL be a raw image available, but it will likely contain junk sections in undecodable parts. However, as much as it was possible to decode will be available. So treat these messages as warnings.
+
+Another thing to note here is that the RawImage object is automatically refcounted, so you can pass the object around without worrying about the image being freed before all instances are out of scope. Do however keep this in mind if you pass the pointer to image data to another part of your application.
+
+```cpp
+raw->scaleBlackWhite();
+```
+
+This will apply the black/white scaling to the image, so the data is normalized into the 0->65535 range no matter what the sensor adjustment is (for 16 bit images). This function does no throw any errors. Now you can retrieve information about the image:
+
+```cpp
+int components_per_pixel = raw->getCpp();
+RawImageType type = raw->getDataType();
+bool is_cfa = r->isCFA;
+```
+
+Components per pixel indicates how many components are present per pixel. Common values are 1 on CFA images, and 3, found in some DNG images for instance. Do note, you cannot assume that an images is CFA just because it is 1 cpp - greyscale dng images from things like scanners can be saved like that.
+
+The RawImageType can be TYPE_USHORT16 (most common) which indicates unsigned 16 bit data or TYPE_FLOAT32 (found in some DNGs)
+
+The isCFA indicates whether the image has all components per pixel, or if it was taken with a colorfilter array. This usually corresponds to the number of components per pixel (1 on CFA, 3 on non-CFA).
+
+The ColorfilterArray contains information about the placement of colors in the CFA:
+
+```cpp
+if (true == is_cfa) {
+ ColorFilterArray cfa = raw->cfa;
+ int dcraw_filter = cfa.getDcrawFilter();
+ int cfa_width = cfa.size.x;
+ int cfa_height = cfa.size.y;
+ CFAColor c = cfa.getColorAt(0,0);
+}
+```
+
+To get this information as a dcraw compatible filter information, you can use getDcrawFilter() function.
+
+You can also use getColorAt(x, y) to get a single color information. ~~Note that unlike dcraw, RawSpeed only supports 2×2 patterns, so you can reuse this information.~~ CFAColor can be CFA_RED, CFA_GREEN, CFA_BLUE for instance.
+
+Finally information about the image itself:
+
+```cpp
+unsigned char* data = raw->getData(0,0);
+int width = raw->dim.x;
+int height = raw->dim.y;
+int pitch_in_bytes = raw->pitch;
+```
+
+The getData(x, y) function will give you a pointer to the Raw data at pixel x, y. This is the coordinate after crop, so you can start copying data right away. Don’t use this function on every pixel, but instead increment the pointer yourself. The width and height gives you the size of the image in pixels – again after crop.
+
+Pitch is the number of bytes between lines, since this is usually NOT width * components_per_pixel * bytes_per_component. So in this instance, to calculate a pointer at line y, use &data[y * raw->pitch] for instance.
+
+Finally to clean up, use:
+
+```cpp
+delete map;
+delete decoder;
+```
+
+Actually the map and decoder can be deallocated once the metadata has been decoded. The RawImage will automatically be deallocated when it goes out of scope and the decoder has been deallocated. After that all data pointers that have been retrieved will no longer be usable.
+
+## Tips & Tricks
+
+You will most likely find that a relatively long time is spent actually reading the file. The biggest trick to speeding up raw reading is to have some sort of prefetching going on while the file is being decoded. This is the main reason why RawSpeed decodes from memory, and doesn’t use direct file reads while decoding.
+
+The simplest solution is to start a thread that simply reads the file, and rely on the system cache to cache the data. This is fairly simple and works in 99% of all cases. So if you are doing batch processing simply start a process reading the next file, when the current image starts decoding. This will ensure that your file is read linearly, which gives the highest possible throughput.
+
+A more complex option is to read the file to a memory portion, which is then given to RawSpeed to decode. This might be a few milliseconds faster in the best case, but I have found no practical difference between that and simply relying on system caching.
+
+You might want to try out memory mapped files. However this approach has in practical tests shown to be just as fast in best cases (when file is cached), or slower (uncached files).
+
+## Bad pixel elimination
+
+A few cameras will mark bad pixels within their RAW files in various ways. For the camera we know how to this will be picked up by RawSpeed. By default these pixels are eliminated by 4-way interpolating to the closest valid pixels in an on-axis search from the current pixel.
+
+If you want to do bad pixel interpolation yourself you can set:
+
+```cpp
+RawDecoder.interpolateBadPixels = false;
+```
+
+Before calling the decoder. This will disable the automatic interpolation of bad pixels. You can retrieve the bad pixels by using:
+
+```cpp
+std::vector<uint32> RawImage->mBadPixelPositions;
+```
+
+This is a vector that contains the positions of the detected bad pixels in the image. The positions are stored as x | (y << 16), so maximum pixel position is 65535, which also corresponds with the limit of the image sizes within RawSpeed. you can loop through all bad pixels with a loop like this:
+
+```cpp
+for (vector<uint32>::iterator i=mBadPixelPositions.begin(); i != mBadPixelPositions.end(); i++) {
+ uint32 pos_x = (*i)&0xffff;
+ uint32 pos_y = (*i)>>16;
+ ushort16* pix = (ushort16*)getDataUncropped(pos_x, pos_y);
+}
+```
+
+This however may not be most optimal format for you. You can also call RawImage->transferBadPixelsToMap(). This will create a bit-mask for you with all bad pixels. Each byte correspond to 8 pixels with the least significant bit for the leftmost pixel. To set position x,y this operation is used:
+
+```cpp
+RawImage->mBadPixelMap[(x >> 8) + y * mBadPixelMapPitch] |= 1 << (x & 7);
+```
+
+This enables you to quickly search through the array. If you for instance cast the array to integers you can check 32 pixels at the time.
+
+Note that all positions are uncropped image positions. Also note that if you keep the interpolation enabled you can still retrieve the mBadPixelMap, but the mBadPixelPositions will be cleared.
+
+## Updating Camera Support
+
+If you implement an autoupdate feature, you simply update “cameras.xml” and delete and re-create the CameraMetaData object.
+
+There might of course be some specific cameras that require code-changes to work properly. However, there is a versioning check inplace, whereby cameras requirering a specific code version to decode properly will be marked as such.
+
+That means you should safely be able to update cameras.xml to a newer version, and cameras requiring a code update will then simply refuse to open.
+
+
+## Format Specific Notes
+
+### Canon sRaw/mRaw
+Canon reduced resolution Raws (mRaw/sRaw) are returned as RGB with 3 component per pixel without whitebalance compensation, so color balance should match ordinary CR2 images. The subsampled color components are linearly interpolated.
+
+This is even more complicated by the fact that Canon has changed the way they store the sraw whitebalance values. This means that on newer cameras, you might have to specify "invert_sraw_wb" as a hint to properly decode the whitebalance on these casmeras. To see examples of this, search cameras.xml for "invert_sraw_wb".
+
+### Sigma Foveon Support
+
+Sigma Foveon (x3f-based) images are not supported. If you want them to be supported, help welcomed :)
+
+### Fuji Rotated Support
+
+By default RawSpeed delivers Fuji SuperCCD images as 45 degree rotated images.
+
+RawSpeed does however use two camera hints to do this. The first hint is "fuji_rotate": When this is specified in cameras.xml, the images are rotated.
+
+To check if an image has been rotated, check RawImage->fujiWidth after calling RawDecoder->decodeMetaData(...) If it is > 0, then the image has been rotated, and you can use this value to calculate the un-rotated image size. See [here](https://rawstudio.org/svn/rawstudio/trunk/plugins/fuji-rotate/fuji-rotate.c) for an example on how to rotate the image back after de-mosaic.
+
+If you do NOT want your images to be delivered rotated, you can disable it when decoding.
+```cpp
+RawDecoder->fujiRotate = false;
+```
+Do however note the CFA colors are still referring to the rotated color positions.
+
+
+## Other options
+
+### RawDecoder -> uncorrectedRawValues
+If you enable this on the decoder before calling RawDecoder->decodeRaw(), you will get complely unscaled values. Some cameras have a "compressed" mode, where a non-linear compression curve is applied to the image data. If you enable this parameter the compression curve will not be applied to the image. Currently there is no way to retrieve the compression curve, so this option is only useful for diagnostics.
+
+
+### RawImage.mDitherScale
+This option will determine whether dither is applied when values are scaled to 16 bits. Dither is applied as a random value between "+-scalefactor/2". This will make it so that images with less number of bits/pixel doesn't have a big tendency for posterization, since values close to eachother will be spaced out a bit.
+
+Another way of putting it, is that if your camera saves 12 bit per pixel, when RawSpeed upscales this to 16 bits, the 4 "new" bits will be random instead of always the same value.
+
+## Memory Usage
+
+RawSpeed will need:
+
+* Size of Raw File.
+* Image width * image height * 2 for ordinary Raw images with 16 bit output.
+* Image width * image height * 4 for float point images with float point output .
+* Image width * image height * 6 for ordinary Raw images with float point output.
+* Image width * image height / 8 for images with bad pixels.
diff --git a/src/external/rawspeed/src/librawspeed/RawSpeed-API.h b/src/external/rawspeed/src/librawspeed/RawSpeed-API.h
new file mode 100644
index 000000000..0ac4418e7
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/RawSpeed-API.h
@@ -0,0 +1,43 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2011 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+// IWYU pragma: begin_exports
+
+#include "rawspeedconfig.h"
+
+#include "common/Common.h"
+#include "common/Mutex.h"
+#include "common/Point.h"
+#include "common/RawImage.h"
+#include "common/RawspeedException.h"
+#include "decoders/RawDecoder.h"
+#include "io/Buffer.h"
+#include "io/Endianness.h"
+#include "io/FileReader.h"
+#include "metadata/BlackArea.h"
+#include "metadata/Camera.h"
+#include "metadata/CameraMetaData.h"
+#include "metadata/ColorFilterArray.h"
+#include "parsers/RawParser.h"
+
+// IWYU pragma: end_exports
diff --git a/src/external/rawspeed/src/librawspeed/common/CMakeLists.txt b/src/external/rawspeed/src/librawspeed/common/CMakeLists.txt
new file mode 100644
index 000000000..495e8eeb7
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/CMakeLists.txt
@@ -0,0 +1,28 @@
+FILE(GLOB SOURCES
+ "Common.cpp"
+ "Common.h"
+ "Cpuid.cpp"
+ "DngOpcodes.cpp"
+ "DngOpcodes.h"
+ "ErrorLog.cpp"
+ "ErrorLog.h"
+ "Memory.cpp"
+ "Memory.h"
+ "Mutex.h"
+ "NORangesSet.h"
+ "Point.h"
+ "Range.h"
+ "RawImage.cpp"
+ "RawImage.h"
+ "RawImageDataFloat.cpp"
+ "RawImageDataU16.cpp"
+ "RawspeedException.h"
+ "Spline.h"
+ "TableLookUp.cpp"
+ "TableLookUp.h"
+ "Threading.h"
+)
+
+target_sources(rawspeed PRIVATE
+ ${SOURCES}
+)
diff --git a/src/external/rawspeed/src/librawspeed/common/Common.cpp b/src/external/rawspeed/src/librawspeed/common/Common.cpp
new file mode 100644
index 000000000..8c8c56630
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/Common.cpp
@@ -0,0 +1,62 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Common.h"
+#include <cstdarg> // for va_end, va_list, va_start
+#include <cstdio> // for printf, vprintf
+
+// #define _DEBUG
+
+namespace rawspeed {
+
+#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(_DEBUG)
+
+void __attribute__((const))
+writeLog(DEBUG_PRIO priority, const char* format, ...) {
+ // When fuzzing, any output is really undesirable.
+}
+
+#else
+
+void writeLog(DEBUG_PRIO priority, const char* format, ...) {
+#ifndef _DEBUG
+ if (priority < DEBUG_PRIO_INFO)
+#endif // _DEBUG
+ fprintf(stdout, "%s", "RawSpeed:");
+
+ va_list args;
+ va_start(args, format);
+
+#ifndef _DEBUG
+ if (priority < DEBUG_PRIO_INFO)
+#endif // _DEBUG
+ vfprintf(stdout, format, args);
+
+ va_end(args);
+
+#ifndef _DEBUG
+ if (priority < DEBUG_PRIO_INFO)
+#endif // _DEBUG
+ fprintf(stdout, "%s", "\n");
+}
+
+#endif
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/Common.h b/src/external/rawspeed/src/librawspeed/common/Common.h
new file mode 100644
index 000000000..9af437c5b
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/Common.h
@@ -0,0 +1,211 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h"
+
+#include <cassert> // for assert
+#include <cstdint> // for uintptr_t
+#include <cstring> // for memcpy, size_t
+#include <initializer_list> // for initializer_list
+#include <string> // for string
+#include <type_traits> // for enable_if, is_pointer
+#include <vector> // for vector
+
+extern "C" int rawspeed_get_number_of_processor_cores();
+
+namespace rawspeed {
+
+using char8 = signed char;
+using uchar8 = unsigned char;
+using uint32 = unsigned int;
+using int64 = long long;
+using uint64 = unsigned long long;
+using int32 = signed int;
+using ushort16 = unsigned short;
+using short16 = signed short;
+
+enum DEBUG_PRIO {
+ DEBUG_PRIO_ERROR = 0x10,
+ DEBUG_PRIO_WARNING = 0x100,
+ DEBUG_PRIO_INFO = 0x1000,
+ DEBUG_PRIO_EXTRA = 0x10000
+};
+
+void writeLog(DEBUG_PRIO priority, const char* format, ...)
+ __attribute__((format(printf, 2, 3)));
+
+inline void copyPixels(uchar8* dest, int dstPitch, const uchar8* src,
+ int srcPitch, int rowSize, int height)
+{
+ if (height == 1 || (dstPitch == srcPitch && srcPitch == rowSize))
+ memcpy(dest, src, static_cast<size_t>(rowSize) * height);
+ else {
+ for (int y = height; y > 0; --y) {
+ memcpy(dest, src, rowSize);
+ dest += dstPitch;
+ src += srcPitch;
+ }
+ }
+}
+
+// only works for positive values and zero
+template <typename T> inline constexpr bool isPowerOfTwo(T val) {
+ return (val & (~val+1)) == val;
+}
+
+constexpr inline size_t __attribute__((const))
+roundUp(size_t value, size_t multiple) {
+ return ((multiple == 0) || (value % multiple == 0))
+ ? value
+ : value + multiple - (value % multiple);
+}
+
+constexpr inline size_t __attribute__((const))
+roundUpDivision(size_t value, size_t div) {
+ return (value != 0) ? (1 + ((value - 1) / div)) : 0;
+}
+
+template <class T>
+inline constexpr __attribute__((const)) bool
+isAligned(T value, size_t multiple,
+ typename std::enable_if<std::is_pointer<T>::value>::type* /*unused*/ =
+ nullptr) {
+ return (multiple == 0) ||
+ (reinterpret_cast<std::uintptr_t>(value) % multiple == 0);
+}
+
+template <class T>
+inline constexpr __attribute__((const)) bool isAligned(
+ T value, size_t multiple,
+ typename std::enable_if<!std::is_pointer<T>::value>::type* /*unused*/ =
+ nullptr) {
+ return (multiple == 0) ||
+ (static_cast<std::uintptr_t>(value) % multiple == 0);
+}
+
+template <typename T, typename T2>
+bool __attribute__((pure))
+isIn(const T value, const std::initializer_list<T2>& list) {
+ for (auto t : list)
+ if (t == value)
+ return true;
+ return false;
+}
+
+inline uint32 getThreadCount()
+{
+#ifndef HAVE_PTHREAD
+ return 1;
+#elif defined(WIN32)
+ return pthread_num_processors_np();
+#else
+ return rawspeed_get_number_of_processor_cores();
+#endif
+}
+
+// clampBits clamps the given int to the range 0 .. 2^n-1, with n <= 16
+inline ushort16 __attribute__((const)) clampBits(int x, uint32 n) {
+ assert(n <= 16);
+ const int tmp = (1 << n) - 1;
+ x = x < 0 ? 0 : x;
+ x = x > tmp ? tmp : x;
+ return x;
+}
+
+// Trim both leading and trailing spaces from the string
+inline std::string trimSpaces(const std::string& str)
+{
+ // Find the first character position after excluding leading blank spaces
+ size_t startpos = str.find_first_not_of(" \t");
+
+ // Find the first character position from reverse af
+ size_t endpos = str.find_last_not_of(" \t");
+
+ // if all spaces or empty return an empty string
+ if ((startpos == std::string::npos) || (endpos == std::string::npos))
+ return "";
+
+ return str.substr(startpos, endpos - startpos + 1);
+}
+
+inline std::vector<std::string> splitString(const std::string& input,
+ char c = ' ')
+{
+ std::vector<std::string> result;
+ const char* str = input.c_str();
+
+ while (true) {
+ const char* begin = str;
+
+ while (*str != c && *str != '\0')
+ str++;
+
+ if (begin != str)
+ result.emplace_back(begin, str);
+
+ const bool isNullTerminator = (*str == '\0');
+ str++;
+
+ if (isNullTerminator)
+ break;
+ }
+
+ return result;
+}
+
+enum BitOrder {
+ BitOrder_LSB, /* Memory order */
+ BitOrder_MSB, /* Input is added to stack byte by byte, and output is lifted
+ from top */
+ BitOrder_MSB16, /* Same as above, but 16 bits at the time */
+ BitOrder_MSB32, /* Same as above, but 32 bits at the time */
+};
+
+// little 'forced' loop unrolling helper tool, example:
+// unroll_loop<N>([&](int i) {
+// func(i);
+// });
+// will translate to:
+// func(0); func(1); func(2); ... func(N-1);
+
+template <typename Lambda, size_t N>
+struct unroll_loop_t {
+ inline static void repeat(const Lambda& f) {
+ unroll_loop_t<Lambda, N-1>::repeat(f);
+ f(N-1);
+ }
+};
+
+template <typename Lambda>
+struct unroll_loop_t<Lambda, 0> {
+ inline static void repeat(const Lambda& f) {
+ // this method is correctly empty.
+ // only needed as part of compile time 'manual' branch unrolling
+ }
+};
+
+template <size_t N, typename Lambda>
+inline void unroll_loop(const Lambda& f) {
+ unroll_loop_t<Lambda, N>::repeat(f);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/Cpuid.cpp b/src/external/rawspeed/src/librawspeed/common/Cpuid.cpp
new file mode 100644
index 000000000..2f468af94
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/Cpuid.cpp
@@ -0,0 +1,49 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Cpuid.h"
+
+#if defined(__i386__) || defined(__x86_64__)
+#include <cpuid.h> // for __get_cpuid, bit_SSE2
+#endif
+
+namespace rawspeed {
+
+#if defined(__i386__) || defined(__x86_64__)
+
+bool Cpuid::SSE2() {
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+
+ if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx))
+ return false;
+
+ return edx & bit_SSE2;
+}
+
+#else
+
+bool Cpuid::SSE2() { return false; }
+
+#endif
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/Cpuid.h b/src/external/rawspeed/src/librawspeed/common/Cpuid.h
new file mode 100644
index 000000000..fdce5d4f9
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/Cpuid.h
@@ -0,0 +1,30 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+namespace rawspeed {
+
+class Cpuid final {
+public:
+ static bool __attribute__((const)) SSE2();
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/DngOpcodes.cpp b/src/external/rawspeed/src/librawspeed/common/DngOpcodes.cpp
new file mode 100644
index 000000000..7f10741cf
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/DngOpcodes.cpp
@@ -0,0 +1,589 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/DngOpcodes.h"
+#include "common/Common.h" // for uint32, ushort16, clampBits
+#include "common/Mutex.h" // for MutexLocker
+#include "common/Point.h" // for iRectangle2D, iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::big
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include <algorithm> // for generate_n, fill_n
+#include <cassert> // for assert
+#include <cmath> // for pow
+#include <iterator> // for back_insert_iterator
+#include <limits> // for numeric_limits
+#include <stdexcept> // for out_of_range
+#include <tuple> // for tie, tuple
+// IWYU pragma: no_include <ext/alloc_traits.h>
+// IWYU pragma: no_include <type_traits>
+
+using std::vector;
+using std::fill_n;
+using std::make_pair;
+
+namespace rawspeed {
+
+class DngOpcodes::DngOpcode {
+public:
+ virtual ~DngOpcode() = default;
+
+ // Will be called once before processing.
+ // Can be used for preparing pre-calculated values, etc.
+ virtual void setup(const RawImage& ri) {
+ // NOP by default. child class shall override this if needed.
+ }
+
+ // Will be called for actual processing.
+ virtual void apply(const RawImage& ri) = 0;
+};
+
+// ****************************************************************************
+
+class DngOpcodes::FixBadPixelsConstant final : public DngOpcodes::DngOpcode {
+ uint32 value;
+
+public:
+ explicit FixBadPixelsConstant(const RawImage& ri, ByteStream* bs) {
+ value = bs->getU32();
+ bs->getU32(); // Bayer Phase not used
+ }
+
+ void setup(const RawImage& ri) override {
+ // These limitations are present within the DNG SDK as well.
+ if (ri->getDataType() != TYPE_USHORT16)
+ ThrowRDE("Only 16 bit images supported");
+
+ if (ri->getCpp() > 1)
+ ThrowRDE("Only 1 component images supported");
+ }
+
+ void apply(const RawImage& ri) override {
+ MutexLocker guard(&ri->mBadPixelMutex);
+ iPoint2D crop = ri->getCropOffset();
+ uint32 offset = crop.x | (crop.y << 16);
+ for (auto y = 0; y < ri->dim.y; ++y) {
+ auto* src = reinterpret_cast<ushort16*>(ri->getData(0, y));
+ for (auto x = 0; x < ri->dim.x; ++x) {
+ if (src[x] == value)
+ ri->mBadPixelPositions.push_back(offset + (y << 16 | x));
+ }
+ }
+ }
+};
+
+// ****************************************************************************
+
+class DngOpcodes::ROIOpcode : public DngOpcodes::DngOpcode {
+ iRectangle2D roi;
+
+protected:
+ explicit ROIOpcode(const RawImage& ri, ByteStream* bs, bool minusOne) {
+ const iRectangle2D fullImage =
+ minusOne ? iRectangle2D(0, 0, ri->dim.x - 1, ri->dim.y - 1)
+ : iRectangle2D(0, 0, ri->dim.x, ri->dim.y);
+
+ uint32 top = bs->getU32();
+ uint32 left = bs->getU32();
+ uint32 bottom = bs->getU32();
+ uint32 right = bs->getU32();
+
+ const iPoint2D topLeft(left, top);
+ const iPoint2D bottomRight(right, bottom);
+
+ if (!(fullImage.isPointInsideInclusive(topLeft) &&
+ fullImage.isPointInsideInclusive(bottomRight) &&
+ bottomRight >= topLeft)) {
+ ThrowRDE("Rectangle (%u, %u, %u, %u) not inside image (%u, %u, %u, %u).",
+ topLeft.x, topLeft.y, bottomRight.x, bottomRight.y,
+ fullImage.getTopLeft().x, fullImage.getTopLeft().y,
+ fullImage.getBottomRight().x, fullImage.getBottomRight().y);
+ }
+
+ roi.setTopLeft(topLeft);
+ roi.setBottomRightAbsolute(bottomRight);
+ assert(roi.isThisInside(fullImage));
+ }
+
+ const iRectangle2D& __attribute__((pure)) getRoi() const { return roi; }
+};
+
+// ****************************************************************************
+
+class DngOpcodes::DummyROIOpcode final : public ROIOpcode {
+public:
+ explicit DummyROIOpcode(const RawImage& ri, ByteStream* bs)
+ : ROIOpcode(ri, bs, true) {}
+
+ const iRectangle2D& __attribute__((pure)) getRoi() const {
+ return ROIOpcode::getRoi();
+ }
+
+ [[noreturn]] void apply(const RawImage& ri) final {
+ assert(false && "You should not be calling this.");
+ __builtin_unreachable();
+ }
+};
+
+// ****************************************************************************
+
+class DngOpcodes::FixBadPixelsList final : public DngOpcodes::DngOpcode {
+ std::vector<uint32> badPixels;
+
+public:
+ explicit FixBadPixelsList(const RawImage& ri, ByteStream* bs) {
+ const iRectangle2D fullImage(0, 0, ri->getUncroppedDim().x - 1,
+ ri->getUncroppedDim().y - 1);
+
+ bs->getU32(); // Skip phase - we don't care
+ auto badPointCount = bs->getU32();
+ auto badRectCount = bs->getU32();
+
+ // first, check that we indeed have much enough data
+ const auto origPos = bs->getPosition();
+ bs->skipBytes(badPointCount, 2 * 4);
+ bs->skipBytes(badRectCount, 4 * 4);
+ bs->setPosition(origPos);
+
+ // Read points
+ badPixels.reserve(badPixels.size() + badPointCount);
+ for (auto i = 0U; i < badPointCount; ++i) {
+ auto y = bs->getU32();
+ auto x = bs->getU32();
+
+ const iPoint2D badPoint(x, y);
+ if (!fullImage.isPointInsideInclusive(badPoint))
+ ThrowRDE("Bad point not inside image.");
+
+ badPixels.emplace_back(y << 16 | x);
+ }
+
+ // Read rects
+ for (auto i = 0U; i < badRectCount; ++i) {
+ const DummyROIOpcode dummy(ri, bs);
+
+ const iRectangle2D badRect = dummy.getRoi();
+ assert(badRect.isThisInside(fullImage));
+
+ auto area = (1 + badRect.getHeight()) * (1 + badRect.getWidth());
+ badPixels.reserve(badPixels.size() + area);
+ for (auto y = badRect.getTop(); y <= badRect.getBottom(); ++y) {
+ for (auto x = badRect.getLeft(); x <= badRect.getRight(); ++x) {
+ badPixels.emplace_back(y << 16 | x);
+ }
+ }
+ }
+ }
+
+ void apply(const RawImage& ri) override {
+ MutexLocker guard(&ri->mBadPixelMutex);
+ ri->mBadPixelPositions.insert(ri->mBadPixelPositions.begin(),
+ badPixels.begin(), badPixels.end());
+ }
+};
+
+// ****************************************************************************
+
+class DngOpcodes::TrimBounds final : public ROIOpcode {
+public:
+ explicit TrimBounds(const RawImage& ri, ByteStream* bs)
+ : ROIOpcode(ri, bs, false) {}
+
+ void apply(const RawImage& ri) override { ri->subFrame(getRoi()); }
+};
+
+// ****************************************************************************
+
+class DngOpcodes::PixelOpcode : public ROIOpcode {
+ uint32 firstPlane;
+ uint32 planes;
+ uint32 rowPitch;
+ uint32 colPitch;
+
+protected:
+ explicit PixelOpcode(const RawImage& ri, ByteStream* bs)
+ : ROIOpcode(ri, bs, false) {
+ firstPlane = bs->getU32();
+ planes = bs->getU32();
+
+ if (planes == 0 || firstPlane > ri->getCpp() || planes > ri->getCpp() ||
+ firstPlane + planes > ri->getCpp()) {
+ ThrowRDE("Bad plane params (first %u, num %u), got planes = %u",
+ firstPlane, planes, ri->getCpp());
+ }
+
+ rowPitch = bs->getU32();
+ colPitch = bs->getU32();
+
+ const iRectangle2D& ROI = getRoi();
+
+ if (rowPitch < 1 || rowPitch > static_cast<uint32>(ROI.getHeight()) ||
+ colPitch < 1 || colPitch > static_cast<uint32>(ROI.getWidth()))
+ ThrowRDE("Invalid pitch");
+ }
+
+ // traverses the current ROI and applies the operation OP to each pixel,
+ // i.e. each pixel value v is replaced by op(x, y, v), where x/y are the
+ // coordinates of the pixel value v.
+ template <typename T, typename OP> void applyOP(const RawImage& ri, OP op) {
+ int cpp = ri->getCpp();
+ const iRectangle2D& ROI = getRoi();
+ for (auto y = ROI.getTop(); y < ROI.getBottom(); y += rowPitch) {
+ auto* src = reinterpret_cast<T*>(ri->getData(0, y));
+ // Add offset, so this is always first plane
+ src += firstPlane;
+ // FIXME: is op() really supposed to recieve global image coordinates,
+ // and not [0..ROI.getHeight()-1][0..ROI.getWidth()-1] ?
+ for (auto x = ROI.getLeft(); x < ROI.getRight(); x += colPitch) {
+ for (auto p = 0U; p < planes; ++p)
+ src[x * cpp + p] = op(x, y, src[x * cpp + p]);
+ }
+ }
+ }
+};
+
+// ****************************************************************************
+
+class DngOpcodes::LookupOpcode : public PixelOpcode {
+protected:
+ vector<ushort16> lookup;
+
+ explicit LookupOpcode(const RawImage& ri, ByteStream* bs)
+ : PixelOpcode(ri, bs), lookup(65536) {}
+
+ void setup(const RawImage& ri) override {
+ PixelOpcode::setup(ri);
+ if (ri->getDataType() != TYPE_USHORT16)
+ ThrowRDE("Only 16 bit images supported");
+ }
+
+ void apply(const RawImage& ri) override {
+ applyOP<ushort16>(
+ ri, [this](uint32 x, uint32 y, ushort16 v) { return lookup[v]; });
+ }
+};
+
+// ****************************************************************************
+
+class DngOpcodes::TableMap final : public LookupOpcode {
+public:
+ explicit TableMap(const RawImage& ri, ByteStream* bs) : LookupOpcode(ri, bs) {
+ auto count = bs->getU32();
+
+ if (count == 0 || count > 65536)
+ ThrowRDE("Invalid size of lookup table");
+
+ for (auto i = 0U; i < count; ++i)
+ lookup[i] = bs->getU16();
+
+ if (count < lookup.size())
+ fill_n(&lookup[count], lookup.size() - count, lookup[count - 1]);
+ }
+};
+
+// ****************************************************************************
+
+class DngOpcodes::PolynomialMap final : public LookupOpcode {
+public:
+ explicit PolynomialMap(const RawImage& ri, ByteStream* bs)
+ : LookupOpcode(ri, bs) {
+ vector<double> polynomial;
+
+ const auto polynomial_size = bs->getU32() + 1UL;
+ bs->check(8UL * polynomial_size);
+ if (polynomial_size > 9)
+ ThrowRDE("A polynomial with more than 8 degrees not allowed");
+
+ polynomial.reserve(polynomial_size);
+ std::generate_n(std::back_inserter(polynomial), polynomial_size,
+ [&bs]() { return bs->get<double>(); });
+
+ // Create lookup
+ lookup.resize(65536);
+ for (auto i = 0U; i < lookup.size(); ++i) {
+ double val = polynomial[0];
+ for (auto j = 1U; j < polynomial.size(); ++j)
+ val += polynomial[j] * pow(i / 65536.0, j);
+ lookup[i] = (clampBits(static_cast<int>(val * 65535.5), 16));
+ }
+ }
+};
+
+// ****************************************************************************
+
+class DngOpcodes::DeltaRowOrColBase : public PixelOpcode {
+public:
+ struct SelectX {
+ static inline uint32 select(uint32 x, uint32 /*y*/) { return x; }
+ };
+
+ struct SelectY {
+ static inline uint32 select(uint32 /*x*/, uint32 y) { return y; }
+ };
+
+protected:
+ DeltaRowOrColBase(const RawImage& ri, ByteStream* bs) : PixelOpcode(ri, bs) {}
+};
+
+template <typename S>
+class DngOpcodes::DeltaRowOrCol : public DeltaRowOrColBase {
+public:
+ void setup(const RawImage& ri) override {
+ PixelOpcode::setup(ri);
+
+ // If we are working on a float image, no need to convert to int
+ if (ri->getDataType() != TYPE_USHORT16)
+ return;
+
+ deltaI.reserve(deltaF.size());
+ for (const auto f : deltaF) {
+ if (!valueIsOk(f))
+ ThrowRDE("Got float %f which is unacceptable.", f);
+ deltaI.emplace_back(static_cast<int>(f2iScale * f));
+ }
+ }
+
+protected:
+ const float f2iScale;
+ vector<float> deltaF;
+ vector<int> deltaI;
+
+ // only meaningful for ushort16 images!
+ virtual bool valueIsOk(float value) = 0;
+
+ DeltaRowOrCol(const RawImage& ri, ByteStream* bs, float f2iScale_)
+ : DeltaRowOrColBase(ri, bs), f2iScale(f2iScale_) {
+ const auto deltaF_count = bs->getU32();
+ bs->check(deltaF_count, 4);
+
+ // See PixelOpcode::applyOP(). We will access deltaF/deltaI up to (excl.)
+ // either ROI.getRight() or ROI.getBottom() index. Thus, we need to have
+ // either ROI.getRight() or ROI.getBottom() elements in there.
+ // FIXME: i guess not strictly true with pitch != 1.
+ const auto expectedSize =
+ S::select(getRoi().getRight(), getRoi().getBottom());
+ if (expectedSize != deltaF_count) {
+ ThrowRDE("Got unexpected number of elements (%u), expected %u.",
+ expectedSize, deltaF_count);
+ }
+
+ deltaF.reserve(deltaF_count);
+ std::generate_n(std::back_inserter(deltaF), deltaF_count, [&bs]() {
+ const auto F = bs->get<float>();
+ if (!std::isfinite(F))
+ ThrowRDE("Got bad float %f.", F);
+ return F;
+ });
+ }
+};
+
+// ****************************************************************************
+
+template <typename S>
+class DngOpcodes::OffsetPerRowOrCol final : public DeltaRowOrCol<S> {
+ // We have pixel value in range of [0..65535]. We apply some offset X.
+ // For this to generate a value within the same range , the offset X needs
+ // to have an absolute value of 65535. Since the offset is multiplied
+ // by f2iScale before applying, we need to divide by f2iScale here.
+ const double absLimit;
+
+ bool valueIsOk(float value) final { return std::abs(value) <= absLimit; }
+
+public:
+ explicit OffsetPerRowOrCol(const RawImage& ri, ByteStream* bs)
+ : DeltaRowOrCol<S>(ri, bs, 65535.0F),
+ absLimit(double(std::numeric_limits<ushort16>::max()) /
+ this->f2iScale) {}
+
+ void apply(const RawImage& ri) override {
+ if (ri->getDataType() == TYPE_USHORT16) {
+ this->template applyOP<ushort16>(
+ ri, [this](uint32 x, uint32 y, ushort16 v) {
+ return clampBits(this->deltaI[S::select(x, y)] + v, 16);
+ });
+ } else {
+ this->template applyOP<float>(ri, [this](uint32 x, uint32 y, float v) {
+ return this->deltaF[S::select(x, y)] + v;
+ });
+ }
+ }
+};
+
+template <typename S>
+class DngOpcodes::ScalePerRowOrCol final : public DeltaRowOrCol<S> {
+ // We have pixel value in range of [0..65535]. We scale by float X.
+ // For this to generate a value within the same range , the scale X needs
+ // to be in the range [0..65535]. Since the offset is multiplied
+ // by f2iScale before applying, we need to divide by f2iScale here.
+ // So the maxLimit has the same value as absLimit for OffsetPerRowOrCol.
+ static constexpr const double minLimit = 0.0;
+ const double maxLimit;
+
+ bool valueIsOk(float value) final {
+ return value >= minLimit && value <= maxLimit;
+ }
+
+public:
+ explicit ScalePerRowOrCol(const RawImage& ri, ByteStream* bs)
+ : DeltaRowOrCol<S>(ri, bs, 1024.0F),
+ maxLimit(double(std::numeric_limits<ushort16>::max()) /
+ this->f2iScale) {}
+
+ void apply(const RawImage& ri) override {
+ if (ri->getDataType() == TYPE_USHORT16) {
+ this->template applyOP<ushort16>(ri, [this](uint32 x, uint32 y,
+ ushort16 v) {
+ return clampBits((this->deltaI[S::select(x, y)] * v + 512) >> 10, 16);
+ });
+ } else {
+ this->template applyOP<float>(ri, [this](uint32 x, uint32 y, float v) {
+ return this->deltaF[S::select(x, y)] * v;
+ });
+ }
+ }
+};
+
+// ****************************************************************************
+
+DngOpcodes::DngOpcodes(const RawImage& ri, TiffEntry* entry) {
+ ByteStream bs = entry->getData();
+
+ // DNG opcodes are always stored in big-endian byte order.
+ bs.setByteOrder(Endianness::big);
+
+ const auto opcode_count = bs.getU32();
+ auto origPos = bs.getPosition();
+
+ // validate opcode count. we either have to do this, or we can't preallocate
+ for (auto i = 0U; i < opcode_count; i++) {
+ bs.skipBytes(4); // code
+ bs.skipBytes(4); // version
+ bs.skipBytes(4); // flags
+ const auto opcode_size = bs.getU32();
+ bs.skipBytes(opcode_size);
+ }
+
+ bs.setPosition(origPos);
+
+ // okay, we may indeed have that many opcodes in here. now let's reserve
+ opcodes.reserve(opcode_count);
+
+ for (auto i = 0U; i < opcode_count; i++) {
+ auto code = bs.getU32();
+ bs.skipBytes(4); // ignore version
+#ifdef DEBUG
+ bs.skipBytes(4); // ignore flags
+#else
+ auto flags = bs.getU32();
+#endif
+ const auto opcode_size = bs.getU32();
+ ByteStream opcode_bs = bs.getStream(opcode_size);
+
+ const char* opName = nullptr;
+ constructor_t opConstructor = nullptr;
+ try {
+ std::tie(opName, opConstructor) = Map.at(code);
+ } catch (std::out_of_range&) {
+ ThrowRDE("Unknown unhandled Opcode: %d", code);
+ }
+
+ if (opConstructor != nullptr)
+ opcodes.emplace_back(opConstructor(ri, &opcode_bs));
+ else {
+#ifndef DEBUG
+ // Throw Error if not marked as optional
+ if (!(flags & 1))
+#endif
+ ThrowRDE("Unsupported Opcode: %d (%s)", code, opName);
+ }
+
+ if (opcode_bs.getRemainSize() != 0)
+ ThrowRDE("Inconsistent length of opcode");
+ }
+
+#ifdef DEBUG
+ assert(opcodes.size() == opcode_count);
+#endif
+}
+
+// defined here as empty destrutor, otherwise we'd need a complete definition
+// of the the DngOpcode type in DngOpcodes.h
+DngOpcodes::~DngOpcodes() = default;
+
+void DngOpcodes::applyOpCodes(const RawImage& ri) {
+ for (const auto& code : opcodes) {
+ code->setup(ri);
+ code->apply(ri);
+ }
+}
+
+template <class Opcode>
+std::unique_ptr<DngOpcodes::DngOpcode>
+DngOpcodes::constructor(const RawImage& ri, ByteStream* bs) {
+ return std::make_unique<Opcode>(ri, bs);
+}
+
+// ALL opcodes specified in DNG Specification MUST be listed here.
+// however, some of them might not be implemented.
+const std::map<uint32, std::pair<const char*, DngOpcodes::constructor_t>>
+ DngOpcodes::Map = {
+ {1U, make_pair("WarpRectilinear", nullptr)},
+ {2U, make_pair("WarpFisheye", nullptr)},
+ {3U, make_pair("FixVignetteRadial", nullptr)},
+ {4U,
+ make_pair("FixBadPixelsConstant",
+ &DngOpcodes::constructor<DngOpcodes::FixBadPixelsConstant>)},
+ {5U, make_pair("FixBadPixelsList",
+ &DngOpcodes::constructor<DngOpcodes::FixBadPixelsList>)},
+ {6U, make_pair("TrimBounds",
+ &DngOpcodes::constructor<DngOpcodes::TrimBounds>)},
+ {7U,
+ make_pair("MapTable", &DngOpcodes::constructor<DngOpcodes::TableMap>)},
+ {8U, make_pair("MapPolynomial",
+ &DngOpcodes::constructor<DngOpcodes::PolynomialMap>)},
+ {9U, make_pair("GainMap", nullptr)},
+ {10U,
+ make_pair(
+ "DeltaPerRow",
+ &DngOpcodes::constructor<
+ DngOpcodes::OffsetPerRowOrCol<DeltaRowOrColBase::SelectY>>)},
+ {11U,
+ make_pair(
+ "DeltaPerColumn",
+ &DngOpcodes::constructor<
+ DngOpcodes::OffsetPerRowOrCol<DeltaRowOrColBase::SelectX>>)},
+ {12U,
+ make_pair(
+ "ScalePerRow",
+ &DngOpcodes::constructor<
+ DngOpcodes::ScalePerRowOrCol<DeltaRowOrColBase::SelectY>>)},
+ {13U,
+ make_pair(
+ "ScalePerColumn",
+ &DngOpcodes::constructor<
+ DngOpcodes::ScalePerRowOrCol<DeltaRowOrColBase::SelectX>>)},
+
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/DngOpcodes.h b/src/external/rawspeed/src/librawspeed/common/DngOpcodes.h
new file mode 100644
index 000000000..ce90ddeca
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/DngOpcodes.h
@@ -0,0 +1,73 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include <map> // for map
+#include <memory> // for unique_ptr
+#include <utility> // for pair
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class RawImage;
+
+class TiffEntry;
+
+class ByteStream;
+
+class DngOpcodes
+{
+public:
+ DngOpcodes(const RawImage& ri, TiffEntry* entry);
+ ~DngOpcodes();
+ void applyOpCodes(const RawImage& ri);
+
+private:
+ class DngOpcode;
+ std::vector<std::unique_ptr<DngOpcode>> opcodes;
+
+protected:
+ class FixBadPixelsConstant;
+ class FixBadPixelsList;
+ class ROIOpcode;
+ class DummyROIOpcode;
+ class TrimBounds;
+ class PixelOpcode;
+ class LookupOpcode;
+ class TableMap;
+ class PolynomialMap;
+ class DeltaRowOrColBase;
+ template <typename S> class DeltaRowOrCol;
+ template <typename S> class OffsetPerRowOrCol;
+ template <typename S> class ScalePerRowOrCol;
+
+ template <class Opcode>
+ static std::unique_ptr<DngOpcode> constructor(const RawImage& ri,
+ ByteStream* bs);
+
+ using constructor_t = std::unique_ptr<DngOpcode> (*)(const RawImage& ri,
+ ByteStream* bs);
+ static const std::map<uint32, std::pair<const char*, constructor_t>> Map;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/ErrorLog.cpp b/src/external/rawspeed/src/librawspeed/common/ErrorLog.cpp
new file mode 100644
index 000000000..d188ef83b
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/ErrorLog.cpp
@@ -0,0 +1,50 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "ErrorLog.h"
+#include "common/Mutex.h" // for MutexLocker
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+void ErrorLog::setError(const std::string& err) {
+ MutexLocker guard(&mutex);
+ errors.push_back(err);
+}
+
+bool ErrorLog::isTooManyErrors(unsigned many, std::string* firstErr) {
+ MutexLocker guard(&mutex);
+
+ if (errors.size() < many)
+ return false;
+
+ if (!firstErr)
+ return true;
+
+ *firstErr = errors[0];
+ return true;
+}
+
+std::vector<std::string>&& ErrorLog::getErrors() {
+ MutexLocker guard(&mutex);
+ return std::move(errors);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/ErrorLog.h b/src/external/rawspeed/src/librawspeed/common/ErrorLog.h
new file mode 100644
index 000000000..71a9b8df4
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/ErrorLog.h
@@ -0,0 +1,41 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "ThreadSafetyAnalysis.h" // for REQUIRES, GUARDED_BY
+#include "common/Mutex.h" // for Mutex
+#include <string> // for string
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class ErrorLog {
+ Mutex mutex;
+ std::vector<std::string> errors GUARDED_BY(mutex);
+
+public:
+ void setError(const std::string& err) REQUIRES(!mutex);
+ bool isTooManyErrors(unsigned many, std::string* firstErr = nullptr)
+ REQUIRES(!mutex);
+ std::vector<std::string>&& getErrors() REQUIRES(!mutex);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/Memory.cpp b/src/external/rawspeed/src/librawspeed/common/Memory.cpp
new file mode 100644
index 000000000..e110e44af
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/Memory.cpp
@@ -0,0 +1,107 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h"
+
+#include "common/Memory.h"
+
+#ifndef NDEBUG
+#include "common/Common.h" // for isPowerOfTwo, isAligned
+#endif
+
+#include <cassert> // for assert
+#include <cstddef> // for size_t, uintptr_t
+
+#if defined(HAVE_MM_MALLOC)
+// for _mm_malloc, _mm_free
+#include <xmmintrin.h>
+#elif defined(HAVE_ALIGNED_MALLOC)
+extern "C" {
+#include <malloc.h> // for _aligned_malloc, _aligned_free
+}
+#else
+#include <cstdlib> // for posix_memalign / aligned_alloc / malloc; free
+#endif
+
+namespace rawspeed {
+
+void* alignedMalloc(size_t size, size_t alignment) {
+ assert(isPowerOfTwo(alignment)); // for posix_memalign, _aligned_malloc
+ assert(isAligned(alignment, sizeof(void*))); // for posix_memalign
+ assert(isAligned(size, alignment)); // for aligned_alloc
+
+ void* ptr = nullptr;
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ // workaround ASAN's broken allocator_may_return_null option
+ // plus, avoidance of libFuzzer's rss_limit_mb option
+ // if trying to alloc more than 2GB, just return null.
+ // else it would abort() the whole program...
+ if (size > 2UL << 30UL)
+ return ptr;
+#endif
+
+#if defined(HAVE_POSIX_MEMALIGN)
+ if (0 != posix_memalign(&ptr, alignment, size))
+ return nullptr;
+#elif defined(HAVE_ALIGNED_ALLOC)
+ ptr = aligned_alloc(alignment, size);
+#elif defined(HAVE_MM_MALLOC)
+ ptr = _mm_malloc(size, alignment);
+#elif defined(HAVE_ALIGNED_MALLOC)
+ ptr = _aligned_malloc(size, alignment);
+#else
+#pragma message "No aligned malloc() implementation avaliable!"
+ assert(alignment <= alignof(std::max_align_t));
+#ifdef __APPLE__
+ // apple malloc() aligns to 16 by default
+ assert(alignment <= 16);
+#endif
+
+ ptr = malloc(size); // NOLINT
+#endif
+
+ assert(isAligned(ptr, alignment));
+
+ return ptr;
+}
+
+void alignedFree(void* ptr) {
+#if defined(HAVE_MM_MALLOC)
+ _mm_free(ptr);
+#elif defined(HAVE_ALIGNED_MALLOC)
+ _aligned_free(ptr);
+#else
+ free(ptr); // NOLINT
+#endif
+}
+
+void alignedFreeConstPtr(const void* ptr) {
+// an exception, specified by EXP05-C-EX1 and EXP55-CPP-EX1
+#if defined(HAVE_MM_MALLOC)
+ _mm_free(const_cast<void*>(ptr));
+#elif defined(HAVE_ALIGNED_MALLOC)
+ _aligned_free(const_cast<void*>(ptr));
+#else
+ free(const_cast<void*>(ptr)); // NOLINT
+#endif
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/Memory.h b/src/external/rawspeed/src/librawspeed/common/Memory.h
new file mode 100644
index 000000000..76c6abf74
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/Memory.h
@@ -0,0 +1,100 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h"
+
+#include "common/Common.h" // for isPowerOfTwo
+#include <cstddef> // for size_t
+#include <cstdint> // for SIZE_MAX
+
+namespace rawspeed {
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Wunknown-attributes"
+#pragma GCC diagnostic ignored "-Wattributes"
+
+// coverity[+alloc]
+void* alignedMalloc(size_t size, size_t alignment)
+ __attribute__((malloc, warn_unused_result, alloc_size(1), alloc_align(2),
+ deprecated("use alignedMalloc<alignment>(size)")));
+
+template <typename T, size_t alignment>
+// coverity[+alloc]
+inline T* __attribute__((malloc, warn_unused_result, alloc_size(1)))
+alignedMalloc(size_t size) {
+ static_assert(alignment >= alignof(T), "unsufficient alignment");
+ static_assert(isPowerOfTwo(alignment), "not power-of-two");
+ static_assert(isAligned(alignment, sizeof(void*)),
+ "not multiple of sizeof(void*)");
+
+#if !(defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_ALIGNED_ALLOC) || \
+ defined(HAVE_MM_MALLOC) || defined(HAVE_ALIGNED_MALLOC))
+ static_assert(alignment <= alignof(std::max_align_t), "too high alignment");
+#if defined(__APPLE__)
+ // apple malloc() aligns to 16 by default. can not expect any more
+ static_assert(alignment <= 16, "on OSX, plain malloc() aligns to 16");
+#endif
+#endif
+
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+ return reinterpret_cast<T*>(alignedMalloc(size, alignment));
+}
+
+#pragma GCC diagnostic pop
+
+template <typename T, size_t alignment, bool doRoundUp = false>
+// coverity[+alloc]
+inline T* __attribute__((malloc, warn_unused_result))
+alignedMallocArray(size_t nmemb, size_t size) {
+ // Check for size_t overflow
+ if (size && nmemb > SIZE_MAX / size)
+ return nullptr;
+
+ size *= nmemb;
+
+ if (doRoundUp)
+ size = roundUp(size, alignment);
+
+ return alignedMalloc<T, alignment>(size);
+}
+
+template <typename T, size_t alignment, typename T2, bool doRoundUp = false>
+// coverity[+alloc]
+inline T* __attribute__((malloc, warn_unused_result))
+alignedMallocArray(size_t nmemb) {
+ static_assert(sizeof(T), "???");
+ static_assert(sizeof(T2), "???");
+ static_assert(alignment >= alignof(T), "unsufficient alignment");
+ static_assert(alignment >= alignof(T2), "unsufficient alignment");
+ static_assert(isPowerOfTwo(sizeof(T2)), "not power-of-two");
+
+ return alignedMallocArray<T, alignment, doRoundUp>(nmemb, sizeof(T2));
+}
+
+// coverity[+free : arg-0]
+void alignedFree(void* ptr);
+
+// coverity[+free : arg-0]
+void alignedFreeConstPtr(const void* ptr);
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/Mutex.h b/src/external/rawspeed/src/librawspeed/common/Mutex.h
new file mode 100644
index 000000000..a036319b9
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/Mutex.h
@@ -0,0 +1,97 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h"
+#include "ThreadSafetyAnalysis.h"
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+namespace rawspeed {
+
+// Defines an annotated interface for mutexes.
+// These methods can be implemented to use any internal mutex implementation.
+#ifdef HAVE_PTHREAD
+
+class CAPABILITY("mutex") Mutex final {
+ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+public:
+ ~Mutex() { pthread_mutex_destroy(&mutex); }
+
+ // Acquire/lock this mutex exclusively. Only one thread can have exclusive
+ // access at any one time. Write operations to guarded data require an
+ // exclusive lock.
+ void Lock() ACQUIRE() { pthread_mutex_lock(&mutex); }
+
+ // Release/unlock an exclusive mutex.
+ void Unlock() RELEASE() { pthread_mutex_unlock(&mutex); }
+
+ // Try to acquire the mutex. Returns true on success, and false on failure.
+ bool TryLock() TRY_ACQUIRE(true) {
+ return pthread_mutex_trylock(&mutex) == 0;
+ }
+
+ // For negative capabilities.
+ const Mutex& operator!() const { return *this; }
+};
+
+#else
+
+class CAPABILITY("mutex") Mutex final {
+public:
+ // Acquire/lock this mutex exclusively. Only one thread can have exclusive
+ // access at any one time. Write operations to guarded data require an
+ // exclusive lock.
+ void __attribute__((const)) Lock() const ACQUIRE() {
+ // NOP, since there is no mutex. only here to still check for proper locking
+ }
+
+ // Release/unlock an exclusive mutex.
+ void __attribute__((const)) Unlock() const RELEASE() {
+ // NOP, since there is no mutex. only here to still check for proper locking
+ }
+
+ // Try to acquire the mutex. Returns true on success, and false on failure.
+ bool __attribute__((const)) TryLock() const TRY_ACQUIRE(true) {
+ // NOP, since there is no mutex. only here to still check for proper locking
+ return true;
+ }
+
+ // For negative capabilities.
+ const Mutex& operator!() const { return *this; }
+};
+
+#endif
+
+// MutexLocker is an RAII class that acquires a mutex in its constructor, and
+// releases it in its destructor.
+class SCOPED_CAPABILITY MutexLocker final {
+ Mutex* mut;
+
+public:
+ explicit MutexLocker(Mutex* mu) ACQUIRE(mu) : mut(mu) { mu->Lock(); }
+ ~MutexLocker() RELEASE() { mut->Unlock(); }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/NORangesSet.h b/src/external/rawspeed/src/librawspeed/common/NORangesSet.h
new file mode 100644
index 000000000..af1e208fc
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/NORangesSet.h
@@ -0,0 +1,37 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Range.h" // for RangesOverlap
+#include <set> // IWYU pragma: export
+// IWYU pragma: no_include <bits/stl_set.h>
+
+namespace rawspeed {
+
+template <typename T> struct RangesOverlapCmp final {
+ constexpr bool operator()(const T& lhs, const T& rhs) const {
+ return !RangesOverlap(lhs, rhs);
+ }
+};
+
+template <typename T> using NORangesSet = std::set<T, RangesOverlapCmp<T>>;
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/Point.h b/src/external/rawspeed/src/librawspeed/common/Point.h
new file mode 100644
index 000000000..3209c8ee7
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/Point.h
@@ -0,0 +1,210 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include <algorithm> // for max, min
+#include <cassert> // for assert
+#include <type_traits> // for make_signed
+
+namespace rawspeed {
+
+class iPoint2D {
+public:
+ using value_type = int;
+ using area_type = unsigned long long;
+
+ constexpr iPoint2D() = default;
+ constexpr iPoint2D(value_type a, value_type b) : x(a), y(b) {}
+
+ constexpr iPoint2D operator+(const iPoint2D& rhs) const {
+ return {x + rhs.x, y + rhs.y};
+ }
+ constexpr iPoint2D operator-(const iPoint2D& rhs) const {
+ return {x - rhs.x, y - rhs.y};
+ }
+
+ iPoint2D& operator+=(const iPoint2D& rhs) {
+ *this = operator+(rhs);
+ return *this;
+ }
+ iPoint2D& operator-=(const iPoint2D& rhs) {
+ *this = operator-(rhs);
+ return *this;
+ }
+
+ constexpr bool operator==(const iPoint2D& rhs) const {
+ return x == rhs.x && y == rhs.y;
+ }
+ constexpr bool operator!=(const iPoint2D& rhs) const {
+ return !operator==(rhs);
+ }
+
+ constexpr bool operator>(const iPoint2D& rhs) const {
+ return x > rhs.x && y > rhs.y;
+ }
+ constexpr bool operator<(const iPoint2D& rhs) const {
+ return x < rhs.x && y < rhs.y;
+ }
+
+ constexpr bool operator>=(const iPoint2D& rhs) const {
+ return x >= rhs.x && y >= rhs.y;
+ }
+ constexpr bool operator<=(const iPoint2D& rhs) const {
+ return x <= rhs.x && y <= rhs.y;
+ }
+
+ area_type __attribute__((pure)) area() const {
+ using signed_area = std::make_signed<area_type>::type;
+
+ if (x >= 0 && y >= 0)
+ return static_cast<area_type>(x) * static_cast<area_type>(y);
+ if (x >= 0 && y < 0)
+ return static_cast<area_type>(x) * (-1 * static_cast<signed_area>(y));
+ if (y >= 0 && x < 0)
+ return static_cast<area_type>(y) * (-1 * static_cast<signed_area>(x));
+
+ assert(x < 0 && y < 0);
+ return static_cast<signed_area>(x) * static_cast<signed_area>(y);
+ }
+
+ constexpr bool isThisInside(const iPoint2D& rhs) const {
+ return operator<=(rhs);
+ }
+
+ constexpr iPoint2D getSmallest(const iPoint2D& rhs) const {
+ return {x < rhs.x ? x : rhs.x, y < rhs.y ? y : rhs.y};
+ }
+
+ value_type x = 0;
+ value_type y = 0;
+};
+
+/* Helper class for managing a rectangle in 2D space. */
+class iRectangle2D {
+public:
+ constexpr iRectangle2D() = default;
+ constexpr iRectangle2D(const iPoint2D& pos_, const iPoint2D& dim_)
+ : pos(pos_), dim(dim_) {}
+ constexpr iRectangle2D(iPoint2D&& pos_, iPoint2D&& dim_)
+ : pos(pos_), dim(dim_) {}
+
+ constexpr iRectangle2D(int w, int h) : dim({w, h}) {}
+ constexpr iRectangle2D(int x_pos, int y_pos, int w, int h)
+ : pos({x_pos, y_pos}), dim({w, h}) {}
+
+ constexpr int getTop() const { return pos.y; }
+ constexpr int getBottom() const { return pos.y + dim.y; }
+ constexpr int getLeft() const { return pos.x; }
+ constexpr int getRight() const { return pos.x + dim.x; }
+ constexpr int getWidth() const { return dim.x; }
+ constexpr int getHeight() const { return dim.y; }
+ constexpr iPoint2D getTopLeft() const { return pos; }
+ constexpr iPoint2D getBottomRight() const { return dim + pos; }
+ constexpr bool hasPositiveArea() const { return (dim.x > 0) && (dim.y > 0); }
+
+ constexpr bool isThisInside(const iRectangle2D& otherPoint) const {
+ return pos >= otherPoint.pos &&
+ getBottomRight() <= otherPoint.getBottomRight();
+ }
+
+ constexpr bool isPointInsideInclusive(const iPoint2D& checkPoint) const {
+ return pos <= checkPoint && getBottomRight() >= checkPoint;
+ }
+
+ unsigned int area() const { return dim.area(); }
+
+ void offset(const iPoint2D& offset_) { pos += offset_; }
+
+ /* Retains size */
+ void setTopLeft(const iPoint2D& top_left) { pos = top_left; }
+ void setTopLeft(iPoint2D&& top_left) { pos = top_left; }
+
+ /* Set BR */
+ void setBottomRightAbsolute(const iPoint2D& bottom_right) {
+ dim = bottom_right - pos;
+ }
+
+ void setAbsolute(const iPoint2D& top_left, const iPoint2D& bottom_right) {
+ pos = top_left;
+ setBottomRightAbsolute(bottom_right);
+ }
+ void setAbsolute(iPoint2D&& top_left, iPoint2D&& bottom_right) {
+ pos = top_left;
+ setBottomRightAbsolute(bottom_right);
+ }
+ void setAbsolute(int x1, int y1, int x2, int y2) {
+ setAbsolute({x1, y1}, {x2, y2});
+ }
+
+ void setSize(const iPoint2D& size) { dim = size; }
+ void setSize(iPoint2D&& size) { dim = size; }
+
+ /* Crop, so area is postitive, and return true, if there is any area left */
+ /* This will ensure that bottomright is never on the left/top of the offset */
+ bool cropArea() {
+ dim.x = std::max(0, dim.x);
+ dim.y = std::max(0, dim.y);
+ return hasPositiveArea();
+ }
+
+ /* This will make sure that offset is positive, and make the area smaller if
+ * needed */
+ /* This will return true if there is any area left */
+ bool cropOffsetToZero() {
+ iPoint2D crop_pixels;
+ if (pos.x < 0) {
+ crop_pixels.x = -(pos.x);
+ pos.x = 0;
+ }
+ if (pos.y < 0) {
+ crop_pixels.y = -pos.y;
+ pos.y = 0;
+ }
+ dim -= crop_pixels;
+ return cropArea();
+ }
+
+ iRectangle2D getOverlap(const iRectangle2D& other) const {
+ iRectangle2D overlap;
+ iPoint2D br1 = getBottomRight();
+ iPoint2D br2 = other.getBottomRight();
+ overlap.setAbsolute(std::max(pos.x, other.pos.x),
+ std::max(pos.y, other.pos.y), std::min(br1.x, br2.x),
+ std::min(br1.y, br2.y));
+ return overlap;
+ }
+
+ iRectangle2D combine(const iRectangle2D& other) const {
+ iRectangle2D combined;
+ iPoint2D br1 = getBottomRight();
+ iPoint2D br2 = other.getBottomRight();
+ combined.setAbsolute(std::min(pos.x, other.pos.x),
+ std::min(pos.y, other.pos.y), std::max(br1.x, br2.x),
+ std::max(br2.y, br2.y));
+ return combined;
+ }
+
+ iPoint2D pos{0, 0};
+ iPoint2D dim{0, 0};
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/Range.h b/src/external/rawspeed/src/librawspeed/common/Range.h
new file mode 100644
index 000000000..d9e2b84a3
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/Range.h
@@ -0,0 +1,75 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include <algorithm> // for min
+#include <cassert> // for assert
+#include <type_traits> // for enable_if, is_pointer
+#include <utility> // for pair
+
+namespace rawspeed {
+
+template <typename T> class Range final {
+ T base;
+ typename std::make_unsigned<T>::type size;
+
+public:
+ constexpr Range() = default;
+
+ template <typename T2,
+ typename = std::enable_if_t<std::is_unsigned<T2>::value>>
+ constexpr Range(T base_, T2 size_) : base(base_), size(size_) {}
+
+ constexpr T __attribute__((const)) begin() const { return base; }
+
+ constexpr T __attribute__((const)) end() const { return base + T(size); }
+};
+
+template <typename Tr, typename Tv>
+inline constexpr bool __attribute__((const))
+RangeContains(const Tr& r, Tv pos) {
+ if (pos < r.begin())
+ return false;
+
+ assert(pos >= r.begin());
+ return r.end() > pos;
+}
+
+template <typename T>
+inline constexpr bool __attribute__((const))
+RangesOverlap(const T& lhs, const T& rhs) {
+ if (&lhs == &rhs)
+ return true;
+
+ if (lhs.begin() == rhs.begin())
+ return true;
+
+ const std::pair<const T&, const T&> ordered =
+ std::minmax(lhs, rhs, [](const T& r0, const T& r1) {
+ assert(r0.begin() != r1.begin());
+ return r0.begin() < r1.begin();
+ });
+
+ assert(ordered.first.begin() < ordered.second.begin());
+ return RangeContains(ordered.first, ordered.second.begin());
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/RawImage.cpp b/src/external/rawspeed/src/librawspeed/common/RawImage.cpp
new file mode 100644
index 000000000..7a4f33fdd
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/RawImage.cpp
@@ -0,0 +1,626 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h" // for WITH_SSE2
+#include "common/RawImage.h"
+#include "common/Memory.h" // for alignedFree, alignedMalloc...
+#include "decoders/RawDecoderException.h" // for ThrowRDE, RawDecoderException
+#include "io/IOException.h" // for IOException
+#include "parsers/TiffParserException.h" // for TiffParserException
+#include <algorithm> // for min
+#include <cassert> // for assert
+#include <cmath> // for NAN
+#include <cstdlib> // for free
+#include <cstring> // for memset, memcpy, strdup
+#include <limits> // for numeric_limits
+#include <memory> // for unique_ptr
+
+using std::fill_n;
+using std::string;
+
+namespace rawspeed {
+
+RawImageData::RawImageData() : cfa(iPoint2D(0, 0)) {
+ blackLevelSeparate.fill(-1);
+}
+
+RawImageData::RawImageData(const iPoint2D& _dim, uint32 _bpc, uint32 _cpp)
+ : dim(_dim), isCFA(_cpp == 1), cfa(iPoint2D(0, 0)), cpp(_cpp) {
+ assert(_bpc > 0);
+
+ if (cpp > std::numeric_limits<decltype(bpp)>::max() / _bpc)
+ ThrowRDE("Components-per-pixel is too large.");
+
+ bpp = _bpc * _cpp;
+ blackLevelSeparate.fill(-1);
+ createData();
+}
+
+ImageMetaData::ImageMetaData() {
+ subsampling.x = subsampling.y = 1;
+ isoSpeed = 0;
+ pixelAspectRatio = 1;
+ fujiRotationPos = 0;
+ fill_n(wbCoeffs, 4, NAN);
+}
+
+RawImageData::~RawImageData() {
+ assert(dataRefCount == 0);
+ mOffset = iPoint2D(0, 0);
+
+ destroyData();
+}
+
+
+void RawImageData::createData() {
+ static constexpr const auto alignment = 16;
+
+ if (dim.x > 65535 || dim.y > 65535)
+ ThrowRDE("Dimensions too large for allocation.");
+ if (dim.x <= 0 || dim.y <= 0)
+ ThrowRDE("Dimension of one sides is less than 1 - cannot allocate image.");
+ if (data)
+ ThrowRDE("Duplicate data allocation in createData.");
+
+ // want each line to start at 16-byte aligned address
+ pitch = roundUp(static_cast<size_t>(dim.x) * bpp, alignment);
+ assert(isAligned(pitch, alignment));
+
+#if defined(DEBUG) || __has_feature(address_sanitizer) || \
+ defined(__SANITIZE_ADDRESS__)
+ // want to ensure that we have some padding
+ pitch += alignment * alignment;
+ assert(isAligned(pitch, alignment));
+#endif
+
+ padding = pitch - dim.x * bpp;
+
+#if defined(DEBUG) || __has_feature(address_sanitizer) || \
+ defined(__SANITIZE_ADDRESS__)
+ assert(padding > 0);
+#endif
+
+ data = alignedMallocArray<uchar8, alignment>(dim.y, pitch);
+
+ if (!data)
+ ThrowRDE("Memory Allocation failed.");
+
+ uncropped_dim = dim;
+
+#ifndef NDEBUG
+ if (dim.y > 1) {
+ // padding is the size of the area after last pixel of line n
+ // and before the first pixel of line n+1
+ assert(getData(dim.x - 1, 0) + bpp + padding == getData(0, 1));
+ }
+
+ for (int j = 0; j < dim.y; j++) {
+ const uchar8* const line = getData(0, j);
+ // each line is indeed 16-byte aligned
+ assert(isAligned(line, alignment));
+ }
+#endif
+
+ poisonPadding();
+}
+
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+void RawImageData::poisonPadding() {
+ if (padding <= 0)
+ return;
+
+ for (int j = 0; j < uncropped_dim.y; j++) {
+ const uchar8* const curr_line_end =
+ getDataUncropped(uncropped_dim.x - 1, j) + bpp;
+
+ // and now poison the padding.
+ ASAN_POISON_MEMORY_REGION(curr_line_end, padding);
+ }
+}
+#else
+void __attribute__((const)) RawImageData::poisonPadding() {
+ // if we are building without ASAN, then there is no need/way to poison.
+ // however, i think it is better to have such an empty function rather
+ // than making this whole function not exist in ASAN-less builds
+}
+#endif
+
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+void RawImageData::unpoisonPadding() {
+ if (padding <= 0)
+ return;
+
+ for (int j = 0; j < uncropped_dim.y; j++) {
+ const uchar8* const curr_line_end =
+ getDataUncropped(uncropped_dim.x - 1, j) + bpp;
+
+ // and now unpoison the padding.
+ ASAN_UNPOISON_MEMORY_REGION(curr_line_end, padding);
+ }
+}
+#else
+void __attribute__((const)) RawImageData::unpoisonPadding() {
+ // if we are building without ASAN, then there is no need/way to poison.
+ // however, i think it is better to have such an empty function rather
+ // than making this whole function not exist in ASAN-less builds
+}
+#endif
+
+#if __has_feature(memory_sanitizer) || defined(__SANITIZE_MEMORY__)
+void RawImageData::checkRowIsInitialized(int row) {
+ const auto rowsize = bpp * uncropped_dim.x;
+
+ const uchar8* const curr_line = getDataUncropped(0, row);
+
+ // and check that image line is initialized.
+ // do note that we are avoiding padding here.
+ MSAN_MEM_IS_INITIALIZED(curr_line, rowsize);
+}
+#else
+void __attribute__((const)) RawImageData::checkRowIsInitialized(int row) {
+ // if we are building without MSAN, then there is no way to check whether
+ // the image row was fully initialized. however, i think it is better to
+ // have such an empty function rather than making this whole function not
+ // exist in MSAN-less builds
+}
+#endif
+
+#if __has_feature(memory_sanitizer) || defined(__SANITIZE_MEMORY__)
+void RawImageData::checkMemIsInitialized() {
+ for (int j = 0; j < uncropped_dim.y; j++)
+ checkRowIsInitialized(j);
+}
+#else
+void __attribute__((const)) RawImageData::checkMemIsInitialized() {
+ // if we are building without MSAN, then there is no way to check whether
+ // the image data was fully initialized. however, i think it is better to
+ // have such an empty function rather than making this whole function not
+ // exist in MSAN-less builds
+}
+#endif
+
+void RawImageData::destroyData() {
+ if (data)
+ alignedFree(data);
+ if (mBadPixelMap)
+ alignedFree(mBadPixelMap);
+ data = nullptr;
+ mBadPixelMap = nullptr;
+}
+
+void RawImageData::setCpp(uint32 val) {
+ if (data)
+ ThrowRDE("Attempted to set Components per pixel after data allocation");
+ if (val > 4) {
+ ThrowRDE(
+ "Only up to 4 components per pixel is support - attempted to set: %d",
+ val);
+ }
+
+ bpp /= cpp;
+ cpp = val;
+ bpp *= val;
+}
+
+uchar8* RawImageData::getData() const {
+ if (!data)
+ ThrowRDE("Data not yet allocated.");
+ return &data[mOffset.y*pitch+mOffset.x*bpp];
+}
+
+uchar8* RawImageData::getData(uint32 x, uint32 y) {
+ if (x >= static_cast<unsigned>(uncropped_dim.x))
+ ThrowRDE("X Position outside image requested.");
+ if (y >= static_cast<unsigned>(uncropped_dim.y))
+ ThrowRDE("Y Position outside image requested.");
+
+ x += mOffset.x;
+ y += mOffset.y;
+
+ if (!data)
+ ThrowRDE("Data not yet allocated.");
+
+ return &data[static_cast<size_t>(y) * pitch + x * bpp];
+}
+
+uchar8* RawImageData::getDataUncropped(uint32 x, uint32 y) {
+ if (x >= static_cast<unsigned>(uncropped_dim.x))
+ ThrowRDE("X Position outside image requested.");
+ if (y >= static_cast<unsigned>(uncropped_dim.y))
+ ThrowRDE("Y Position outside image requested.");
+
+ if (!data)
+ ThrowRDE("Data not yet allocated.");
+
+ return &data[static_cast<size_t>(y) * pitch + x * bpp];
+}
+
+iPoint2D __attribute__((pure)) rawspeed::RawImageData::getUncroppedDim() const {
+ return uncropped_dim;
+}
+
+iPoint2D __attribute__((pure)) RawImageData::getCropOffset() const {
+ return mOffset;
+}
+
+void RawImageData::subFrame(iRectangle2D crop) {
+ if (!crop.dim.isThisInside(dim - crop.pos)) {
+ writeLog(DEBUG_PRIO_WARNING, "WARNING: RawImageData::subFrame - Attempted "
+ "to create new subframe larger than original "
+ "size. Crop skipped.");
+ return;
+ }
+ if (crop.pos.x < 0 || crop.pos.y < 0 || !crop.hasPositiveArea()) {
+ writeLog(DEBUG_PRIO_WARNING, "WARNING: RawImageData::subFrame - Negative "
+ "crop offset. Crop skipped.");
+ return;
+ }
+
+ // if CFA, and not X-Trans, adjust.
+ if (isCFA && cfa.getDcrawFilter() != 1 && cfa.getDcrawFilter() != 9) {
+ cfa.shiftLeft(crop.pos.x);
+ cfa.shiftDown(crop.pos.y);
+ }
+
+ mOffset += crop.pos;
+ dim = crop.dim;
+}
+
+void RawImageData::createBadPixelMap()
+{
+ if (!isAllocated())
+ ThrowRDE("(internal) Bad pixel map cannot be allocated before image.");
+ mBadPixelMapPitch = roundUp(roundUpDivision(uncropped_dim.x, 8), 16);
+ mBadPixelMap =
+ alignedMallocArray<uchar8, 16>(uncropped_dim.y, mBadPixelMapPitch);
+ memset(mBadPixelMap, 0,
+ static_cast<size_t>(mBadPixelMapPitch) * uncropped_dim.y);
+ if (!mBadPixelMap)
+ ThrowRDE("Memory Allocation failed.");
+}
+
+RawImage::RawImage(RawImageData* p) : p_(p) {
+ MutexLocker guard(&p_->mymutex);
+ ++p_->dataRefCount;
+}
+
+RawImage::RawImage(const RawImage& p) : p_(p.p_) {
+ MutexLocker guard(&p_->mymutex);
+ ++p_->dataRefCount;
+}
+
+RawImage::~RawImage() {
+ p_->mymutex.Lock();
+
+ --p_->dataRefCount;
+
+ if (p_->dataRefCount == 0) {
+ p_->mymutex.Unlock();
+ delete p_;
+ return;
+ }
+
+ p_->mymutex.Unlock();
+}
+
+void RawImageData::transferBadPixelsToMap()
+{
+ MutexLocker guard(&mBadPixelMutex);
+ if (mBadPixelPositions.empty())
+ return;
+
+ if (!mBadPixelMap)
+ createBadPixelMap();
+
+ for (unsigned int pos : mBadPixelPositions) {
+ ushort16 pos_x = pos & 0xffff;
+ ushort16 pos_y = pos >> 16;
+
+ assert(pos_x < static_cast<ushort16>(uncropped_dim.x));
+ assert(pos_y < static_cast<ushort16>(uncropped_dim.y));
+
+ mBadPixelMap[mBadPixelMapPitch * pos_y + (pos_x >> 3)] |= 1 << (pos_x&7);
+ }
+ mBadPixelPositions.clear();
+}
+
+void RawImageData::fixBadPixels()
+{
+#if !defined (EMULATE_DCRAW_BAD_PIXELS)
+
+ /* Transfer if not already done */
+ transferBadPixelsToMap();
+
+#if 0 // For testing purposes
+ if (!mBadPixelMap)
+ createBadPixelMap();
+ for (int y = 400; y < 700; y++){
+ for (int x = 1200; x < 1700; x++) {
+ mBadPixelMap[mBadPixelMapPitch * y + (x >> 3)] |= 1 << (x&7);
+ }
+ }
+#endif
+
+ /* Process bad pixels, if any */
+ if (mBadPixelMap)
+ startWorker(RawImageWorker::FIX_BAD_PIXELS, false);
+
+#else // EMULATE_DCRAW_BAD_PIXELS - not recommended, testing purposes only
+
+ for (vector<uint32>::iterator i=mBadPixelPositions.begin(); i != mBadPixelPositions.end(); ++i) {
+ uint32 pos = *i;
+ uint32 pos_x = pos&0xffff;
+ uint32 pos_y = pos>>16;
+ uint32 total = 0;
+ uint32 div = 0;
+ // 0 side covered by unsignedness.
+ for (uint32 r=pos_x-2; r<=pos_x+2 && r<(uint32)uncropped_dim.x; r+=2) {
+ for (uint32 c=pos_y-2; c<=pos_y+2 && c<(uint32)uncropped_dim.y; c+=2) {
+ ushort16* pix = (ushort16*)getDataUncropped(r,c);
+ if (*pix) {
+ total += *pix;
+ div++;
+ }
+ }
+ }
+ ushort16* pix = (ushort16*)getDataUncropped(pos_x,pos_y);
+ if (div) {
+ pix[0] = total / div;
+ }
+ }
+#endif
+
+}
+
+void RawImageData::startWorker(RawImageWorker::RawImageWorkerTask task, bool cropped )
+{
+ int height = (cropped) ? dim.y : uncropped_dim.y;
+ if (task & RawImageWorker::FULL_IMAGE) {
+ height = uncropped_dim.y;
+ }
+
+ int threads = getThreadCount();
+ if (threads <= 1) {
+ RawImageWorker worker(this, task, 0, height);
+ worker.performTask();
+ return;
+ }
+
+#ifdef HAVE_PTHREAD
+ std::vector<RawImageWorker> workers;
+ workers.reserve(threads);
+
+ int y_offset = 0;
+ int y_per_thread = (height + threads - 1) / threads;
+
+ for (int i = 0; i < threads; i++) {
+ int y_end = std::min(y_offset + y_per_thread, height);
+
+ workers.emplace_back(this, task, y_offset, y_end);
+ workers.back().startThread();
+
+ y_offset = y_end;
+ }
+
+ for (auto& worker : workers)
+ worker.waitForThread();
+#else
+ ThrowRDE("Unreachable");
+#endif
+}
+
+void RawImageData::fixBadPixelsThread(int start_y, int end_y) {
+ int gw = (uncropped_dim.x + 15) / 32;
+
+ for (int y = start_y; y < end_y; y++) {
+ auto* bad_map =
+ reinterpret_cast<const uint32*>(&mBadPixelMap[y * mBadPixelMapPitch]);
+ for (int x = 0; x < gw; x++) {
+ // Test if there is a bad pixel within these 32 pixels
+ if (bad_map[x] == 0)
+ continue;
+ auto* bad = reinterpret_cast<const uchar8*>(&bad_map[x]);
+ // Go through each pixel
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 8; j++) {
+ if (1 != ((bad[i] >> j) & 1))
+ continue;
+
+ fixBadPixel(x * 32 + i * 8 + j, y, 0);
+ }
+ }
+ }
+ }
+}
+
+void RawImageData::blitFrom(const RawImage& src, const iPoint2D& srcPos,
+ const iPoint2D& size, const iPoint2D& destPos) {
+ iRectangle2D src_rect(srcPos, size);
+ iRectangle2D dest_rect(destPos, size);
+ src_rect = src_rect.getOverlap(iRectangle2D(iPoint2D(0,0), src->dim));
+ dest_rect = dest_rect.getOverlap(iRectangle2D(iPoint2D(0,0), dim));
+
+ iPoint2D blitsize = src_rect.dim.getSmallest(dest_rect.dim);
+ if (blitsize.area() <= 0)
+ return;
+
+ // TODO: Move offsets after crop.
+ copyPixels(getData(dest_rect.pos.x, dest_rect.pos.y), pitch,
+ src->getData(src_rect.pos.x, src_rect.pos.y), src->pitch,
+ blitsize.x * bpp, blitsize.y);
+}
+
+/* Does not take cfa into consideration */
+void RawImageData::expandBorder(iRectangle2D validData)
+{
+ validData = validData.getOverlap(iRectangle2D(0,0,dim.x, dim.y));
+ if (validData.pos.x > 0) {
+ for (int y = 0; y < dim.y; y++ ) {
+ uchar8* src_pos = getData(validData.pos.x, y);
+ uchar8* dst_pos = getData(validData.pos.x-1, y);
+ for (int x = validData.pos.x; x >= 0; x--) {
+ for (uint32 i = 0; i < bpp; i++) {
+ dst_pos[i] = src_pos[i];
+ }
+ dst_pos -= bpp;
+ }
+ }
+ }
+
+ if (validData.getRight() < dim.x) {
+ int pos = validData.getRight();
+ for (int y = 0; y < dim.y; y++ ) {
+ uchar8* src_pos = getData(pos-1, y);
+ uchar8* dst_pos = getData(pos, y);
+ for (int x = pos; x < dim.x; x++) {
+ for (uint32 i = 0; i < bpp; i++) {
+ dst_pos[i] = src_pos[i];
+ }
+ dst_pos += bpp;
+ }
+ }
+ }
+
+ if (validData.pos.y > 0) {
+ uchar8* src_pos = getData(0, validData.pos.y);
+ for (int y = 0; y < validData.pos.y; y++ ) {
+ uchar8* dst_pos = getData(0, y);
+ memcpy(dst_pos, src_pos, static_cast<size_t>(dim.x) * bpp);
+ }
+ }
+ if (validData.getBottom() < dim.y) {
+ uchar8* src_pos = getData(0, validData.getBottom()-1);
+ for (int y = validData.getBottom(); y < dim.y; y++ ) {
+ uchar8* dst_pos = getData(0, y);
+ memcpy(dst_pos, src_pos, static_cast<size_t>(dim.x) * bpp);
+ }
+ }
+}
+
+void RawImageData::clearArea( iRectangle2D area, uchar8 val /*= 0*/ )
+{
+ area = area.getOverlap(iRectangle2D(iPoint2D(0,0), dim));
+
+ if (area.area() <= 0)
+ return;
+
+ for (int y = area.getTop(); y < area.getBottom(); y++)
+ memset(getData(area.getLeft(), y), val,
+ static_cast<size_t>(area.getWidth()) * bpp);
+}
+
+RawImage& RawImage::operator=(RawImage&& rhs) noexcept {
+ if (this == &rhs)
+ return *this;
+
+ std::swap(p_, rhs.p_);
+
+ return *this;
+}
+
+RawImage& RawImage::operator=(const RawImage& rhs) noexcept {
+ if (this == &rhs)
+ return *this;
+
+ RawImage tmp(rhs);
+ *this = std::move(tmp);
+
+ return *this;
+}
+
+void *RawImageWorkerThread(void *_this) {
+ auto* me = static_cast<RawImageWorker*>(_this);
+ me->performTask();
+ return nullptr;
+}
+
+RawImageWorker::RawImageWorker(RawImageData* _img, RawImageWorkerTask _task,
+ int _start_y, int _end_y)
+ : data(_img), task(_task), start_y(_start_y), end_y(_end_y) {
+#ifdef HAVE_PTHREAD
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+#endif
+}
+
+#ifdef HAVE_PTHREAD
+RawImageWorker::~RawImageWorker() { pthread_attr_destroy(&attr); }
+#endif
+
+#ifdef HAVE_PTHREAD
+void RawImageWorker::startThread()
+{
+ /* Initialize and set thread detached attribute */
+ pthread_create(&threadid, &attr, RawImageWorkerThread, this);
+}
+
+void RawImageWorker::waitForThread()
+{
+ void *status;
+ pthread_join(threadid, &status);
+}
+#endif
+
+void RawImageWorker::performTask()
+{
+ try {
+ switch(task)
+ {
+ case SCALE_VALUES:
+ data->scaleValues(start_y, end_y);
+ break;
+ case FIX_BAD_PIXELS:
+ data->fixBadPixelsThread(start_y, end_y);
+ break;
+ case APPLY_LOOKUP:
+ data->doLookup(start_y, end_y);
+ break;
+ default:
+ assert(false);
+ }
+ } catch (RawDecoderException &e) {
+ data->setError(e.what());
+ } catch (TiffParserException &e) {
+ data->setError(e.what());
+ } catch (IOException &e) {
+ data->setError(e.what());
+ }
+}
+
+void RawImageData::sixteenBitLookup() {
+ if (table == nullptr) {
+ return;
+ }
+ startWorker(RawImageWorker::APPLY_LOOKUP, true);
+}
+
+void RawImageData::setTable(std::unique_ptr<TableLookUp> t) {
+ table = std::move(t);
+}
+
+void RawImageData::setTable(const std::vector<ushort16>& table_, bool dither) {
+ assert(!table_.empty());
+
+ auto t = std::make_unique<TableLookUp>(1, dither);
+ t->setTable(0, table_);
+ this->setTable(std::move(t));
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/RawImage.h b/src/external/rawspeed/src/librawspeed/common/RawImage.h
new file mode 100644
index 000000000..79d8efdc3
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/RawImage.h
@@ -0,0 +1,322 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h"
+
+#include "ThreadSafetyAnalysis.h" // for GUARDED_BY, REQUIRES
+#include "common/Common.h" // for uint32, uchar8, ushort16, wri...
+#include "common/ErrorLog.h" // for ErrorLog
+#include "common/Mutex.h" // for Mutex
+#include "common/Point.h" // for iPoint2D, iRectangle2D (ptr o...
+#include "common/TableLookUp.h" // for TableLookUp
+#include "metadata/BlackArea.h" // for BlackArea
+#include "metadata/ColorFilterArray.h" // for ColorFilterArray
+#include <array> // for array
+#include <memory> // for unique_ptr, operator==
+#include <string> // for string
+#include <vector> // for vector
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
+namespace rawspeed {
+
+class RawImage;
+
+class RawImageData;
+
+enum RawImageType { TYPE_USHORT16, TYPE_FLOAT32 };
+
+class RawImageWorker {
+public:
+ enum RawImageWorkerTask {
+ SCALE_VALUES = 1, FIX_BAD_PIXELS = 2, APPLY_LOOKUP = 3 | 0x1000, FULL_IMAGE = 0x1000
+ };
+
+private:
+#ifdef HAVE_PTHREAD
+ pthread_t threadid;
+ pthread_attr_t attr;
+#endif
+ RawImageData* data;
+ RawImageWorkerTask task;
+ int start_y;
+ int end_y;
+
+public:
+ RawImageWorker(RawImageData* img, RawImageWorkerTask task, int start_y,
+ int end_y);
+#ifdef HAVE_PTHREAD
+ ~RawImageWorker();
+ void startThread();
+ void waitForThread();
+#endif
+ void performTask();
+};
+
+void* RawImageWorkerThread(void* _this);
+
+class ImageMetaData {
+public:
+ ImageMetaData();
+
+ // Aspect ratio of the pixels, usually 1 but some cameras need scaling
+ // <1 means the image needs to be stretched vertically, (0.5 means 2x)
+ // >1 means the image needs to be stretched horizontally (2 mean 2x)
+ double pixelAspectRatio;
+
+ // White balance coefficients of the image
+ float wbCoeffs[4];
+
+ // How many pixels far down the left edge and far up the right edge the image
+ // corners are when the image is rotated 45 degrees in Fuji rotated sensors.
+ uint32 fujiRotationPos;
+
+ iPoint2D subsampling;
+ std::string make;
+ std::string model;
+ std::string mode;
+
+ std::string canonical_make;
+ std::string canonical_model;
+ std::string canonical_alias;
+ std::string canonical_id;
+
+ // ISO speed. If known the value is set, otherwise it will be '0'.
+ int isoSpeed;
+};
+
+class RawImageData : public ErrorLog {
+ friend class RawImageWorker;
+public:
+ virtual ~RawImageData();
+ uint32 getCpp() const { return cpp; }
+ uint32 getBpp() const { return bpp; }
+ void setCpp(uint32 val);
+ void createData();
+ void poisonPadding();
+ void unpoisonPadding();
+ void checkRowIsInitialized(int row);
+ void checkMemIsInitialized();
+ void destroyData();
+ void blitFrom(const RawImage& src, const iPoint2D& srcPos,
+ const iPoint2D& size, const iPoint2D& destPos);
+ rawspeed::RawImageType getDataType() const { return dataType; }
+ uchar8* getData() const;
+ uchar8* getData(uint32 x, uint32 y); // Not super fast, but safe. Don't use per pixel.
+ uchar8* getDataUncropped(uint32 x, uint32 y);
+ void subFrame(iRectangle2D cropped);
+ void clearArea(iRectangle2D area, uchar8 value = 0);
+ iPoint2D __attribute__((pure)) getUncroppedDim() const;
+ iPoint2D __attribute__((pure)) getCropOffset() const;
+ virtual void scaleBlackWhite() = 0;
+ virtual void calculateBlackAreas() = 0;
+ virtual void setWithLookUp(ushort16 value, uchar8* dst, uint32* random) = 0;
+ void sixteenBitLookup();
+ void transferBadPixelsToMap() REQUIRES(!mBadPixelMutex);
+ void fixBadPixels() REQUIRES(!mBadPixelMutex);
+ void expandBorder(iRectangle2D validData);
+ void setTable(const std::vector<ushort16>& table_, bool dither);
+ void setTable(std::unique_ptr<TableLookUp> t);
+
+ bool isAllocated() {return !!data;}
+ void createBadPixelMap();
+ iPoint2D dim;
+ uint32 pitch = 0;
+
+ // padding is the size of the area after last pixel of line n
+ // and before the first pixel of line n+1
+ uint32 padding = 0;
+
+ bool isCFA{true};
+ ColorFilterArray cfa;
+ int blackLevel = -1;
+ std::array<int, 4> blackLevelSeparate;
+ int whitePoint = 65536;
+ std::vector<BlackArea> blackAreas;
+
+ /* Vector containing the positions of bad pixels */
+ /* Format is x | (y << 16), so maximum pixel position is 65535 */
+ // Positions of zeroes that must be interpolated
+ std::vector<uint32> mBadPixelPositions GUARDED_BY(mBadPixelMutex);
+ uchar8* mBadPixelMap = nullptr;
+ uint32 mBadPixelMapPitch = 0;
+ bool mDitherScale =
+ true; // Should upscaling be done with dither to minimize banding?
+ ImageMetaData metadata;
+
+ Mutex mBadPixelMutex; // Mutex for 'mBadPixelPositions, must be used if more
+ // than 1 thread is accessing vector
+
+private:
+ uint32 dataRefCount GUARDED_BY(mymutex) = 0;
+
+protected:
+ RawImageType dataType;
+ RawImageData();
+ RawImageData(const iPoint2D &dim, uint32 bpp, uint32 cpp = 1);
+ virtual void scaleValues(int start_y, int end_y) = 0;
+ virtual void doLookup(int start_y, int end_y) = 0;
+ virtual void fixBadPixel( uint32 x, uint32 y, int component = 0) = 0;
+ void fixBadPixelsThread(int start_y, int end_y);
+ void startWorker(RawImageWorker::RawImageWorkerTask task, bool cropped );
+ uchar8* data = nullptr;
+ uint32 cpp = 1; // Components per pixel
+ uint32 bpp = 0; // Bytes per pixel.
+ friend class RawImage;
+ iPoint2D mOffset;
+ iPoint2D uncropped_dim;
+ std::unique_ptr<TableLookUp> table;
+ Mutex mymutex;
+};
+
+class RawImageDataU16 final : public RawImageData {
+public:
+ void scaleBlackWhite() override;
+ void calculateBlackAreas() override;
+ void setWithLookUp(ushort16 value, uchar8* dst, uint32* random) override;
+
+protected:
+ void scaleValues_plain(int start_y, int end_y);
+#ifdef WITH_SSE2
+ void scaleValues_SSE2(int start_y, int end_y);
+#endif
+ void scaleValues(int start_y, int end_y) override;
+ void fixBadPixel(uint32 x, uint32 y, int component = 0) override;
+ void doLookup(int start_y, int end_y) override;
+
+ RawImageDataU16();
+ explicit RawImageDataU16(const iPoint2D& dim, uint32 cpp = 1);
+ friend class RawImage;
+};
+
+class RawImageDataFloat final : public RawImageData {
+public:
+ void scaleBlackWhite() override;
+ void calculateBlackAreas() override;
+ void setWithLookUp(ushort16 value, uchar8 *dst, uint32 *random) override;
+
+protected:
+ void scaleValues(int start_y, int end_y) override;
+ void fixBadPixel(uint32 x, uint32 y, int component = 0) override;
+ [[noreturn]] void doLookup(int start_y, int end_y) override;
+ RawImageDataFloat();
+ explicit RawImageDataFloat(const iPoint2D& dim, uint32 cpp = 1);
+ friend class RawImage;
+};
+
+ class RawImage {
+ public:
+ static RawImage create(RawImageType type = TYPE_USHORT16);
+ static RawImage create(const iPoint2D &dim,
+ RawImageType type = TYPE_USHORT16,
+ uint32 componentsPerPixel = 1);
+ RawImageData* operator->() const { return p_; }
+ RawImageData& operator*() const { return *p_; }
+ explicit RawImage(RawImageData* p); // p must not be NULL
+ ~RawImage();
+ RawImage(const RawImage& p);
+ RawImage& operator=(const RawImage& p) noexcept;
+ RawImage& operator=(RawImage&& p) noexcept;
+
+ RawImageData* get() { return p_; }
+ private:
+ RawImageData* p_; // p_ is never NULL
+ };
+
+inline RawImage RawImage::create(RawImageType type) {
+ switch (type)
+ {
+ case TYPE_USHORT16:
+ return RawImage(new RawImageDataU16());
+ case TYPE_FLOAT32:
+ return RawImage(new RawImageDataFloat());
+ default:
+ writeLog(DEBUG_PRIO_ERROR, "RawImage::create: Unknown Image type!");
+ __builtin_unreachable();
+
+ }
+}
+
+inline RawImage RawImage::create(const iPoint2D& dim, RawImageType type, uint32 componentsPerPixel) {
+ switch (type) {
+ case TYPE_USHORT16:
+ return RawImage(new RawImageDataU16(dim, componentsPerPixel));
+ case TYPE_FLOAT32:
+ return RawImage(new RawImageDataFloat(dim, componentsPerPixel));
+ default:
+ writeLog(DEBUG_PRIO_ERROR, "RawImage::create: Unknown Image type!");
+ __builtin_unreachable();
+ }
+}
+
+// setWithLookUp will set a single pixel by using the lookup table if supplied,
+// You must supply the destination where the value should be written, and a pointer to
+// a value that will be used to store a random counter that can be reused between calls.
+// this needs to be inline to speed up tight decompressor loops
+inline void RawImageDataU16::setWithLookUp(ushort16 value, uchar8* dst, uint32* random) {
+ auto* dest = reinterpret_cast<ushort16*>(dst);
+ if (table == nullptr) {
+ *dest = value;
+ return;
+ }
+ if (table->dither) {
+ auto* t = reinterpret_cast<const uint32*>(table->tables.data());
+ uint32 lookup = t[value];
+ uint32 base = lookup & 0xffff;
+ uint32 delta = lookup >> 16;
+ uint32 r = *random;
+
+ uint32 pix = base + ((delta * (r&2047) + 1024) >> 12);
+ *random = 15700 *(r & 65535) + (r >> 16);
+ *dest = pix;
+ return;
+ }
+ *dest = table->tables[value];
+}
+
+class RawImageCurveGuard final {
+ RawImage* mRaw;
+ const std::vector<ushort16>& curve;
+ const bool uncorrectedRawValues;
+
+public:
+ RawImageCurveGuard(RawImage* raw, const std::vector<ushort16>& curve_,
+ bool uncorrectedRawValues_)
+ : mRaw(raw), curve(curve_), uncorrectedRawValues(uncorrectedRawValues_) {
+ if (uncorrectedRawValues)
+ return;
+
+ (*mRaw)->setTable(curve, true);
+ }
+
+ ~RawImageCurveGuard() {
+ // Set the table, if it should be needed later.
+ if (uncorrectedRawValues)
+ (*mRaw)->setTable(curve, false);
+ else
+ (*mRaw)->setTable(nullptr);
+ }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/RawImageDataFloat.cpp b/src/external/rawspeed/src/librawspeed/common/RawImageDataFloat.cpp
new file mode 100644
index 000000000..a2f40be6f
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/RawImageDataFloat.cpp
@@ -0,0 +1,392 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/RawImage.h" // for RawImageDataFloat, RawImag...
+#include "common/Common.h" // for uchar8, uint32, writeLog
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "metadata/BlackArea.h" // for BlackArea
+#include <algorithm> // for max, min
+#include <memory> // for operator==, unique_ptr
+#include <vector> // for vector
+
+using std::min;
+using std::max;
+
+namespace rawspeed {
+
+RawImageDataFloat::RawImageDataFloat() {
+ bpp = 4;
+ dataType = TYPE_FLOAT32;
+ }
+
+ RawImageDataFloat::RawImageDataFloat(const iPoint2D &_dim, uint32 _cpp)
+ : RawImageData(_dim, 4, _cpp) {
+ dataType = TYPE_FLOAT32;
+ }
+
+
+ void RawImageDataFloat::calculateBlackAreas() {
+ float accPixels[4] = {0,0,0,0};
+ int totalpixels = 0;
+
+ for (auto area : blackAreas) {
+ /* Make sure area sizes are multiple of two,
+ so we have the same amount of pixels for each CFA group */
+ area.size = area.size - (area.size&1);
+
+ /* Process horizontal area */
+ if (!area.isVertical) {
+ if (static_cast<int>(area.offset) + static_cast<int>(area.size) >
+ uncropped_dim.y)
+ ThrowRDE("Offset + size is larger than height of image");
+ for (uint32 y = area.offset; y < area.offset+area.size; y++) {
+ auto* pixel =
+ reinterpret_cast<float*>(getDataUncropped(mOffset.x, y));
+
+ for (int x = mOffset.x; x < dim.x + mOffset.x; x++) {
+ accPixels[((y & 1) << 1) | (x & 1)] += *pixel;
+ pixel++;
+ }
+ }
+ totalpixels += area.size * dim.x;
+ }
+
+ /* Process vertical area */
+ if (area.isVertical) {
+ if (static_cast<int>(area.offset) + static_cast<int>(area.size) >
+ uncropped_dim.x)
+ ThrowRDE("Offset + size is larger than width of image");
+ for (int y = mOffset.y; y < dim.y+mOffset.y; y++) {
+ auto* pixel =
+ reinterpret_cast<float*>(getDataUncropped(area.offset, y));
+
+ for (uint32 x = area.offset; x < area.size + area.offset; x++) {
+ accPixels[((y & 1) << 1) | (x & 1)] += *pixel;
+ pixel++;
+ }
+ }
+ totalpixels += area.size * dim.y;
+ }
+ }
+
+ if (!totalpixels) {
+ for (int &i : blackLevelSeparate)
+ i = blackLevel;
+ return;
+ }
+
+ /* Calculate median value of black areas for each component */
+ /* Adjust the number of total pixels so it is the same as the median of each histogram */
+ totalpixels /= 4;
+
+ for (int i = 0 ; i < 4; i++) {
+ blackLevelSeparate[i] =
+ static_cast<int>(65535.0F * accPixels[i] / totalpixels);
+ }
+
+ /* If this is not a CFA image, we do not use separate blacklevels, use average */
+ if (!isCFA) {
+ int total = 0;
+ for (int i : blackLevelSeparate)
+ total += i;
+ for (int &i : blackLevelSeparate)
+ i = (total + 2) >> 2;
+ }
+ }
+
+ void RawImageDataFloat::scaleBlackWhite() {
+ const int skipBorder = 150;
+ int gw = (dim.x - skipBorder) * cpp;
+ if ((blackAreas.empty() && blackLevelSeparate[0] < 0 && blackLevel < 0) || whitePoint == 65536) { // Estimate
+ float b = 100000000;
+ float m = -10000000;
+ for (int row = skipBorder*cpp;row < (dim.y - skipBorder);row++) {
+ auto* pixel = reinterpret_cast<float*>(getData(skipBorder, row));
+ for (int col = skipBorder ; col < gw ; col++) {
+ b = min(*pixel, b);
+ m = max(*pixel, m);
+ pixel++;
+ }
+ }
+ if (blackLevel < 0)
+ blackLevel = static_cast<int>(b);
+ if (whitePoint == 65536)
+ whitePoint = static_cast<int>(m);
+ writeLog(DEBUG_PRIO_INFO, "Estimated black:%d, Estimated white: %d",
+ blackLevel, whitePoint);
+ }
+
+ /* If filter has not set separate blacklevel, compute or fetch it */
+ if (blackLevelSeparate[0] < 0)
+ calculateBlackAreas();
+
+ startWorker(RawImageWorker::SCALE_VALUES, true);
+}
+
+#if 0 // def WITH_SSE2
+
+ void RawImageDataFloat::scaleValues(int start_y, int end_y) {
+ bool WITH_SSE2;
+#ifdef _MSC_VER
+ int info[4];
+ __cpuid(info, 1);
+ WITH_SSE2 = !!(info[3]&(1 << 26));
+#else
+ WITH_SSE2 = true;
+#endif
+
+ float app_scale = 65535.0F / (whitePoint - blackLevelSeparate[0]);
+ // Check SSE2
+ if (WITH_SSE2 && app_scale < 63) {
+
+ __m128i sseround;
+ __m128i ssesub2;
+ __m128i ssesign;
+ auto* sub_mul = alignedMallocArray<uint32, 16, __m128i>(4);
+ if (!sub_mul)
+ ThrowRDE("Out of memory, failed to allocate 128 bytes");
+
+ uint32 gw = pitch / 16;
+ // 10 bit fraction
+ uint32 mul = (int)(1024.0F * 65535.0F / (float)(whitePoint - blackLevelSeparate[mOffset.x&1]));
+ mul |= ((int)(1024.0F * 65535.0F / (float)(whitePoint - blackLevelSeparate[(mOffset.x+1)&1])))<<16;
+ uint32 b = blackLevelSeparate[mOffset.x&1] | (blackLevelSeparate[(mOffset.x+1)&1]<<16);
+
+ for (int i = 0; i< 4; i++) {
+ sub_mul[i] = b; // Subtract even lines
+ sub_mul[4+i] = mul; // Multiply even lines
+ }
+
+ mul = (int)(1024.0F * 65535.0F / (float)(whitePoint - blackLevelSeparate[2+(mOffset.x&1)]));
+ mul |= ((int)(1024.0F * 65535.0F / (float)(whitePoint - blackLevelSeparate[2+((mOffset.x+1)&1)])))<<16;
+ b = blackLevelSeparate[2+(mOffset.x&1)] | (blackLevelSeparate[2+((mOffset.x+1)&1)]<<16);
+
+ for (int i = 0; i< 4; i++) {
+ sub_mul[8+i] = b; // Subtract odd lines
+ sub_mul[12+i] = mul; // Multiply odd lines
+ }
+
+ sseround = _mm_set_epi32(512, 512, 512, 512);
+ ssesub2 = _mm_set_epi32(32768, 32768, 32768, 32768);
+ ssesign = _mm_set_epi32(0x80008000, 0x80008000, 0x80008000, 0x80008000);
+
+ for (int y = start_y; y < end_y; y++) {
+ __m128i* pixel = (__m128i*) & data[(mOffset.y+y)*pitch];
+ __m128i ssescale, ssesub;
+ if (((y+mOffset.y)&1) == 0) {
+ ssesub = _mm_load_si128((__m128i*)&sub_mul[0]);
+ ssescale = _mm_load_si128((__m128i*)&sub_mul[4]);
+ } else {
+ ssesub = _mm_load_si128((__m128i*)&sub_mul[8]);
+ ssescale = _mm_load_si128((__m128i*)&sub_mul[12]);
+ }
+
+ for (uint32 x = 0 ; x < gw; x++) {
+ __m128i pix_high;
+ __m128i temp;
+ _mm_prefetch((char*)(pixel+1), _MM_HINT_T0);
+ __m128i pix_low = _mm_load_si128(pixel);
+ // Subtract black
+ pix_low = _mm_subs_epu16(pix_low, ssesub);
+ // Multiply the two unsigned shorts and combine it to 32 bit result
+ pix_high = _mm_mulhi_epu16(pix_low, ssescale);
+ temp = _mm_mullo_epi16(pix_low, ssescale);
+ pix_low = _mm_unpacklo_epi16(temp, pix_high);
+ pix_high = _mm_unpackhi_epi16(temp, pix_high);
+ // Add rounder
+ pix_low = _mm_add_epi32(pix_low, sseround);
+ pix_high = _mm_add_epi32(pix_high, sseround);
+ // Shift down
+ pix_low = _mm_srai_epi32(pix_low, 10);
+ pix_high = _mm_srai_epi32(pix_high, 10);
+ // Subtract to avoid clipping
+ pix_low = _mm_sub_epi32(pix_low, ssesub2);
+ pix_high = _mm_sub_epi32(pix_high, ssesub2);
+ // Pack
+ pix_low = _mm_packs_epi32(pix_low, pix_high);
+ // Shift sign off
+ pix_low = _mm_xor_si128(pix_low, ssesign);
+ _mm_store_si128(pixel, pix_low);
+ pixel++;
+ }
+ }
+ alignedFree(sub_mul);
+ } else {
+ // Not SSE2
+ int gw = dim.x * cpp;
+ int mul[4];
+ int sub[4];
+ for (int i = 0; i < 4; i++) {
+ int v = i;
+ if ((mOffset.x&1) != 0)
+ v ^= 1;
+ if ((mOffset.y&1) != 0)
+ v ^= 2;
+ mul[i] = (int)(16384.0F * 65535.0F / (float)(whitePoint - blackLevelSeparate[v]));
+ sub[i] = blackLevelSeparate[v];
+ }
+ for (int y = start_y; y < end_y; y++) {
+ ushort16 *pixel = (ushort16*)getData(0, y);
+ int *mul_local = &mul[2*(y&1)];
+ int *sub_local = &sub[2*(y&1)];
+ for (int x = 0 ; x < gw; x++) {
+ pixel[x] = clampBits(((pixel[x] - sub_local[x&1]) * mul_local[x&1] + 8192) >> 14, 16);
+ }
+ }
+ }
+ }
+
+#else
+
+ void RawImageDataFloat::scaleValues(int start_y, int end_y) {
+ int gw = dim.x * cpp;
+ float mul[4];
+ float sub[4];
+ for (int i = 0; i < 4; i++) {
+ int v = i;
+ if ((mOffset.x&1) != 0)
+ v ^= 1;
+ if ((mOffset.y&1) != 0)
+ v ^= 2;
+ mul[i] =
+ 65535.0F / static_cast<float>(whitePoint - blackLevelSeparate[v]);
+ sub[i] = static_cast<float>(blackLevelSeparate[v]);
+ }
+ for (int y = start_y; y < end_y; y++) {
+ auto* pixel = reinterpret_cast<float*>(getData(0, y));
+ float *mul_local = &mul[2*(y&1)];
+ float *sub_local = &sub[2*(y&1)];
+ for (int x = 0 ; x < gw; x++) {
+ pixel[x] = (pixel[x] - sub_local[x&1]) * mul_local[x&1];
+ }
+ }
+ }
+
+#endif
+
+ /* This performs a 4 way interpolated pixel */
+ /* The value is interpolated from the 4 closest valid pixels in */
+ /* the horizontal and vertical direction. Pixels found further away */
+ /* are weighed less */
+
+void RawImageDataFloat::fixBadPixel( uint32 x, uint32 y, int component )
+{
+ float values[4];
+ float dist[4];
+ float weight[4];
+
+ values[0] = values[1] = values[2] = values[3] = -1;
+ dist[0] = dist[1] = dist[2] = dist[3] = 0;
+ uchar8* bad_line = &mBadPixelMap[y*mBadPixelMapPitch];
+
+ // Find pixel to the left
+ int x_find = static_cast<int>(x) - 2;
+ int curr = 0;
+ while (x_find >= 0 && values[curr] < 0) {
+ if (0 == ((bad_line[x_find>>3] >> (x_find&7)) & 1)) {
+ values[curr] = (reinterpret_cast<float*>(getData(x_find, y)))[component];
+ dist[curr] = static_cast<float>(static_cast<int>(x) - x_find);
+ }
+ x_find-=2;
+ }
+ // Find pixel to the right
+ x_find = static_cast<int>(x) + 2;
+ curr = 1;
+ while (x_find < uncropped_dim.x && values[curr] < 0) {
+ if (0 == ((bad_line[x_find>>3] >> (x_find&7)) & 1)) {
+ values[curr] = (reinterpret_cast<float*>(getData(x_find, y)))[component];
+ dist[curr] = static_cast<float>(x_find - static_cast<int>(x));
+ }
+ x_find+=2;
+ }
+
+ bad_line = &mBadPixelMap[x>>3];
+ // Find pixel upwards
+ int y_find = static_cast<int>(y) - 2;
+ curr = 2;
+ while (y_find >= 0 && values[curr] < 0) {
+ if (0 == ((bad_line[y_find*mBadPixelMapPitch] >> (x&7)) & 1)) {
+ values[curr] = (reinterpret_cast<float*>(getData(x, y_find)))[component];
+ dist[curr] = static_cast<float>(static_cast<int>(y) - y_find);
+ }
+ y_find-=2;
+ }
+ // Find pixel downwards
+ y_find = static_cast<int>(y) + 2;
+ curr = 3;
+ while (y_find < uncropped_dim.y && values[curr] < 0) {
+ if (0 == ((bad_line[y_find*mBadPixelMapPitch] >> (x&7)) & 1)) {
+ values[curr] = (reinterpret_cast<float*>(getData(x, y_find)))[component];
+ dist[curr] = static_cast<float>(y_find - static_cast<int>(y));
+ }
+ y_find+=2;
+ }
+ // Find x weights
+ float total_dist_x = dist[0] + dist[1];
+
+ float total_div = 0.000001F;
+ if (total_dist_x) {
+ weight[0] = dist[0] > 0.0F ? (total_dist_x - dist[0]) / total_dist_x : 0;
+ weight[1] = 1.0F - weight[0];
+ total_div += 1;
+ }
+
+ // Find y weights
+ float total_dist_y = dist[2] + dist[3];
+ if (total_dist_y) {
+ weight[2] = dist[2] > 0.0F ? (total_dist_y - dist[2]) / total_dist_y : 0;
+ weight[3] = 1.0F - weight[2];
+ total_div += 1;
+ }
+
+
+ float total_pixel = 0;
+ for (int i = 0; i < 4; i++)
+ if (values[i] >= 0)
+ total_pixel += values[i] * dist[i];
+
+ total_pixel /= total_div;
+ auto* pix = reinterpret_cast<float*>(getDataUncropped(x, y));
+ pix[component] = total_pixel;
+
+ /* Process other pixels - could be done inline, since we have the weights */
+ if (cpp > 1 && component == 0)
+ for (int i = 1; i < static_cast<int>(cpp); i++)
+ fixBadPixel(x,y,i);
+
+}
+
+
+void RawImageDataFloat::doLookup( int start_y, int end_y ) {
+ ThrowRDE("Float point lookup tables not implemented");
+}
+
+void RawImageDataFloat::setWithLookUp(ushort16 value, uchar8* dst, uint32* random) {
+ auto* dest = reinterpret_cast<float*>(dst);
+ if (table == nullptr) {
+ *dest = static_cast<float>(value) * (1.0F / 65535);
+ return;
+ }
+
+ ThrowRDE("Float point lookup tables not implemented");
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/RawImageDataU16.cpp b/src/external/rawspeed/src/librawspeed/common/RawImageDataU16.cpp
new file mode 100644
index 000000000..7570f6b5d
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/RawImageDataU16.cpp
@@ -0,0 +1,512 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h" // for WITH_SSE2
+#include "common/RawImage.h" // for RawImageDataU16, TableLookUp
+#include "common/Common.h" // for ushort16, uint32, uchar8
+#include "common/Memory.h" // for alignedFree, alignedMalloc...
+#include "common/Point.h" // for iPoint2D
+#include "common/TableLookUp.h" // for TableLookUp
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "metadata/BlackArea.h" // for BlackArea
+#include <algorithm> // for fill, max, min
+#include <array> // for array
+#include <cassert> // for assert
+#include <memory> // for operator==, unique_ptr
+#include <vector> // for vector
+
+#ifdef WITH_SSE2
+#include "common/Cpuid.h" // for Cpuid
+#include <emmintrin.h> // for __m128i, _mm_load_si128
+#include <xmmintrin.h> // for _MM_HINT_T0, _mm_prefetch
+#endif
+
+using std::vector;
+using std::min;
+using std::max;
+using std::array;
+
+namespace rawspeed {
+
+RawImageDataU16::RawImageDataU16() {
+ dataType = TYPE_USHORT16;
+ bpp = 2;
+}
+
+RawImageDataU16::RawImageDataU16(const iPoint2D &_dim, uint32 _cpp)
+ : RawImageData(_dim, 2, _cpp) {
+ dataType = TYPE_USHORT16;
+}
+
+
+void RawImageDataU16::calculateBlackAreas() {
+ vector<unsigned int> histogram(4 * 65536);
+ fill(histogram.begin(), histogram.end(), 0);
+
+ int totalpixels = 0;
+
+ for (auto area : blackAreas) {
+ /* Make sure area sizes are multiple of two,
+ so we have the same amount of pixels for each CFA group */
+ area.size = area.size - (area.size&1);
+
+ /* Process horizontal area */
+ if (!area.isVertical) {
+ if (static_cast<int>(area.offset) + static_cast<int>(area.size) >
+ uncropped_dim.y)
+ ThrowRDE("Offset + size is larger than height of image");
+ for (uint32 y = area.offset; y < area.offset+area.size; y++) {
+ auto* pixel =
+ reinterpret_cast<ushort16*>(getDataUncropped(mOffset.x, y));
+ auto* localhist = &histogram[(y & 1) * (65536UL * 2UL)];
+ for (int x = mOffset.x; x < dim.x+mOffset.x; x++) {
+ const auto hBin = ((x & 1) << 16) + *pixel;
+ localhist[hBin]++;
+ }
+ }
+ totalpixels += area.size * dim.x;
+ }
+
+ /* Process vertical area */
+ if (area.isVertical) {
+ if (static_cast<int>(area.offset) + static_cast<int>(area.size) >
+ uncropped_dim.x)
+ ThrowRDE("Offset + size is larger than width of image");
+ for (int y = mOffset.y; y < dim.y+mOffset.y; y++) {
+ auto* pixel =
+ reinterpret_cast<ushort16*>(getDataUncropped(area.offset, y));
+ auto* localhist = &histogram[(y & 1) * (65536UL * 2UL)];
+ for (uint32 x = area.offset; x < area.size+area.offset; x++) {
+ const auto hBin = ((x & 1) << 16) + *pixel;
+ localhist[hBin]++;
+ }
+ }
+ totalpixels += area.size * dim.y;
+ }
+ }
+
+ if (!totalpixels) {
+ for (int &i : blackLevelSeparate)
+ i = blackLevel;
+ return;
+ }
+
+ /* Calculate median value of black areas for each component */
+ /* Adjust the number of total pixels so it is the same as the median of each histogram */
+ totalpixels /= 4*2;
+
+ for (int i = 0 ; i < 4; i++) {
+ auto* localhist = &histogram[i * 65536UL];
+ int acc_pixels = localhist[0];
+ int pixel_value = 0;
+ while (acc_pixels <= totalpixels && pixel_value < 65535) {
+ pixel_value++;
+ acc_pixels += localhist[pixel_value];
+ }
+ blackLevelSeparate[i] = pixel_value;
+ }
+
+ /* If this is not a CFA image, we do not use separate blacklevels, use average */
+ if (!isCFA) {
+ int total = 0;
+ for (int i : blackLevelSeparate)
+ total += i;
+ for (int &i : blackLevelSeparate)
+ i = (total + 2) >> 2;
+ }
+}
+
+void RawImageDataU16::scaleBlackWhite() {
+ const int skipBorder = 250;
+ int gw = (dim.x - skipBorder) * cpp;
+ if ((blackAreas.empty() && blackLevelSeparate[0] < 0 && blackLevel < 0) || whitePoint >= 65536) { // Estimate
+ int b = 65536;
+ int m = 0;
+ for (int row = skipBorder; row < (dim.y - skipBorder);row++) {
+ auto* pixel = reinterpret_cast<ushort16*>(getData(skipBorder, row));
+ for (int col = skipBorder ; col < gw ; col++) {
+ b = min(static_cast<int>(*pixel), b);
+ m = max(static_cast<int>(*pixel), m);
+ pixel++;
+ }
+ }
+ if (blackLevel < 0)
+ blackLevel = b;
+ if (whitePoint >= 65536)
+ whitePoint = m;
+ writeLog(DEBUG_PRIO_INFO, "ISO:%d, Estimated black:%d, Estimated white: %d",
+ metadata.isoSpeed, blackLevel, whitePoint);
+ }
+
+ /* Skip, if not needed */
+ if ((blackAreas.empty() && blackLevel == 0 && whitePoint == 65535 &&
+ blackLevelSeparate[0] < 0) ||
+ dim.area() <= 0)
+ return;
+
+ /* If filter has not set separate blacklevel, compute or fetch it */
+ if (blackLevelSeparate[0] < 0)
+ calculateBlackAreas();
+
+ startWorker(RawImageWorker::SCALE_VALUES, true);
+}
+
+void RawImageDataU16::scaleValues(int start_y, int end_y) {
+#ifndef WITH_SSE2
+
+ return scaleValues_plain(start_y, end_y);
+
+#else
+
+ int depth_values = whitePoint - blackLevelSeparate[0];
+ float app_scale = 65535.0F / depth_values;
+
+ // Check SSE2
+ if (Cpuid::SSE2() && app_scale < 63) {
+ scaleValues_SSE2(start_y, end_y);
+ } else {
+ scaleValues_plain(start_y, end_y);
+ }
+
+#endif
+}
+
+#ifdef WITH_SSE2
+void RawImageDataU16::scaleValues_SSE2(int start_y, int end_y) {
+ int depth_values = whitePoint - blackLevelSeparate[0];
+ float app_scale = 65535.0F / depth_values;
+
+ // Scale in 30.2 fp
+ auto full_scale_fp = static_cast<int>(app_scale * 4.0F);
+ // Half Scale in 18.14 fp
+ auto half_scale_fp = static_cast<int>(app_scale * 4095.0F);
+
+ __m128i sseround;
+ __m128i ssesub2;
+ __m128i ssesign;
+ __m128i rand_mul;
+ __m128i rand_mask;
+ __m128i sse_full_scale_fp;
+ __m128i sse_half_scale_fp;
+
+ auto* sub_mul = alignedMallocArray<uint32, 16, __m128i>(4);
+ if (!sub_mul)
+ ThrowRDE("Out of memory, failed to allocate 128 bytes");
+
+ assert(sub_mul != nullptr);
+
+ uint32 gw = pitch / 16;
+ // 10 bit fraction
+ uint32 mul = static_cast<int>(
+ 1024.0F * 65535.0F /
+ static_cast<float>(whitePoint - blackLevelSeparate[mOffset.x & 1]));
+ mul |= (static_cast<int>(
+ 1024.0F * 65535.0F /
+ static_cast<float>(whitePoint -
+ blackLevelSeparate[(mOffset.x + 1) & 1])))
+ << 16;
+ uint32 b = blackLevelSeparate[mOffset.x & 1] |
+ (blackLevelSeparate[(mOffset.x + 1) & 1] << 16);
+
+ for (int i = 0; i < 4; i++) {
+ sub_mul[i] = b; // Subtract even lines
+ sub_mul[4 + i] = mul; // Multiply even lines
+ }
+
+ mul = static_cast<int>(
+ 1024.0F * 65535.0F /
+ static_cast<float>(whitePoint - blackLevelSeparate[2 + (mOffset.x & 1)]));
+ mul |= (static_cast<int>(
+ 1024.0F * 65535.0F /
+ static_cast<float>(whitePoint -
+ blackLevelSeparate[2 + ((mOffset.x + 1) & 1)])))
+ << 16;
+ b = blackLevelSeparate[2 + (mOffset.x & 1)] |
+ (blackLevelSeparate[2 + ((mOffset.x + 1) & 1)] << 16);
+
+ for (int i = 0; i < 4; i++) {
+ sub_mul[8 + i] = b; // Subtract odd lines
+ sub_mul[12 + i] = mul; // Multiply odd lines
+ }
+
+ sseround = _mm_set_epi32(512, 512, 512, 512);
+ ssesub2 = _mm_set_epi32(32768, 32768, 32768, 32768);
+ ssesign = _mm_set_epi32(0x80008000, 0x80008000, 0x80008000, 0x80008000);
+ sse_full_scale_fp = _mm_set1_epi32(full_scale_fp | (full_scale_fp << 16));
+ sse_half_scale_fp = _mm_set1_epi32(half_scale_fp >> 4);
+
+ if (mDitherScale) {
+ rand_mul = _mm_set1_epi32(0x4d9f1d32);
+ } else {
+ rand_mul = _mm_set1_epi32(0);
+ }
+ rand_mask = _mm_set1_epi32(0x00ff00ff); // 8 random bits
+
+ for (int y = start_y; y < end_y; y++) {
+ __m128i sserandom;
+ if (mDitherScale) {
+ sserandom =
+ _mm_set_epi32(dim.x * 1676 + y * 18000, dim.x * 2342 + y * 34311,
+ dim.x * 4272 + y * 12123, dim.x * 1234 + y * 23464);
+ } else {
+ sserandom = _mm_setzero_si128();
+ }
+ auto* pixel = reinterpret_cast<__m128i*>(&data[(mOffset.y + y) * pitch]);
+ __m128i ssescale;
+ __m128i ssesub;
+ if (((y + mOffset.y) & 1) == 0) {
+ ssesub = _mm_load_si128(reinterpret_cast<__m128i*>(&sub_mul[0]));
+ ssescale = _mm_load_si128(reinterpret_cast<__m128i*>(&sub_mul[4]));
+ } else {
+ ssesub = _mm_load_si128(reinterpret_cast<__m128i*>(&sub_mul[8]));
+ ssescale = _mm_load_si128(reinterpret_cast<__m128i*>(&sub_mul[12]));
+ }
+
+ for (uint32 x = 0; x < gw; x++) {
+ __m128i pix_high;
+ __m128i temp;
+ _mm_prefetch(reinterpret_cast<char*>(pixel + 1), _MM_HINT_T0);
+ __m128i pix_low = _mm_load_si128(pixel);
+ // Subtract black
+ pix_low = _mm_subs_epu16(pix_low, ssesub);
+ // Multiply the two unsigned shorts and combine it to 32 bit result
+ pix_high = _mm_mulhi_epu16(pix_low, ssescale);
+ temp = _mm_mullo_epi16(pix_low, ssescale);
+ pix_low = _mm_unpacklo_epi16(temp, pix_high);
+ pix_high = _mm_unpackhi_epi16(temp, pix_high);
+ // Add rounder
+ pix_low = _mm_add_epi32(pix_low, sseround);
+ pix_high = _mm_add_epi32(pix_high, sseround);
+
+ sserandom = _mm_xor_si128(_mm_mulhi_epi16(sserandom, rand_mul),
+ _mm_mullo_epi16(sserandom, rand_mul));
+ __m128i rand_masked =
+ _mm_and_si128(sserandom, rand_mask); // Get 8 random bits
+ rand_masked = _mm_mullo_epi16(rand_masked, sse_full_scale_fp);
+
+ __m128i zero = _mm_setzero_si128();
+ __m128i rand_lo = _mm_sub_epi32(sse_half_scale_fp,
+ _mm_unpacklo_epi16(rand_masked, zero));
+ __m128i rand_hi = _mm_sub_epi32(sse_half_scale_fp,
+ _mm_unpackhi_epi16(rand_masked, zero));
+
+ pix_low = _mm_add_epi32(pix_low, rand_lo);
+ pix_high = _mm_add_epi32(pix_high, rand_hi);
+
+ // Shift down
+ pix_low = _mm_srai_epi32(pix_low, 10);
+ pix_high = _mm_srai_epi32(pix_high, 10);
+ // Subtract to avoid clipping
+ pix_low = _mm_sub_epi32(pix_low, ssesub2);
+ pix_high = _mm_sub_epi32(pix_high, ssesub2);
+ // Pack
+ pix_low = _mm_packs_epi32(pix_low, pix_high);
+ // Shift sign off
+ pix_low = _mm_xor_si128(pix_low, ssesign);
+ _mm_store_si128(pixel, pix_low);
+ pixel++;
+ }
+ }
+ alignedFree(sub_mul);
+}
+#endif
+
+void RawImageDataU16::scaleValues_plain(int start_y, int end_y) {
+ int depth_values = whitePoint - blackLevelSeparate[0];
+ float app_scale = 65535.0F / depth_values;
+
+ // Scale in 30.2 fp
+ auto full_scale_fp = static_cast<int>(app_scale * 4.0F);
+ // Half Scale in 18.14 fp
+ auto half_scale_fp = static_cast<int>(app_scale * 4095.0F);
+
+ // Not SSE2
+ int gw = dim.x * cpp;
+ int mul[4];
+ int sub[4];
+ for (int i = 0; i < 4; i++) {
+ int v = i;
+ if ((mOffset.x & 1) != 0)
+ v ^= 1;
+ if ((mOffset.y & 1) != 0)
+ v ^= 2;
+ mul[i] = static_cast<int>(
+ 16384.0F * 65535.0F /
+ static_cast<float>(whitePoint - blackLevelSeparate[v]));
+ sub[i] = blackLevelSeparate[v];
+ }
+ for (int y = start_y; y < end_y; y++) {
+ int v = dim.x + y * 36969;
+ auto* pixel = reinterpret_cast<ushort16*>(getData(0, y));
+ int* mul_local = &mul[2 * (y & 1)];
+ int* sub_local = &sub[2 * (y & 1)];
+ for (int x = 0; x < gw; x++) {
+ int rand;
+ if (mDitherScale) {
+ v = 18000 * (v & 65535) + (v >> 16);
+ rand = half_scale_fp - (full_scale_fp * (v & 2047));
+ } else {
+ rand = 0;
+ }
+ pixel[x] = clampBits(
+ ((pixel[x] - sub_local[x & 1]) * mul_local[x & 1] + 8192 + rand) >>
+ 14,
+ 16);
+ }
+ }
+}
+
+/* This performs a 4 way interpolated pixel */
+/* The value is interpolated from the 4 closest valid pixels in */
+/* the horizontal and vertical direction. Pixels found further away */
+/* are weighed less */
+
+void RawImageDataU16::fixBadPixel( uint32 x, uint32 y, int component )
+{
+ array<int, 4> values;
+ array<int, 4> dist;
+ array<int, 4> weight;
+
+ values.fill(-1);
+ dist.fill(0);
+ weight.fill(0);
+
+ uchar8* bad_line = &mBadPixelMap[y*mBadPixelMapPitch];
+ int step = isCFA ? 2 : 1;
+
+ // Find pixel to the left
+ int x_find = static_cast<int>(x) - step;
+ int curr = 0;
+ while (x_find >= 0 && values[curr] < 0) {
+ if (0 == ((bad_line[x_find>>3] >> (x_find&7)) & 1)) {
+ values[curr] =
+ (reinterpret_cast<ushort16*>(getDataUncropped(x_find, y)))[component];
+ dist[curr] = static_cast<int>(x) - x_find;
+ }
+ x_find -= step;
+ }
+ // Find pixel to the right
+ x_find = static_cast<int>(x) + step;
+ curr = 1;
+ while (x_find < uncropped_dim.x && values[curr] < 0) {
+ if (0 == ((bad_line[x_find>>3] >> (x_find&7)) & 1)) {
+ values[curr] =
+ (reinterpret_cast<ushort16*>(getDataUncropped(x_find, y)))[component];
+ dist[curr] = x_find - static_cast<int>(x);
+ }
+ x_find += step;
+ }
+
+ bad_line = &mBadPixelMap[x>>3];
+ // Find pixel upwards
+ int y_find = static_cast<int>(y) - step;
+ curr = 2;
+ while (y_find >= 0 && values[curr] < 0) {
+ if (0 == ((bad_line[y_find*mBadPixelMapPitch] >> (x&7)) & 1)) {
+ values[curr] =
+ (reinterpret_cast<ushort16*>(getDataUncropped(x, y_find)))[component];
+ dist[curr] = static_cast<int>(y) - y_find;
+ }
+ y_find -= step;
+ }
+ // Find pixel downwards
+ y_find = static_cast<int>(y) + step;
+ curr = 3;
+ while (y_find < uncropped_dim.y && values[curr] < 0) {
+ if (0 == ((bad_line[y_find*mBadPixelMapPitch] >> (x&7)) & 1)) {
+ values[curr] =
+ (reinterpret_cast<ushort16*>(getDataUncropped(x, y_find)))[component];
+ dist[curr] = y_find - static_cast<int>(y);
+ }
+ y_find += step;
+ }
+
+ // Find x weights
+ int total_dist_x = dist[0] + dist[1];
+
+ int total_shifts = 7;
+ if (total_dist_x) {
+ weight[0] = dist[0] ? (total_dist_x - dist[0]) * 256 / total_dist_x : 0;
+ weight[1] = 256 - weight[0];
+ total_shifts++;
+ }
+
+ // Find y weights
+ int total_dist_y = dist[2] + dist[3];
+ if (total_dist_y) {
+ weight[2] = dist[2] ? (total_dist_y - dist[2]) * 256 / total_dist_y : 0;
+ weight[3] = 256-weight[2];
+ total_shifts++;
+ }
+
+ int total_pixel = 0;
+ for (int i = 0; i < 4; i++)
+ if (values[i] >= 0)
+ total_pixel += values[i] * weight[i];
+
+ total_pixel >>= total_shifts;
+ auto* pix = reinterpret_cast<ushort16*>(getDataUncropped(x, y));
+ pix[component] = clampBits(total_pixel, 16);
+
+ /* Process other pixels - could be done inline, since we have the weights */
+ if (cpp > 1 && component == 0)
+ for (int i = 1; i < static_cast<int>(cpp); i++)
+ fixBadPixel(x,y,i);
+}
+
+// TODO: Could be done with SSE2
+void RawImageDataU16::doLookup( int start_y, int end_y )
+{
+ if (table->ntables == 1) {
+ if (table->dither) {
+ int gw = uncropped_dim.x * cpp;
+ auto* t = reinterpret_cast<uint32*>(table->getTable(0));
+ for (int y = start_y; y < end_y; y++) {
+ uint32 v = (uncropped_dim.x + y * 13) ^ 0x45694584;
+ auto* pixel = reinterpret_cast<ushort16*>(getDataUncropped(0, y));
+ for (int x = 0 ; x < gw; x++) {
+ ushort16 p = *pixel;
+ uint32 lookup = t[p];
+ uint32 base = lookup & 0xffff;
+ uint32 delta = lookup >> 16;
+ v = 15700 *(v & 65535) + (v >> 16);
+ uint32 pix = base + ((delta * (v & 2047) + 1024) >> 12);
+ *pixel = pix;
+ pixel++;
+ }
+ }
+ return;
+ }
+
+ int gw = uncropped_dim.x * cpp;
+ ushort16 *t = table->getTable(0);
+ for (int y = start_y; y < end_y; y++) {
+ auto* pixel = reinterpret_cast<ushort16*>(getDataUncropped(0, y));
+ for (int x = 0 ; x < gw; x++) {
+ *pixel = t[*pixel];
+ pixel ++;
+ }
+ }
+ return;
+ }
+ ThrowRDE("Table lookup with multiple components not implemented");
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/RawspeedException.h b/src/external/rawspeed/src/librawspeed/common/RawspeedException.h
new file mode 100644
index 000000000..28a72f86b
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/RawspeedException.h
@@ -0,0 +1,90 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h"
+
+#include "common/Common.h"
+#include <cstdarg>
+#include <cstdio>
+#include <stdexcept>
+#include <string>
+
+namespace rawspeed {
+
+template <typename T>
+[[noreturn]] void __attribute__((noreturn, noinline, format(printf, 1, 2)))
+ThrowException(const char* fmt, ...) {
+ static constexpr size_t bufSize = 8192;
+#if defined(HAVE_CXX_THREAD_LOCAL)
+ static thread_local char buf[bufSize];
+#elif defined(HAVE_GCC_THREAD_LOCAL)
+ static __thread char buf[bufSize];
+#else
+#pragma message \
+ "Don't have thread-local-storage! Exception text may be garbled if used multithreaded"
+ static char buf[bufSize];
+#endif
+
+ va_list val;
+ va_start(val, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, val);
+ va_end(val);
+ writeLog(DEBUG_PRIO_EXTRA, "EXCEPTION: %s", buf);
+ throw T(buf);
+}
+
+class RawspeedException : public std::runtime_error {
+private:
+ void log(const char* msg) {
+ writeLog(DEBUG_PRIO_EXTRA, "EXCEPTION: %s", msg);
+ }
+
+public:
+ explicit RawspeedException(const std::string& msg) : std::runtime_error(msg) {
+ log(msg.c_str());
+ }
+ explicit RawspeedException(const char* msg) : std::runtime_error(msg) {
+ log(msg);
+ }
+};
+
+#undef XSTR
+#define XSTR(a) #a
+
+#undef STR
+#define STR(a) XSTR(a)
+
+#ifndef DEBUG
+#define ThrowExceptionHelper(CLASS, fmt, ...) \
+ rawspeed::ThrowException<CLASS>("%s, line " STR(__LINE__) ": " fmt, \
+ __PRETTY_FUNCTION__, ##__VA_ARGS__)
+#else
+#define ThrowExceptionHelper(CLASS, fmt, ...) \
+ rawspeed::ThrowException<CLASS>(__FILE__ ":" STR(__LINE__) ": %s: " fmt, \
+ __PRETTY_FUNCTION__, ##__VA_ARGS__)
+#endif
+
+#define ThrowRSE(...) \
+ ThrowExceptionHelper(rawspeed::RawspeedException, __VA_ARGS__)
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/Spline.h b/src/external/rawspeed/src/librawspeed/common/Spline.h
new file mode 100644
index 000000000..fa87f585e
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/Spline.h
@@ -0,0 +1,177 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Robert Bieber
+ Copyright (C) 2018 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for ushort16
+#include "common/Point.h" // for iPoint2D
+#include <algorithm> // for adjacent_find
+#include <algorithm> // for min, max
+#include <cassert> // for assert
+#include <limits> // for numeric_limits
+#include <type_traits> // for enable_if_t, is_arithmetic
+#include <vector> // for vector
+
+namespace rawspeed {
+
+// This is a Natural Cubic Spline. The second derivative at curve ends are zero.
+// See https://en.wikipedia.org/wiki/Spline_(mathematics)
+// section "Algorithm for computing natural cubic splines"
+
+template <typename T = ushort16,
+ typename = std::enable_if_t<std::is_arithmetic<T>::value>>
+class Spline final {
+public:
+ using value_type = T;
+
+ // These are the constant factors for each segment of the curve.
+ // Each segment i will have the formula:
+ // f(x) = a[i] + b[i]*(x - x[i]) + c[i]*(x - x[i])^2 + d[i]*(x - x[i])^3
+ struct Segment {
+ double a;
+ double b;
+ double c;
+ double d;
+ };
+
+private:
+ int num_coords;
+ int num_segments;
+
+ std::vector<int> xCp;
+ std::vector<Segment> segments;
+
+ void prepare() {
+ // Extra values used during computation
+ std::vector<double> h(num_segments);
+ std::vector<double> alpha(num_segments);
+ std::vector<double> mu(num_coords);
+ std::vector<double> z(num_coords);
+
+ for (int i = 0; i < num_segments; i++)
+ h[i] = xCp[i + 1] - xCp[i];
+
+ for (int i = 1; i < num_segments; i++) {
+ Segment& sp = segments[i - 1];
+ Segment& s = segments[i];
+ Segment& sn = segments[i + 1];
+
+ alpha[i] = (3. / h[i]) * (sn.a - s.a) - (3. / h[i - 1]) * (s.a - sp.a);
+ }
+
+ mu[0] = z[0] = 0;
+
+ for (int i = 1; i < num_segments; i++) {
+ const double l = 2 * (xCp[i + 1] - xCp[i - 1]) - (h[i - 1] * mu[i - 1]);
+ mu[i] = h[i] / l;
+ z[i] = (alpha[i] - h[i - 1] * z[i - 1]) / l;
+ }
+
+ z.back() = segments.back().c = 0;
+
+ for (int i = num_segments - 1; i >= 0; i--) {
+ Segment& s = segments[i];
+ Segment& sn = segments[i + 1];
+
+ s.c = z[i] - mu[i] * sn.c;
+ s.b = (sn.a - s.a) / h[i] - h[i] * (sn.c + 2 * s.c) / 3.;
+ s.d = (sn.c - s.c) / (3. * h[i]);
+ }
+
+ // The last segment is nonsensical, and was only used to temporairly store
+ // the a and c to simplify calculations, so drop that 'segment' now
+ segments.pop_back();
+
+ assert(static_cast<typename decltype(segments)::size_type>(num_segments) ==
+ segments.size());
+ }
+
+public:
+ explicit Spline(const std::vector<iPoint2D>& control_points) {
+ assert(control_points.size() >= 2 &&
+ "Need at least two points to interpolate between");
+
+ // Expect the X coords of the curve to start/end at the extreme values
+ assert(control_points.front().x == 0);
+ assert(control_points.back().x == 65535);
+
+ assert(std::adjacent_find(
+ control_points.cbegin(), control_points.cend(),
+ [](const iPoint2D& lhs, const iPoint2D& rhs) -> bool {
+ return std::greater_equal<>()(lhs.x, rhs.x);
+ }) == control_points.cend() &&
+ "The X coordinates must all be strictly increasing");
+
+#ifndef NDEBUG
+ if (!std::is_floating_point<value_type>::value) {
+ // The Y coords must be limited to the range of value_type
+ std::for_each(control_points.cbegin(), control_points.cend(),
+ [](const iPoint2D& p) -> void {
+ assert(p.y >= std::numeric_limits<value_type>::min());
+ assert(p.y <= std::numeric_limits<value_type>::max());
+ });
+ }
+#endif
+
+ num_coords = control_points.size();
+ num_segments = num_coords - 1;
+
+ xCp.resize(num_coords);
+ segments.resize(num_coords);
+ for (int i = 0; i < num_coords; i++) {
+ xCp[i] = control_points[i].x;
+ segments[i].a = control_points[i].y;
+ }
+
+ prepare();
+ }
+
+ std::vector<Segment> getSegments() const { return segments; }
+
+ std::vector<value_type> calculateCurve() const {
+ std::vector<value_type> curve(65536);
+
+ for (int i = 0; i < num_segments; i++) {
+ const Segment& s = segments[i];
+
+ for (int x = xCp[i]; x <= xCp[i + 1]; x++) {
+ double diff = x - xCp[i];
+ double diff_2 = diff * diff;
+ double diff_3 = diff * diff * diff;
+
+ double interpolated = s.a + s.b * diff + s.c * diff_2 + s.d * diff_3;
+
+ if (!std::is_floating_point<value_type>::value) {
+ interpolated = std::max(
+ interpolated, double(std::numeric_limits<value_type>::min()));
+ interpolated = std::min(
+ interpolated, double(std::numeric_limits<value_type>::max()));
+ }
+
+ curve[x] = interpolated;
+ }
+ }
+
+ return curve;
+ }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/TableLookUp.cpp b/src/external/rawspeed/src/librawspeed/common/TableLookUp.cpp
new file mode 100644
index 000000000..abaeec3a4
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/TableLookUp.cpp
@@ -0,0 +1,80 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/TableLookUp.h"
+#include "decoders/RawDecoderException.h" // for RawDecoderException (ptr o...
+#include <cassert> // for assert
+
+namespace rawspeed {
+
+const int TABLE_SIZE = 65536 * 2;
+
+// Creates n numre of tables.
+TableLookUp::TableLookUp(int _ntables, bool _dither)
+ : ntables(_ntables), dither(_dither) {
+ if (ntables < 1) {
+ ThrowRDE("Cannot construct 0 tables");
+ }
+ tables.resize(ntables * TABLE_SIZE, ushort16(0));
+}
+
+void TableLookUp::setTable(int ntable, const std::vector<ushort16>& table) {
+ assert(!table.empty());
+
+ const int nfilled = table.size();
+ if (nfilled >= 65536)
+ ThrowRDE("Table lookup with %i entries is unsupported", nfilled);
+
+ if (ntable > ntables) {
+ ThrowRDE("Table lookup with number greater than number of tables.");
+ }
+ ushort16* t = &tables[ntable * TABLE_SIZE];
+ if (!dither) {
+ for (int i = 0; i < 65536; i++) {
+ t[i] = (i < nfilled) ? table[i] : table[nfilled - 1];
+ }
+ return;
+ }
+ for (int i = 0; i < nfilled; i++) {
+ int center = table[i];
+ int lower = i > 0 ? table[i - 1] : center;
+ int upper = i < (nfilled - 1) ? table[i + 1] : center;
+ int delta = upper - lower;
+ t[i * 2] = center - ((upper - lower + 2) / 4);
+ t[i * 2 + 1] = delta;
+ }
+
+ for (int i = nfilled; i < 65536; i++) {
+ t[i * 2] = table[nfilled - 1];
+ t[i * 2 + 1] = 0;
+ }
+ t[0] = t[1];
+ t[TABLE_SIZE - 1] = t[TABLE_SIZE - 2];
+}
+
+ushort16* TableLookUp::getTable(int n) {
+ if (n > ntables) {
+ ThrowRDE("Table lookup with number greater than number of tables.");
+ }
+ return &tables[n * TABLE_SIZE];
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/TableLookUp.h b/src/external/rawspeed/src/librawspeed/common/TableLookUp.h
new file mode 100644
index 000000000..6bad3ef89
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/TableLookUp.h
@@ -0,0 +1,40 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for ushort16
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class TableLookUp {
+public:
+ TableLookUp(int ntables, bool dither);
+
+ void setTable(int ntable, const std::vector<ushort16>& table);
+ ushort16* getTable(int n);
+ const int ntables;
+ std::vector<ushort16> tables;
+ const bool dither;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/common/Threading.h b/src/external/rawspeed/src/librawspeed/common/Threading.h
new file mode 100644
index 000000000..c74795b8e
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/common/Threading.h
@@ -0,0 +1,52 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include <algorithm> // for fill_n, min
+#include <cassert> // for assert
+#include <iterator> // for back_insert_iterator
+#include <numeric> // for accumulate
+#include <vector> // for vector
+
+namespace rawspeed {
+
+inline std::vector<unsigned> sliceUp(unsigned bucketsNum, unsigned pieces) {
+ std::vector<unsigned> buckets;
+
+ if (!bucketsNum || !pieces)
+ return buckets;
+
+ bucketsNum = std::min(bucketsNum, pieces);
+ buckets.reserve(bucketsNum);
+
+ const auto quot = pieces / bucketsNum;
+ const auto rem = pieces % bucketsNum;
+
+ std::fill_n(std::back_inserter(buckets), rem, 1 + quot);
+ std::fill_n(std::back_inserter(buckets), bucketsNum - rem, quot);
+
+ assert(buckets.size() == bucketsNum);
+ assert(std::accumulate(buckets.begin(), buckets.end(), 0UL) == pieces);
+
+ return buckets;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/AbstractTiffDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/AbstractTiffDecoder.cpp
new file mode 100644
index 000000000..58c2b7686
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/AbstractTiffDecoder.cpp
@@ -0,0 +1,51 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/AbstractTiffDecoder.h"
+#include "common/Common.h" // for uint32
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffIFD, TiffRootIFD, Tiff...
+#include <vector> // for vector
+
+namespace rawspeed {
+
+const TiffIFD* AbstractTiffDecoder::getIFDWithLargestImage(TiffTag filter) const
+{
+ std::vector<const TiffIFD*> ifds = mRootIFD->getIFDsWithTag(filter);
+
+ if (ifds.empty())
+ ThrowRDE("No suitable IFD with tag 0x%04x found.", filter);
+
+ auto res = ifds[0];
+ uint32 width = res->getEntry(IMAGEWIDTH)->getU32();
+ for (auto ifd : ifds) {
+ TiffEntry* widthE = ifd->getEntry(IMAGEWIDTH);
+ // guard agains random maker note entries with the same tag
+ if (widthE->count == 1 && widthE->getU32() > width) {
+ res = ifd;
+ width = widthE->getU32();
+ }
+ }
+
+ return res;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/AbstractTiffDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/AbstractTiffDecoder.h
new file mode 100644
index 000000000..470c3f2a2
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/AbstractTiffDecoder.h
@@ -0,0 +1,70 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "decoders/RawDecoder.h" // for RawDecoder
+#include "tiff/TiffIFD.h" // for TiffID, TiffRootIFD, TiffRootIFDOwner
+#include "tiff/TiffTag.h" // for TiffTag::IMAGEWIDTH, TiffTag
+#include <algorithm> // for move
+#include <memory> // for unique_ptr
+#include <string> // for string
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+class Buffer;
+
+class AbstractTiffDecoder : public RawDecoder
+{
+protected:
+ TiffRootIFDOwner mRootIFD;
+public:
+ AbstractTiffDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : RawDecoder(file), mRootIFD(std::move(root)) {}
+
+ TiffIFD* getRootIFD() final { return mRootIFD.get(); }
+
+ inline bool checkCameraSupported(const CameraMetaData* meta, const TiffID& id,
+ const std::string& mode) {
+ return RawDecoder::checkCameraSupported(meta, id.make, id.model, mode);
+ }
+
+ using RawDecoder::setMetaData;
+
+ inline void setMetaData(const CameraMetaData* meta, const TiffID& id,
+ const std::string& mode, int iso_speed) {
+ setMetaData(meta, id.make, id.model, mode, iso_speed);
+ }
+
+ inline void setMetaData(const CameraMetaData* meta, const std::string& mode,
+ int iso_speed) {
+ setMetaData(meta, mRootIFD->getID(), mode, iso_speed);
+ }
+
+ inline void checkSupportInternal(const CameraMetaData* meta) override {
+ checkCameraSupported(meta, mRootIFD->getID(), "");
+ }
+
+ const TiffIFD* getIFDWithLargestImage(TiffTag filter = IMAGEWIDTH) const;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/ArwDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/ArwDecoder.cpp
new file mode 100644
index 000000000..3a8ee0819
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/ArwDecoder.cpp
@@ -0,0 +1,460 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/ArwDecoder.h"
+#include "common/Common.h" // for uint32, uchar8
+#include "common/Point.h" // for iPoint2D
+#include "common/RawspeedException.h" // for RawspeedException
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "decompressors/SonyArw1Decompressor.h" // for SonyArw1Decompre...
+#include "decompressors/SonyArw2Decompressor.h" // for SonyArw2Decompre...
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/BitPumpMSB.h" // for BitPumpMSB
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endi...
+#include "io/IOException.h" // for IOException
+#include "metadata/Camera.h" // for Hints
+#include "metadata/ColorFilterArray.h" // for CFAColor::CFA_GREEN
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffRootIFD, Tif...
+#include "tiff/TiffTag.h" // for TiffTag::DNGPRIV...
+#include <cassert> // for assert
+#include <cstring> // for memcpy, size_t
+#include <memory> // for unique_ptr
+#include <string> // for operator==, string
+#include <vector> // for vector
+
+using std::vector;
+using std::string;
+
+namespace rawspeed {
+
+bool ArwDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "SONY";
+}
+
+RawImage ArwDecoder::decodeSRF(const TiffIFD* raw) {
+ raw = mRootIFD->getIFDWithTag(IMAGEWIDTH);
+
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+
+ if (width == 0 || height == 0 || width > 3360 || height > 2460)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ uint32 len = width * height * 2;
+
+ // Constants taken from dcraw
+ uint32 off = 862144;
+ uint32 key_off = 200896;
+ uint32 head_off = 164600;
+
+ // Replicate the dcraw contortions to get the "decryption" key
+ const uchar8* keyData = mFile->getData(key_off, 1);
+ uint32 offset = (*keyData) * 4;
+ keyData = mFile->getData(key_off + offset, 4);
+ uint32 key = getU32BE(keyData);
+ static const size_t head_size = 40;
+ const uchar8* head_orig = mFile->getData(head_off, head_size);
+ vector<uchar8> head(head_size);
+ SonyDecrypt(reinterpret_cast<const uint32*>(head_orig),
+ reinterpret_cast<uint32*>(&head[0]), 10, key);
+ for (int i = 26; i > 22; i--)
+ key = key << 8 | head[i - 1];
+
+ // "Decrypt" the whole image buffer
+ auto image_data = mFile->getData(off, len);
+ auto image_decoded = Buffer::Create(len);
+ SonyDecrypt(reinterpret_cast<const uint32*>(image_data),
+ reinterpret_cast<uint32*>(image_decoded.get()), len / 4, key);
+
+ Buffer di(move(image_decoded), len);
+
+ // And now decode as a normal 16bit raw
+ mRaw->dim = iPoint2D(width, height);
+ mRaw->createData();
+
+ UncompressedDecompressor u(di, 0, len, mRaw);
+ u.decodeRawUnpacked<16, Endianness::big>(width, height);
+
+ return mRaw;
+}
+
+RawImage ArwDecoder::decodeRawInternal() {
+ const TiffIFD* raw = nullptr;
+ vector<const TiffIFD*> data = mRootIFD->getIFDsWithTag(STRIPOFFSETS);
+
+ if (data.empty()) {
+ TiffEntry *model = mRootIFD->getEntryRecursive(MODEL);
+
+ if (model && model->getString() == "DSLR-A100") {
+ // We've caught the elusive A100 in the wild, a transitional format
+ // between the simple sanity of the MRW custom format and the wordly
+ // wonderfullness of the Tiff-based ARW format, let's shoot from the hip
+ raw = mRootIFD->getIFDWithTag(SUBIFDS);
+ uint32 off = raw->getEntry(SUBIFDS)->getU32();
+ uint32 width = 3881;
+ uint32 height = 2608;
+
+ mRaw->dim = iPoint2D(width, height);
+
+ ByteStream input(mFile, off);
+ SonyArw1Decompressor a(mRaw);
+ mRaw->createData();
+ a.decompress(input);
+
+ return mRaw;
+ }
+
+ if (hints.has("srf_format"))
+ return decodeSRF(raw);
+
+ ThrowRDE("No image data found");
+ }
+
+ raw = data[0];
+ int compression = raw->getEntry(COMPRESSION)->getU32();
+ if (1 == compression) {
+ DecodeUncompressed(raw);
+ return mRaw;
+ }
+
+ if (32767 != compression)
+ ThrowRDE("Unsupported compression");
+
+ TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
+ TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);
+
+ if (offsets->count != 1) {
+ ThrowRDE("Multiple Strips found: %u", offsets->count);
+ }
+ if (counts->count != offsets->count) {
+ ThrowRDE(
+ "Byte count number does not match strip size: count:%u, strips:%u ",
+ counts->count, offsets->count);
+ }
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+ uint32 bitPerPixel = raw->getEntry(BITSPERSAMPLE)->getU32();
+
+ switch (bitPerPixel) {
+ case 8:
+ case 12:
+ case 14:
+ break;
+ default:
+ ThrowRDE("Unexpected bits per pixel: %u", bitPerPixel);
+ }
+
+ // Sony E-550 marks compressed 8bpp ARW with 12 bit per pixel
+ // this makes the compression detect it as a ARW v1.
+ // This camera has however another MAKER entry, so we MAY be able
+ // to detect it this way in the future.
+ data = mRootIFD->getIFDsWithTag(MAKE);
+ if (data.size() > 1) {
+ for (auto &i : data) {
+ string make = i->getEntry(MAKE)->getString();
+ /* Check for maker "SONY" without spaces */
+ if (make == "SONY")
+ bitPerPixel = 8;
+ }
+ }
+
+ if (width == 0 || height == 0 || height % 2 != 0 || width > 8000 ||
+ height > 5320)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ bool arw1 = uint64(counts->getU32()) * 8 != width * height * bitPerPixel;
+ if (arw1)
+ height += 8;
+
+ mRaw->dim = iPoint2D(width, height);
+
+ std::vector<ushort16> curve(0x4001);
+ TiffEntry *c = raw->getEntry(SONY_CURVE);
+ uint32 sony_curve[] = { 0, 0, 0, 0, 0, 4095 };
+
+ for (uint32 i = 0; i < 4; i++)
+ sony_curve[i+1] = (c->getU16(i) >> 2) & 0xfff;
+
+ for (uint32 i = 0; i < 0x4001; i++)
+ curve[i] = i;
+
+ for (uint32 i = 0; i < 5; i++)
+ for (uint32 j = sony_curve[i] + 1; j <= sony_curve[i+1]; j++)
+ curve[j] = curve[j-1] + (1 << i);
+
+ RawImageCurveGuard curveHandler(&mRaw, curve, uncorrectedRawValues);
+
+ uint32 c2 = counts->getU32();
+ uint32 off = offsets->getU32();
+
+ if (!mFile->isValid(off))
+ ThrowRDE("Data offset after EOF, file probably truncated");
+
+ if (!mFile->isValid(off, c2))
+ c2 = mFile->getSize() - off;
+
+ ByteStream input(mFile, off, c2);
+
+ if (arw1) {
+ SonyArw1Decompressor a(mRaw);
+ mRaw->createData();
+ a.decompress(input);
+ } else
+ DecodeARW2(input, width, height, bitPerPixel);
+
+ return mRaw;
+}
+
+void ArwDecoder::DecodeUncompressed(const TiffIFD* raw) {
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+ uint32 off = raw->getEntry(STRIPOFFSETS)->getU32();
+ uint32 c2 = raw->getEntry(STRIPBYTECOUNTS)->getU32();
+
+ mRaw->dim = iPoint2D(width, height);
+
+ if (width == 0 || height == 0 || width > 8000 || height > 5320)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ if (c2 == 0)
+ ThrowRDE("Strip is empty, nothing to decode!");
+
+ const Buffer buf(mFile->getSubView(off, c2));
+
+ mRaw->createData();
+
+ UncompressedDecompressor u(buf, mRaw);
+
+ if (hints.has("sr2_format"))
+ u.decodeRawUnpacked<14, Endianness::big>(width, height);
+ else
+ u.decodeRawUnpacked<16, Endianness::little>(width, height);
+}
+
+void ArwDecoder::DecodeARW2(const ByteStream& input, uint32 w, uint32 h,
+ uint32 bpp) {
+
+ if (bpp == 8) {
+ SonyArw2Decompressor a2(mRaw, input);
+ mRaw->createData();
+ a2.decompress();
+ return;
+ } // End bpp = 8
+
+ if (bpp == 12) {
+ mRaw->createData();
+ UncompressedDecompressor u(input, mRaw);
+ u.decode12BitRaw<Endianness::little>(w, h);
+
+ // Shift scales, since black and white are the same as compressed precision
+ mShiftDownScale = 2;
+ return;
+ }
+ ThrowRDE("Unsupported bit depth");
+}
+
+void ArwDecoder::ParseA100WB() {
+ if (!mRootIFD->hasEntryRecursive(DNGPRIVATEDATA))
+ return;
+
+ // only contains the offset, not the length!
+ TiffEntry* priv = mRootIFD->getEntryRecursive(DNGPRIVATEDATA);
+ ByteStream bs = priv->getData();
+ bs.setByteOrder(Endianness::little);
+ const uint32 off = bs.getU32();
+
+ bs = ByteStream(*mFile, off);
+
+ // MRW style, see MrwDecoder
+
+ bs.setByteOrder(Endianness::big);
+ uint32 tag = bs.getU32();
+ if (0x4D5249 != tag) // MRI
+ ThrowRDE("Can not parse DNGPRIVATEDATA, invalid tag (0x%x).", tag);
+
+ bs.setByteOrder(Endianness::little);
+ uint32 len = bs.getU32();
+
+ bs = bs.getSubStream(bs.getPosition(), len);
+
+ while (bs.getRemainSize() > 0) {
+ bs.setByteOrder(Endianness::big);
+ tag = bs.getU32();
+ bs.setByteOrder(Endianness::little);
+ len = bs.getU32();
+ bs.check(len);
+ if (!len)
+ ThrowRDE("Found entry of zero lenght, corrupt.");
+
+ if (0x574247 != tag) { // WBG
+ // not the tag we are interested in, skip
+ bs.skipBytes(len);
+ continue;
+ }
+
+ bs.skipBytes(4);
+
+ ushort16 tmp[4];
+ bs.setByteOrder(Endianness::little);
+ for (auto& coeff : tmp)
+ coeff = bs.getU16();
+
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(tmp[0]);
+ mRaw->metadata.wbCoeffs[1] = static_cast<float>(tmp[1]);
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(tmp[3]);
+
+ // only need this one block, no need to process any further
+ break;
+ }
+}
+
+void ArwDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ //Default
+ int iso = 0;
+
+ mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN, CFA_BLUE);
+
+ if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
+ iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32();
+
+ auto id = mRootIFD->getID();
+
+ setMetaData(meta, id, "", iso);
+ mRaw->whitePoint >>= mShiftDownScale;
+ mRaw->blackLevel >>= mShiftDownScale;
+
+ // Set the whitebalance
+ try {
+ if (id.model == "DSLR-A100") { // Handle the MRW style WB of the A100
+ ParseA100WB();
+ } else { // Everything else but the A100
+ GetWB();
+ }
+ } catch (RawspeedException& e) {
+ mRaw->setError(e.what());
+ // We caught an exception reading WB, just ignore it
+ }
+}
+
+void ArwDecoder::SonyDecrypt(const uint32* ibuf, uint32* obuf, uint32 len,
+ uint32 key) {
+ if (0 == len)
+ return;
+
+ uint32 pad[128];
+
+ // Initialize the decryption pad from the key
+ for (int p=0; p < 4; p++)
+ pad[p] = key = key * 48828125UL + 1UL;
+ pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31;
+ for (int p=4; p < 127; p++)
+ pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31;
+ for (int p=0; p < 127; p++)
+ pad[p] = getU32BE(&pad[p]);
+
+ int p = 127;
+ // Decrypt the buffer in place using the pad
+ for (; len > 0; len--) {
+ pad[p & 127] = pad[(p+1) & 127] ^ pad[(p+1+64) & 127];
+
+ uint32 pv;
+ memcpy(&pv, pad + (p & 127), sizeof(uint32));
+
+ uint32 bv;
+ memcpy(&bv, ibuf, sizeof(uint32));
+
+ bv ^= pv;
+
+ memcpy(obuf, &bv, sizeof(uint32));
+
+ ibuf++;
+ obuf++;
+ p++;
+ }
+}
+
+void ArwDecoder::GetWB() {
+ // Set the whitebalance for all the modern ARW formats (everything after A100)
+ if (mRootIFD->hasEntryRecursive(DNGPRIVATEDATA)) {
+ NORangesSet<Buffer> ifds_undecoded;
+
+ TiffEntry *priv = mRootIFD->getEntryRecursive(DNGPRIVATEDATA);
+ TiffRootIFD makerNoteIFD(nullptr, &ifds_undecoded, priv->getRootIfdData(),
+ priv->getU32());
+
+ TiffEntry *sony_offset = makerNoteIFD.getEntryRecursive(SONY_OFFSET);
+ TiffEntry *sony_length = makerNoteIFD.getEntryRecursive(SONY_LENGTH);
+ TiffEntry *sony_key = makerNoteIFD.getEntryRecursive(SONY_KEY);
+ if(!sony_offset || !sony_length || !sony_key || sony_key->count != 4)
+ ThrowRDE("couldn't find the correct metadata for WB decoding");
+
+ assert(sony_offset != nullptr);
+ uint32 off = sony_offset->getU32();
+
+ assert(sony_length != nullptr);
+ uint32 len = sony_length->getU32();
+
+ assert(sony_key != nullptr);
+ uint32 key = getU32LE(sony_key->getData(4));
+
+ // "Decrypt" IFD
+ const auto& ifd_crypt = priv->getRootIfdData();
+ auto ifd_size = ifd_crypt.getSize();
+ auto ifd_decoded = Buffer::Create(ifd_size);
+
+ SonyDecrypt(reinterpret_cast<const uint32*>(ifd_crypt.getData(off, len)),
+ reinterpret_cast<uint32*>(ifd_decoded.get() + off), len / 4,
+ key);
+
+ NORangesSet<Buffer> ifds_decoded;
+ Buffer decIFD(move(ifd_decoded), ifd_size);
+ DataBuffer dbIDD(decIFD, priv->getRootIfdData().getByteOrder());
+ TiffRootIFD encryptedIFD(nullptr, &ifds_decoded, dbIDD, off);
+
+ if (encryptedIFD.hasEntry(SONYGRBGLEVELS)){
+ TiffEntry *wb = encryptedIFD.getEntry(SONYGRBGLEVELS);
+ if (wb->count != 4)
+ ThrowRDE("WB has %d entries instead of 4", wb->count);
+ mRaw->metadata.wbCoeffs[0] = wb->getFloat(1);
+ mRaw->metadata.wbCoeffs[1] = wb->getFloat(0);
+ mRaw->metadata.wbCoeffs[2] = wb->getFloat(2);
+ } else if (encryptedIFD.hasEntry(SONYRGGBLEVELS)){
+ TiffEntry *wb = encryptedIFD.getEntry(SONYRGGBLEVELS);
+ if (wb->count != 4)
+ ThrowRDE("WB has %d entries instead of 4", wb->count);
+ mRaw->metadata.wbCoeffs[0] = wb->getFloat(0);
+ mRaw->metadata.wbCoeffs[1] = wb->getFloat(1);
+ mRaw->metadata.wbCoeffs[2] = wb->getFloat(3);
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/ArwDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/ArwDecoder.h
new file mode 100644
index 000000000..ddebea2d3
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/ArwDecoder.h
@@ -0,0 +1,61 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "io/ByteStream.h" // for ByteStream
+#include "tiff/TiffIFD.h" // for TiffIFD (ptr only), TiffRo...
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+class Buffer;
+
+class ArwDecoder final : public AbstractTiffDecoder
+{
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ ArwDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : AbstractTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ void ParseA100WB();
+
+ int getDecoderVersion() const override { return 1; }
+ RawImage decodeSRF(const TiffIFD* raw);
+ void DecodeARW2(const ByteStream& input, uint32 w, uint32 h, uint32 bpp);
+ void DecodeUncompressed(const TiffIFD* raw);
+ void SonyDecrypt(const uint32* ibuf, uint32* obuf, uint32 len, uint32 key);
+ void GetWB();
+ ByteStream in;
+ int mShiftDownScale = 0;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/CMakeLists.txt b/src/external/rawspeed/src/librawspeed/decoders/CMakeLists.txt
new file mode 100644
index 000000000..654116331
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/CMakeLists.txt
@@ -0,0 +1,53 @@
+FILE(GLOB SOURCES
+ "AbstractTiffDecoder.cpp"
+ "AbstractTiffDecoder.h"
+ "ArwDecoder.cpp"
+ "ArwDecoder.h"
+ "Cr2Decoder.cpp"
+ "Cr2Decoder.h"
+ "CrwDecoder.cpp"
+ "CrwDecoder.h"
+ "DcrDecoder.cpp"
+ "DcrDecoder.h"
+ "DcsDecoder.cpp"
+ "DcsDecoder.h"
+ "DngDecoder.cpp"
+ "DngDecoder.h"
+ "ErfDecoder.cpp"
+ "ErfDecoder.h"
+ "IiqDecoder.cpp"
+ "IiqDecoder.h"
+ "KdcDecoder.cpp"
+ "KdcDecoder.h"
+ "MefDecoder.cpp"
+ "MefDecoder.h"
+ "MosDecoder.cpp"
+ "MosDecoder.h"
+ "MrwDecoder.cpp"
+ "MrwDecoder.h"
+ "NakedDecoder.cpp"
+ "NakedDecoder.h"
+ "NefDecoder.cpp"
+ "NefDecoder.h"
+ "OrfDecoder.cpp"
+ "OrfDecoder.h"
+ "PefDecoder.cpp"
+ "PefDecoder.h"
+ "RafDecoder.cpp"
+ "RafDecoder.h"
+ "RawDecoder.cpp"
+ "RawDecoder.h"
+ "RawDecoderException.h"
+ "Rw2Decoder.cpp"
+ "Rw2Decoder.h"
+ "SimpleTiffDecoder.cpp"
+ "SimpleTiffDecoder.h"
+ "SrwDecoder.cpp"
+ "SrwDecoder.h"
+ "ThreefrDecoder.cpp"
+ "ThreefrDecoder.h"
+)
+
+target_sources(rawspeed PRIVATE
+ ${SOURCES}
+)
diff --git a/src/external/rawspeed/src/librawspeed/decoders/Cr2Decoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/Cr2Decoder.cpp
new file mode 100644
index 000000000..5dfa6102f
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/Cr2Decoder.cpp
@@ -0,0 +1,322 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2015-2017 Roman Lebedev
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/Cr2Decoder.h"
+#include "common/Common.h" // for ushort16, clampBits, uint32
+#include "common/Point.h" // for iPoint2D
+#include "common/RawspeedException.h" // for RawspeedException
+#include "decoders/RawDecoderException.h" // for RawDecoderException, Thro...
+#include "decompressors/Cr2Decompressor.h" // for Cr2Decompressor
+#include "interpolators/Cr2sRawInterpolator.h" // for Cr2sRawInterpolator
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for getHostEndianness, Endian...
+#include "io/IOException.h" // for IOException
+#include "metadata/Camera.h" // for Hints
+#include "metadata/ColorFilterArray.h" // for CFAColor::CFA_GREEN, CFAC...
+#include "parsers/TiffParserException.h" // for ThrowTPE
+#include "tiff/TiffEntry.h" // for TiffEntry, TiffDataType::...
+#include "tiff/TiffTag.h" // for TiffTag, TiffTag::CANONCO...
+#include <array> // for array
+#include <cassert> // for assert
+#include <memory> // for unique_ptr, allocator
+#include <string> // for string, operator==
+#include <vector> // for vector
+// IWYU pragma: no_include <ext/alloc_traits.h>
+
+using std::string;
+using std::vector;
+
+namespace rawspeed {
+
+bool Cr2Decoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+ const std::string& model = id.model;
+
+ // FIXME: magic
+
+ return make == "Canon" || (make == "Kodak" && model == "DCS560C");
+}
+
+RawImage Cr2Decoder::decodeOldFormat() {
+ uint32 offset = 0;
+ if (mRootIFD->getEntryRecursive(CANON_RAW_DATA_OFFSET))
+ offset = mRootIFD->getEntryRecursive(CANON_RAW_DATA_OFFSET)->getU32();
+ else {
+ // D2000 is oh so special...
+ auto ifd = mRootIFD->getIFDWithTag(CFAPATTERN);
+ if (! ifd->hasEntry(STRIPOFFSETS))
+ ThrowRDE("Couldn't find offset");
+
+ offset = ifd->getEntry(STRIPOFFSETS)->getU32();
+ }
+
+ ByteStream b(mFile, offset, Endianness::big);
+ b.skipBytes(41);
+ int height = b.getU16();
+ int width = b.getU16();
+
+ // some old models (1D/1DS/D2000C) encode two lines as one
+ // see: FIX_CANON_HALF_HEIGHT_DOUBLE_WIDTH
+ if (width > 2*height) {
+ height *= 2;
+ width /= 2;
+ }
+ width *= 2; // components
+
+ mRaw->dim = {width, height};
+
+ const ByteStream bs(mFile->getSubView(offset), 0);
+
+ Cr2Decompressor l(bs, mRaw);
+ mRaw->createData();
+ l.decode({width});
+
+ // deal with D2000 GrayResponseCurve
+ TiffEntry* curve = mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x123));
+ if (curve && curve->type == TIFF_SHORT && curve->count == 4096) {
+ auto table = curve->getU16Array(curve->count);
+ RawImageCurveGuard curveHandler(&mRaw, table, uncorrectedRawValues);
+
+ // Apply table
+ if (!uncorrectedRawValues)
+ mRaw->sixteenBitLookup();
+ }
+
+ return mRaw;
+}
+
+// for technical details about Cr2 mRAW/sRAW, see http://lclevy.free.fr/cr2/
+
+RawImage Cr2Decoder::decodeNewFormat() {
+ TiffEntry* sensorInfoE = mRootIFD->getEntryRecursive(CANON_SENSOR_INFO);
+ if (!sensorInfoE)
+ ThrowTPE("failed to get SensorInfo from MakerNote");
+
+ assert(sensorInfoE != nullptr);
+
+ const ushort16 width = sensorInfoE->getU16(1);
+ const ushort16 height = sensorInfoE->getU16(2);
+ mRaw->dim = {width, height};
+
+ int componentsPerPixel = 1;
+ TiffIFD* raw = mRootIFD->getSubIFDs()[3].get();
+ if (raw->hasEntry(CANON_SRAWTYPE) &&
+ raw->getEntry(CANON_SRAWTYPE)->getU32() == 4)
+ componentsPerPixel = 3;
+
+ mRaw->setCpp(componentsPerPixel);
+ mRaw->isCFA = (mRaw->getCpp() == 1);
+
+ vector<int> s_width;
+ // there are four cases:
+ // * there is a tag with three components,
+ // $ last two components are non-zero: all fine then.
+ // $ first two components are zero, last component is non-zero
+ // we let Cr2Decompressor guess it (it'll throw if fails)
+ // $ else the image is considered corrupt.
+ // * there is a tag with not three components, the image is considered
+ // corrupt. $ there is no tag, we let Cr2Decompressor guess it (it'll throw if
+ // fails)
+ TiffEntry* cr2SliceEntry = raw->getEntryRecursive(CANONCR2SLICE);
+ if (cr2SliceEntry) {
+ if (cr2SliceEntry->count != 3) {
+ ThrowRDE("Found RawImageSegmentation tag with %d elements, should be 3.",
+ cr2SliceEntry->count);
+ }
+
+ if (cr2SliceEntry->getU16(1) != 0 && cr2SliceEntry->getU16(2) != 0) {
+ // first component can be either zero or non-zero, don't care
+ s_width.reserve(1 + cr2SliceEntry->getU16(0));
+ for (int i = 0; i < cr2SliceEntry->getU16(0); i++)
+ s_width.emplace_back(cr2SliceEntry->getU16(1));
+ s_width.emplace_back(cr2SliceEntry->getU16(2));
+ } else if (cr2SliceEntry->getU16(0) == 0 && cr2SliceEntry->getU16(1) == 0 &&
+ cr2SliceEntry->getU16(2) != 0) {
+ // PowerShot G16, PowerShot S120, let Cr2Decompressor guess.
+ } else {
+ ThrowRDE("Strange RawImageSegmentation tag: (%d, %d, %d), image corrupt.",
+ cr2SliceEntry->getU16(0), cr2SliceEntry->getU16(1),
+ cr2SliceEntry->getU16(2));
+ }
+ } // EOS 20D, EOS-1D Mark II, let Cr2Decompressor guess.
+
+ const uint32 offset = raw->getEntry(STRIPOFFSETS)->getU32();
+ const uint32 count = raw->getEntry(STRIPBYTECOUNTS)->getU32();
+
+ const ByteStream bs(mFile->getSubView(offset, count), 0);
+
+ Cr2Decompressor d(bs, mRaw);
+ mRaw->createData();
+ d.decode(s_width);
+
+ if (mRaw->metadata.subsampling.x > 1 || mRaw->metadata.subsampling.y > 1)
+ sRawInterpolate();
+
+ return mRaw;
+}
+
+RawImage Cr2Decoder::decodeRawInternal() {
+ if (mRootIFD->getSubIFDs().size() < 4)
+ return decodeOldFormat();
+ else // NOLINT ok, here it make sense
+ return decodeNewFormat();
+}
+
+void Cr2Decoder::checkSupportInternal(const CameraMetaData* meta) {
+ auto id = mRootIFD->getID();
+ // Check for sRaw mode
+ if (mRootIFD->getSubIFDs().size() == 4) {
+ TiffEntry* typeE = mRootIFD->getSubIFDs()[3]->getEntryRecursive(CANON_SRAWTYPE);
+ if (typeE && typeE->getU32() == 4) {
+ checkCameraSupported(meta, id, "sRaw1");
+ return;
+ }
+ }
+
+ checkCameraSupported(meta, id, "");
+}
+
+void Cr2Decoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ int iso = 0;
+ mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN, CFA_BLUE);
+
+ string mode;
+
+ if (mRaw->metadata.subsampling.y == 2 && mRaw->metadata.subsampling.x == 2)
+ mode = "sRaw1";
+
+ if (mRaw->metadata.subsampling.y == 1 && mRaw->metadata.subsampling.x == 2)
+ mode = "sRaw2";
+
+ if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
+ iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32();
+
+ // Fetch the white balance
+ try{
+ if (mRootIFD->hasEntryRecursive(CANONCOLORDATA)) {
+ TiffEntry *wb = mRootIFD->getEntryRecursive(CANONCOLORDATA);
+ // this entry is a big table, and different cameras store used WB in
+ // different parts, so find the offset, default is the most common one
+ int offset = hints.get("wb_offset", 126);
+
+ offset /= 2;
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(wb->getU16(offset + 0));
+ mRaw->metadata.wbCoeffs[1] = static_cast<float>(wb->getU16(offset + 1));
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(wb->getU16(offset + 3));
+ } else {
+ if (mRootIFD->hasEntryRecursive(CANONSHOTINFO) &&
+ mRootIFD->hasEntryRecursive(CANONPOWERSHOTG9WB)) {
+ TiffEntry *shot_info = mRootIFD->getEntryRecursive(CANONSHOTINFO);
+ TiffEntry *g9_wb = mRootIFD->getEntryRecursive(CANONPOWERSHOTG9WB);
+
+ ushort16 wb_index = shot_info->getU16(7);
+ int wb_offset = (wb_index < 18) ? "012347800000005896"[wb_index]-'0' : 0;
+ wb_offset = wb_offset*8 + 2;
+
+ mRaw->metadata.wbCoeffs[0] =
+ static_cast<float>(g9_wb->getU32(wb_offset + 1));
+ mRaw->metadata.wbCoeffs[1] =
+ (static_cast<float>(g9_wb->getU32(wb_offset + 0)) +
+ static_cast<float>(g9_wb->getU32(wb_offset + 3))) /
+ 2.0F;
+ mRaw->metadata.wbCoeffs[2] =
+ static_cast<float>(g9_wb->getU32(wb_offset + 2));
+ } else if (mRootIFD->hasEntryRecursive(static_cast<TiffTag>(0xa4))) {
+ // WB for the old 1D and 1DS
+ TiffEntry* wb = mRootIFD->getEntryRecursive(static_cast<TiffTag>(0xa4));
+ if (wb->count >= 3) {
+ mRaw->metadata.wbCoeffs[0] = wb->getFloat(0);
+ mRaw->metadata.wbCoeffs[1] = wb->getFloat(1);
+ mRaw->metadata.wbCoeffs[2] = wb->getFloat(2);
+ }
+ }
+ }
+ } catch (RawspeedException& e) {
+ mRaw->setError(e.what());
+ // We caught an exception reading WB, just ignore it
+ }
+ setMetaData(meta, mode, iso);
+}
+
+int Cr2Decoder::getHue() {
+ if (hints.has("old_sraw_hue"))
+ return (mRaw->metadata.subsampling.y * mRaw->metadata.subsampling.x);
+
+ if (!mRootIFD->hasEntryRecursive(static_cast<TiffTag>(0x10))) {
+ return 0;
+ }
+ uint32 model_id =
+ mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x10))->getU32();
+ if (model_id >= 0x80000281 || model_id == 0x80000218 || (hints.has("force_new_sraw_hue")))
+ return ((mRaw->metadata.subsampling.y * mRaw->metadata.subsampling.x) - 1) >> 1;
+
+ return (mRaw->metadata.subsampling.y * mRaw->metadata.subsampling.x);
+}
+
+// Interpolate and convert sRaw data.
+void Cr2Decoder::sRawInterpolate() {
+ TiffEntry* wb = mRootIFD->getEntryRecursive(CANONCOLORDATA);
+ if (!wb)
+ ThrowRDE("Unable to locate WB info.");
+
+ // Offset to sRaw coefficients used to reconstruct uncorrected RGB data.
+ uint32 offset = 78;
+
+ std::array<int, 3> sraw_coeffs;
+
+ assert(wb != nullptr);
+ sraw_coeffs[0] = wb->getU16(offset + 0);
+ sraw_coeffs[1] =
+ (wb->getU16(offset + 1) + wb->getU16(offset + 2) + 1) >> 1;
+ sraw_coeffs[2] = wb->getU16(offset + 3);
+
+ if (hints.has("invert_sraw_wb")) {
+ sraw_coeffs[0] = static_cast<int>(
+ 1024.0F / (static_cast<float>(sraw_coeffs[0]) / 1024.0F));
+ sraw_coeffs[2] = static_cast<int>(
+ 1024.0F / (static_cast<float>(sraw_coeffs[2]) / 1024.0F));
+ }
+
+ /* Determine sRaw coefficients */
+ bool isOldSraw = hints.has("sraw_40d");
+ bool isNewSraw = hints.has("sraw_new");
+
+ Cr2sRawInterpolator i(mRaw, sraw_coeffs, getHue());
+
+ int version;
+ if (isOldSraw)
+ version = 0;
+ else {
+ if (isNewSraw) {
+ version = 2;
+ } else {
+ version = 1;
+ }
+ }
+
+ i.interpolate(version);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/Cr2Decoder.h b/src/external/rawspeed/src/librawspeed/decoders/Cr2Decoder.h
new file mode 100644
index 000000000..9def2ff80
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/Cr2Decoder.h
@@ -0,0 +1,54 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+class Buffer;
+
+class Cr2Decoder final : public AbstractTiffDecoder
+{
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ Cr2Decoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : AbstractTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void checkSupportInternal(const CameraMetaData* meta) override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 9; }
+ RawImage decodeOldFormat();
+ RawImage decodeNewFormat();
+ void sRawInterpolate();
+ int getHue();
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/CrwDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/CrwDecoder.cpp
new file mode 100644
index 000000000..d617a6bdd
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/CrwDecoder.cpp
@@ -0,0 +1,210 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2015 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/CrwDecoder.h"
+#include "common/Common.h" // for ushort16, uint32
+#include "common/Point.h" // for iPoint2D
+#include "common/RawspeedException.h" // for RawspeedException
+#include "decoders/RawDecoderException.h" // for RawDecoderException (ptr ...
+#include "decompressors/CrwDecompressor.h" // for CrwDecompressor
+#include "metadata/Camera.h" // for Hints
+#include "metadata/ColorFilterArray.h" // for CFAColor::CFA_GREEN, CFAC...
+#include "tiff/CiffEntry.h" // for CiffEntry, CiffDataType::...
+#include "tiff/CiffIFD.h" // for CiffIFD
+#include "tiff/CiffTag.h" // for CiffTag, CiffTag::CIFF_MA...
+#include <algorithm> // for move
+#include <array> // for array
+#include <cassert> // for assert
+#include <cmath> // for copysignf, expf, logf
+#include <memory> // for unique_ptr
+#include <string> // for string
+#include <vector> // for vector
+// IWYU pragma: no_include <bits/std_abs.h>
+
+using std::vector;
+using std::string;
+using std::abs;
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+CrwDecoder::CrwDecoder(std::unique_ptr<const CiffIFD> rootIFD,
+ const Buffer* file)
+ : RawDecoder(file), mRootIFD(move(rootIFD)) {}
+
+RawImage CrwDecoder::decodeRawInternal() {
+ const CiffEntry* sensorInfo = mRootIFD->getEntryRecursive(CIFF_SENSORINFO);
+
+ if (!sensorInfo || sensorInfo->count < 6 || sensorInfo->type != CIFF_SHORT)
+ ThrowRDE("Couldn't find image sensor info");
+
+ assert(sensorInfo != nullptr);
+ uint32 width = sensorInfo->getU16(1);
+ uint32 height = sensorInfo->getU16(2);
+ mRaw->dim = iPoint2D(width, height);
+
+ const CiffEntry* decTable = mRootIFD->getEntryRecursive(CIFF_DECODERTABLE);
+ if (!decTable || decTable->type != CIFF_LONG)
+ ThrowRDE("Couldn't find decoder table");
+
+ assert(decTable != nullptr);
+ uint32 dec_table = decTable->getU32();
+
+ bool lowbits = ! hints.has("no_decompressed_lowbits");
+
+ CrwDecompressor c(mRaw, dec_table, lowbits, mFile);
+ mRaw->createData();
+ c.decompress();
+
+ return mRaw;
+}
+
+void CrwDecoder::checkSupportInternal(const CameraMetaData* meta) {
+ vector<const CiffIFD*> data = mRootIFD->getIFDsWithTag(CIFF_MAKEMODEL);
+ if (data.empty())
+ ThrowRDE("Model name not found");
+ vector<string> makemodel = data[0]->getEntry(CIFF_MAKEMODEL)->getStrings();
+ if (makemodel.size() < 2)
+ ThrowRDE("wrong number of strings for make/model");
+ string make = makemodel[0];
+ string model = makemodel[1];
+
+ this->checkCameraSupported(meta, make, model, "");
+}
+
+// based on exiftool's Image::ExifTool::Canon::CanonEv
+float __attribute__((const)) CrwDecoder::canonEv(const long in) {
+ // remove sign
+ long val = abs(in);
+ // remove fraction
+ long frac = val & 0x1f;
+ val -= frac;
+ // convert 1/3 (0x0c) and 2/3 (0x14) codes
+ if (frac == 0x0c) {
+ frac = 32.0F / 3;
+ }
+ else if (frac == 0x14) {
+ frac = 64.0F / 3;
+ }
+ return copysignf((val + frac) / 32.0F, in);
+}
+
+void CrwDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ int iso = 0;
+ mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN, CFA_BLUE);
+ vector<const CiffIFD*> data = mRootIFD->getIFDsWithTag(CIFF_MAKEMODEL);
+ if (data.empty())
+ ThrowRDE("Model name not found");
+ vector<string> makemodel = data[0]->getEntry(CIFF_MAKEMODEL)->getStrings();
+ if (makemodel.size() < 2)
+ ThrowRDE("wrong number of strings for make/model");
+ string make = makemodel[0];
+ string model = makemodel[1];
+ string mode;
+
+ if (mRootIFD->hasEntryRecursive(CIFF_SHOTINFO)) {
+ const CiffEntry* shot_info = mRootIFD->getEntryRecursive(CIFF_SHOTINFO);
+ if (shot_info->type == CIFF_SHORT && shot_info->count >= 2) {
+ // os << exp(canonEv(value.toLong()) * log(2.0)) * 100.0 / 32.0;
+ ushort16 iso_index = shot_info->getU16(2);
+ iso = expf(canonEv(static_cast<long>(iso_index)) * logf(2.0)) * 100.0F /
+ 32.0F;
+ }
+ }
+
+ // Fetch the white balance
+ try{
+ if (mRootIFD->hasEntryRecursive(static_cast<CiffTag>(0x0032))) {
+ const CiffEntry* wb =
+ mRootIFD->getEntryRecursive(static_cast<CiffTag>(0x0032));
+ if (wb->type == CIFF_BYTE && wb->count == 768) {
+ // We're in a D30 file, values are RGGB
+ // This will probably not get used anyway as a 0x102c tag should exist
+ std::array<uchar8, 4> wbMuls{{wb->getByte(72), wb->getByte(73),
+ wb->getByte(74), wb->getByte(75)}};
+ for (const auto& mul : wbMuls) {
+ if (0 == mul)
+ ThrowRDE("WB coeffient is zero!");
+ }
+
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(1024.0 / wbMuls[0]);
+ mRaw->metadata.wbCoeffs[1] =
+ static_cast<float>((1024.0 / wbMuls[1]) + (1024.0 / wbMuls[2])) /
+ 2.0F;
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(1024.0 / wbMuls[3]);
+ } else if (wb->type == CIFF_BYTE && wb->count > 768) { // Other G series and S series cameras
+ // correct offset for most cameras
+ int offset = hints.get("wb_offset", 120);
+
+ ushort16 key[] = { 0x410, 0x45f3 };
+ if (! hints.has("wb_mangle"))
+ key[0] = key[1] = 0;
+
+ offset /= 2;
+ mRaw->metadata.wbCoeffs[0] =
+ static_cast<float>(wb->getU16(offset + 1) ^ key[1]);
+ mRaw->metadata.wbCoeffs[1] =
+ static_cast<float>(wb->getU16(offset + 0) ^ key[0]);
+ mRaw->metadata.wbCoeffs[2] =
+ static_cast<float>(wb->getU16(offset + 2) ^ key[0]);
+ }
+ }
+ if (mRootIFD->hasEntryRecursive(static_cast<CiffTag>(0x102c))) {
+ const CiffEntry* entry =
+ mRootIFD->getEntryRecursive(static_cast<CiffTag>(0x102c));
+ if (entry->type == CIFF_SHORT && entry->getU16() > 512) {
+ // G1/Pro90 CYGM pattern
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(entry->getU16(62));
+ mRaw->metadata.wbCoeffs[1] = static_cast<float>(entry->getU16(63));
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(entry->getU16(60));
+ mRaw->metadata.wbCoeffs[3] = static_cast<float>(entry->getU16(61));
+ } else if (entry->type == CIFF_SHORT) {
+ /* G2, S30, S40 */
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(entry->getU16(51));
+ mRaw->metadata.wbCoeffs[1] = (static_cast<float>(entry->getU16(50)) +
+ static_cast<float>(entry->getU16(53))) /
+ 2.0F;
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(entry->getU16(52));
+ }
+ }
+ if (mRootIFD->hasEntryRecursive(CIFF_SHOTINFO) && mRootIFD->hasEntryRecursive(CIFF_WHITEBALANCE)) {
+ const CiffEntry* shot_info = mRootIFD->getEntryRecursive(CIFF_SHOTINFO);
+ ushort16 wb_index = shot_info->getU16(7);
+ const CiffEntry* wb_data = mRootIFD->getEntryRecursive(CIFF_WHITEBALANCE);
+ /* CANON EOS D60, CANON EOS 10D, CANON EOS 300D */
+ if (wb_index > 9)
+ ThrowRDE("Invalid white balance index");
+ int wb_offset = 1 + ("0134567028"[wb_index]-'0') * 4;
+ mRaw->metadata.wbCoeffs[0] = wb_data->getU16(wb_offset + 0);
+ mRaw->metadata.wbCoeffs[1] = wb_data->getU16(wb_offset + 1);
+ mRaw->metadata.wbCoeffs[2] = wb_data->getU16(wb_offset + 3);
+ }
+ } catch (RawspeedException& e) {
+ mRaw->setError(e.what());
+ // We caught an exception reading WB, just ignore it
+ }
+
+ setMetaData(meta, make, model, mode, iso);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/CrwDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/CrwDecoder.h
new file mode 100644
index 000000000..fbfba41fc
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/CrwDecoder.h
@@ -0,0 +1,49 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/RawDecoder.h" // for RawDecoder
+#include "tiff/CiffIFD.h" // for CiffIFD
+#include <memory> // for unique_ptr
+
+namespace rawspeed {
+
+class Buffer;
+
+class CameraMetaData;
+
+class CrwDecoder final : public RawDecoder {
+ std::unique_ptr<const CiffIFD> mRootIFD;
+
+public:
+ CrwDecoder(std::unique_ptr<const CiffIFD> rootIFD, const Buffer* file);
+ RawImage decodeRawInternal() override;
+ void checkSupportInternal(const CameraMetaData* meta) override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+ static float canonEv(long in);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/DcrDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/DcrDecoder.cpp
new file mode 100644
index 000000000..cdad0691e
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/DcrDecoder.cpp
@@ -0,0 +1,105 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/DcrDecoder.h"
+#include "common/NORangesSet.h" // for NORangesSet
+#include "decoders/RawDecoderException.h" // for RawDecoderException (ptr ...
+#include "decompressors/KodakDecompressor.h" // for KodakDecompressor
+#include "io/ByteStream.h" // for ByteStream
+#include "tiff/TiffEntry.h" // for TiffEntry, TiffDataType::...
+#include "tiff/TiffIFD.h" // for TiffRootIFD, TiffIFD
+#include "tiff/TiffTag.h" // for TiffTag, TiffTag::COMPRES...
+#include <cassert> // for assert
+#include <string> // for operator==, string
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+bool DcrDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "Kodak";
+}
+
+void DcrDecoder::checkImageDimensions() {
+ if (width > 4516 || height > 3012)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+}
+
+RawImage DcrDecoder::decodeRawInternal() {
+ SimpleTiffDecoder::prepareForRawDecoding();
+
+ ByteStream input(mFile, off);
+
+ int compression = raw->getEntry(COMPRESSION)->getU32();
+ if (65000 != compression)
+ ThrowRDE("Unsupported compression %d", compression);
+
+ TiffEntry* ifdoffset = mRootIFD->getEntryRecursive(KODAK_IFD);
+ if (!ifdoffset)
+ ThrowRDE("Couldn't find the Kodak IFD offset");
+
+ NORangesSet<Buffer> ifds;
+
+ assert(ifdoffset != nullptr);
+ TiffRootIFD kodakifd(nullptr, &ifds, ifdoffset->getRootIfdData(),
+ ifdoffset->getU32());
+
+ TiffEntry* linearization = kodakifd.getEntryRecursive(KODAK_LINEARIZATION);
+ if (!linearization || linearization->count != 1024 ||
+ linearization->type != TIFF_SHORT)
+ ThrowRDE("Couldn't find the linearization table");
+
+ assert(linearization != nullptr);
+ auto linTable = linearization->getU16Array(1024);
+
+ RawImageCurveGuard curveHandler(&mRaw, linTable, uncorrectedRawValues);
+
+ // FIXME: dcraw does all sorts of crazy things besides this to fetch
+ // WB from what appear to be presets and calculate it in weird ways
+ // The only file I have only uses this method, if anybody careas look
+ // in dcraw.c parse_kodak_ifd() for all that weirdness
+ TiffEntry* blob = kodakifd.getEntryRecursive(static_cast<TiffTag>(0x03fd));
+ if (blob && blob->count == 72) {
+ for (auto i = 0U; i < 3; i++) {
+ const auto mul = blob->getU16(20 + i);
+ if (0 == mul)
+ ThrowRDE("WB coeffient is zero!");
+ mRaw->metadata.wbCoeffs[i] = 2048.0F / mul;
+ }
+ }
+
+ KodakDecompressor k(mRaw, input, uncorrectedRawValues);
+ k.decompress();
+
+ return mRaw;
+}
+
+void DcrDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ setMetaData(meta, "", 0);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/DcrDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/DcrDecoder.h
new file mode 100644
index 000000000..44ed4c833
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/DcrDecoder.h
@@ -0,0 +1,51 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/SimpleTiffDecoder.h" // for SimpleTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class Buffer;
+
+class CameraMetaData;
+
+class DcrDecoder final : public SimpleTiffDecoder {
+ void checkImageDimensions() override;
+
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ DcrDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : SimpleTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/DcsDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/DcsDecoder.cpp
new file mode 100644
index 000000000..c91a69361
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/DcsDecoder.cpp
@@ -0,0 +1,77 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2015 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/DcsDecoder.h"
+#include "decoders/RawDecoderException.h" // for RawDecoderExcept...
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "tiff/TiffEntry.h" // for TiffEntry, TiffD...
+#include "tiff/TiffIFD.h" // for TiffRootIFD
+#include "tiff/TiffTag.h" // for TiffTag::GRAYRES...
+#include <cassert> // for assert
+#include <memory> // for unique_ptr
+#include <string> // for operator==, string
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+bool DcsDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "KODAK";
+}
+
+void DcsDecoder::checkImageDimensions() {
+ if (width > 3072 || height > 2048)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+}
+
+RawImage DcsDecoder::decodeRawInternal() {
+ SimpleTiffDecoder::prepareForRawDecoding();
+
+ TiffEntry *linearization = mRootIFD->getEntryRecursive(GRAYRESPONSECURVE);
+ if (!linearization || linearization->count != 256 || linearization->type != TIFF_SHORT)
+ ThrowRDE("Couldn't find the linearization table");
+
+ assert(linearization != nullptr);
+ auto table = linearization->getU16Array(256);
+
+ RawImageCurveGuard curveHandler(&mRaw, table, uncorrectedRawValues);
+
+ UncompressedDecompressor u(*mFile, off, c2, mRaw);
+
+ if (uncorrectedRawValues)
+ u.decode8BitRaw<true>(width, height);
+ else
+ u.decode8BitRaw<false>(width, height);
+
+ return mRaw;
+}
+
+void DcsDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ setMetaData(meta, "", 0);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/DcsDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/DcsDecoder.h
new file mode 100644
index 000000000..252aff385
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/DcsDecoder.h
@@ -0,0 +1,51 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/SimpleTiffDecoder.h" // for SimpleTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class Buffer;
+
+class CameraMetaData;
+
+class DcsDecoder final : public SimpleTiffDecoder {
+ void checkImageDimensions() override;
+
+public:
+ static bool __attribute__((pure))
+ isAppropriateDecoder(const TiffRootIFD* rootIFD, const Buffer* file);
+ DcsDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : SimpleTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/DngDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/DngDecoder.cpp
new file mode 100644
index 000000000..fab11206b
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/DngDecoder.cpp
@@ -0,0 +1,767 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h" // for HAVE_JPEG, HAVE_ZLIB
+#include "decoders/DngDecoder.h"
+#include "common/Common.h" // for uint32, writeLog
+#include "common/DngOpcodes.h" // for DngOpcodes
+#include "common/Point.h" // for iPoint2D, iRectan...
+#include "common/RawspeedException.h" // for RawspeedException
+#include "decoders/RawDecoderException.h" // for ThrowRDE, RawDeco...
+#include "decompressors/AbstractDngDecompressor.h" // for AbstractDngDecomp...
+#include "io/Buffer.h" // for Buffer
+#include "metadata/Camera.h" // for Camera
+#include "metadata/CameraMetaData.h" // for CameraMetaData
+#include "metadata/ColorFilterArray.h" // for CFAColor, ColorFi...
+#include "tiff/TiffEntry.h" // for TiffEntry, TiffDa...
+#include "tiff/TiffIFD.h" // for TiffIFD, TiffRootIFD
+#include "tiff/TiffTag.h" // for TiffTag::ACTIVEAREA
+#include <algorithm> // for move
+#include <cassert> // for assert
+#include <cstring> // for memset
+#include <limits> // for numeric_limits
+#include <map> // for map
+#include <memory> // for unique_ptr
+#include <stdexcept> // for out_of_range
+#include <string> // for string, operator+
+#include <vector> // for vector, allocator
+
+using std::vector;
+using std::map;
+using std::string;
+
+namespace rawspeed {
+
+bool __attribute__((pure))
+DngDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ return rootIFD->hasEntryRecursive(DNGVERSION);
+}
+
+DngDecoder::DngDecoder(TiffRootIFDOwner&& rootIFD, const Buffer* file)
+ : AbstractTiffDecoder(move(rootIFD), file) {
+ if (!mRootIFD->hasEntryRecursive(DNGVERSION))
+ ThrowRDE("DNG, but version tag is missing. Will not guess.");
+
+ const uchar8* v = mRootIFD->getEntryRecursive(DNGVERSION)->getData(4);
+
+ if (v[0] != 1)
+ ThrowRDE("Not a supported DNG image format: v%u.%u.%u.%u", (int)v[0], (int)v[1], (int)v[2], (int)v[3]);
+// if (v[1] > 4)
+// ThrowRDE("Not a supported DNG image format: v%u.%u.%u.%u", (int)v[0], (int)v[1], (int)v[2], (int)v[3]);
+
+ if ((v[0] <= 1) && (v[1] < 1)) // Prior to v1.1.xxx fix LJPEG encoding bug
+ mFixLjpeg = true;
+ else
+ mFixLjpeg = false;
+}
+
+void DngDecoder::dropUnsuportedChunks(std::vector<const TiffIFD*>* data) {
+ for (auto i = data->begin(); i != data->end();) {
+ const auto& ifd = *i;
+
+ int comp = ifd->getEntry(COMPRESSION)->getU16();
+ bool isSubsampled = false;
+ bool isAlpha = false;
+
+ if (ifd->hasEntry(NEWSUBFILETYPE) &&
+ ifd->getEntry(NEWSUBFILETYPE)->isInt()) {
+ const uint32 NewSubFileType = (*i)->getEntry(NEWSUBFILETYPE)->getU32();
+
+ // bit 0 is on if image is subsampled.
+ // the value itself can be either 1, or 0x10001.
+ // or 5 for "Transparency information for subsampled raw images"
+ isSubsampled = NewSubFileType & (1 << 0);
+
+ // bit 2 is on if image contains transparency information.
+ // the value itself can be either 4 or 5
+ isAlpha = NewSubFileType & (1 << 2);
+ }
+
+ // normal raw?
+ bool supported = !isSubsampled && !isAlpha;
+
+ switch (comp) {
+ case 1: // uncompressed
+ case 7: // lossless JPEG
+#ifdef HAVE_ZLIB
+ case 8: // deflate
+#endif
+#ifdef HAVE_JPEG
+ case 0x884c: // lossy JPEG
+#endif
+ // no change, if supported, then is still supported.
+ break;
+
+#ifndef HAVE_ZLIB
+ case 8: // deflate
+#pragma message \
+ "ZLIB is not present! Deflate compression will not be supported!"
+ writeLog(DEBUG_PRIO_WARNING, "DNG Decoder: found Deflate-encoded chunk, "
+ "but the deflate support was disabled at "
+ "build!");
+ [[clang::fallthrough]];
+#endif
+#ifndef HAVE_JPEG
+ case 0x884c: // lossy JPEG
+#pragma message \
+ "JPEG is not present! Lossy JPEG compression will not be supported!"
+ writeLog(DEBUG_PRIO_WARNING, "DNG Decoder: found lossy JPEG-encoded "
+ "chunk, but the jpeg support was "
+ "disabled at build!");
+ [[clang::fallthrough]];
+#endif
+ default:
+ supported = false;
+ break;
+ }
+
+ if (supported)
+ ++i;
+ else
+ i = data->erase(i);
+ }
+}
+
+void DngDecoder::parseCFA(const TiffIFD* raw) {
+
+ // Check if layout is OK, if present
+ if (raw->hasEntry(CFALAYOUT) && raw->getEntry(CFALAYOUT)->getU16() != 1)
+ ThrowRDE("Unsupported CFA Layout.");
+
+ TiffEntry* cfadim = raw->getEntry(CFAREPEATPATTERNDIM);
+ if (cfadim->count != 2)
+ ThrowRDE("Couldn't read CFA pattern dimension");
+
+ // Does NOT contain dimensions as some documents state
+ TiffEntry* cPat = raw->getEntry(CFAPATTERN);
+
+ iPoint2D cfaSize(cfadim->getU32(1), cfadim->getU32(0));
+ if (cfaSize.area() != cPat->count) {
+ ThrowRDE("CFA pattern dimension and pattern count does not "
+ "match: %d.",
+ cPat->count);
+ }
+
+ mRaw->cfa.setSize(cfaSize);
+
+ static const map<uint32, CFAColor> int2enum = {
+ {0, CFA_RED}, {1, CFA_GREEN}, {2, CFA_BLUE}, {3, CFA_CYAN},
+ {4, CFA_MAGENTA}, {5, CFA_YELLOW}, {6, CFA_WHITE},
+ };
+
+ for (int y = 0; y < cfaSize.y; y++) {
+ for (int x = 0; x < cfaSize.x; x++) {
+ uint32 c1 = cPat->getByte(x + y * cfaSize.x);
+ CFAColor c2 = CFA_UNKNOWN;
+
+ try {
+ c2 = int2enum.at(c1);
+ } catch (std::out_of_range&) {
+ ThrowRDE("Unsupported CFA Color: %u", c1);
+ }
+
+ mRaw->cfa.setColorAt(iPoint2D(x, y), c2);
+ }
+ }
+
+ // the cfa is specified relative to the ActiveArea. we want it relative (0,0)
+ // Since in handleMetadata(), in subFrame() we unconditionally shift CFA by
+ // activearea+DefaultCropOrigin; here we need to undo the 'ACTIVEAREA' part.
+ if (!raw->hasEntry(ACTIVEAREA))
+ return;
+
+ TiffEntry* active_area = raw->getEntry(ACTIVEAREA);
+ if (active_area->count != 4)
+ ThrowRDE("active area has %d values instead of 4", active_area->count);
+
+ const auto aa = active_area->getFloatArray(2);
+ if (std::any_of(aa.cbegin(), aa.cend(), [](const auto v) {
+ return v < std::numeric_limits<iPoint2D::value_type>::min() ||
+ v > std::numeric_limits<iPoint2D::value_type>::max();
+ }))
+ ThrowRDE("Error decoding active area");
+
+ mRaw->cfa.shiftLeft(aa[1]);
+ mRaw->cfa.shiftDown(aa[0]);
+}
+
+void DngDecoder::decodeData(const TiffIFD* raw, uint32 sample_format) {
+ if (compression == 8 && sample_format != 3) {
+ ThrowRDE("Only float format is supported for "
+ "deflate-compressed data.");
+ } else if ((compression == 7 || compression == 0x884c) &&
+ sample_format != 1) {
+ ThrowRDE("Only 16 bit unsigned data supported for "
+ "JPEG-compressed data.");
+ }
+
+ uint32 predictor = -1;
+ if (raw->hasEntry(PREDICTOR))
+ predictor = raw->getEntry(PREDICTOR)->getU32();
+
+ AbstractDngDecompressor slices(mRaw, compression, mFixLjpeg, bps, predictor);
+
+ if (raw->hasEntry(TILEOFFSETS)) {
+ const uint32 tilew = raw->getEntry(TILEWIDTH)->getU32();
+ const uint32 tileh = raw->getEntry(TILELENGTH)->getU32();
+
+ if (!(tilew > 0 && tileh > 0))
+ ThrowRDE("Invalid tile size: (%u, %u)", tilew, tileh);
+
+ assert(tilew > 0);
+ const uint32 tilesX = roundUpDivision(mRaw->dim.x, tilew);
+ if (!tilesX)
+ ThrowRDE("Zero tiles horizontally");
+
+ assert(tileh > 0);
+ const uint32 tilesY = roundUpDivision(mRaw->dim.y, tileh);
+ if (!tilesY)
+ ThrowRDE("Zero tiles vertically");
+
+ TiffEntry* offsets = raw->getEntry(TILEOFFSETS);
+ TiffEntry* counts = raw->getEntry(TILEBYTECOUNTS);
+ if (offsets->count != counts->count) {
+ ThrowRDE("Tile count mismatch: offsets:%u count:%u", offsets->count,
+ counts->count);
+ }
+
+ // tilesX * tilesY may overflow, but division is fine, so let's do that.
+ if (offsets->count / tilesX != tilesY ||
+ offsets->count / tilesY != tilesX) {
+ ThrowRDE("Tile X/Y count mismatch: total:%u X:%u, Y:%u", offsets->count,
+ tilesX, tilesY);
+ }
+
+ const uint32 nTiles = tilesX * tilesY;
+ assert(nTiles > 0);
+
+ slices.slices.reserve(nTiles);
+
+ for (uint32 y = 0; y < tilesY; y++) {
+ for (uint32 x = 0; x < tilesX; x++) {
+ const auto s = x + y * tilesX;
+ const auto offset = offsets->getU32(s);
+ const auto count = counts->getU32(s);
+
+ if (count < 1)
+ ThrowRDE("Tile %u;%u is empty", x, y);
+
+ ByteStream bs(mFile->getSubView(offset, count), 0);
+
+ const uint32 offX = tilew * x;
+ const uint32 offY = tileh * y;
+
+ DngSliceElement e(bs, offX, offY, tilew, tileh);
+ slices.slices.emplace_back(e);
+ }
+ }
+
+ assert(slices.slices.size() == nTiles);
+ } else { // Strips
+ TiffEntry* offsets = raw->getEntry(STRIPOFFSETS);
+ TiffEntry* counts = raw->getEntry(STRIPBYTECOUNTS);
+
+ if (counts->count != offsets->count) {
+ ThrowRDE("Byte count number does not match strip size: "
+ "count:%u, stips:%u ",
+ counts->count, offsets->count);
+ }
+
+ uint32 yPerSlice = raw->hasEntry(ROWSPERSTRIP) ?
+ raw->getEntry(ROWSPERSTRIP)->getU32() : mRaw->dim.y;
+
+ if (yPerSlice == 0 || yPerSlice > static_cast<uint32>(mRaw->dim.y) ||
+ roundUpDivision(mRaw->dim.y, yPerSlice) != counts->count) {
+ ThrowRDE("Invalid y per slice %u or strip count %u (height = %u)",
+ yPerSlice, counts->count, mRaw->dim.y);
+ }
+
+ slices.slices.reserve(counts->count);
+
+ uint32 offY = 0;
+ for (uint32 s = 0; s < counts->count; s++) {
+ const auto offset = offsets->getU32(s);
+ const auto count = counts->getU32(s);
+
+ if (count < 1)
+ ThrowRDE("Slice %u is empty", s);
+
+ assert(offY < static_cast<uint32>(mRaw->dim.y));
+
+ ByteStream bs(mFile->getSubView(offset, count), 0);
+ DngSliceElement e(bs, /*offsetX=*/0, offY, mRaw->dim.x, yPerSlice);
+
+ slices.slices.emplace_back(e);
+ offY += yPerSlice;
+ }
+
+ assert(static_cast<uint32>(mRaw->dim.y) <= offY);
+ assert(slices.slices.size() == counts->count);
+ }
+
+ if (slices.slices.empty())
+ ThrowRDE("No valid slices found.");
+
+ mRaw->createData();
+
+ slices.decompress();
+}
+
+RawImage DngDecoder::decodeRawInternal() {
+ vector<const TiffIFD*> data = mRootIFD->getIFDsWithTag(COMPRESSION);
+
+ if (data.empty())
+ ThrowRDE("No image data found");
+
+ dropUnsuportedChunks(&data);
+
+ if (data.empty())
+ ThrowRDE("No RAW chunks found");
+
+ if (data.size() > 1) {
+ writeLog(DEBUG_PRIO_EXTRA, "Multiple RAW chunks found - using first only!");
+ }
+
+ const TiffIFD* raw = data[0];
+
+ bps = raw->getEntry(BITSPERSAMPLE)->getU32();
+ if (bps < 1 || bps > 32)
+ ThrowRDE("Unsupported bit per sample count: %u.", bps);
+
+ uint32 sample_format = 1;
+ if (raw->hasEntry(SAMPLEFORMAT))
+ sample_format = raw->getEntry(SAMPLEFORMAT)->getU32();
+
+ compression = raw->getEntry(COMPRESSION)->getU16();
+
+ switch (sample_format) {
+ case 1:
+ mRaw = RawImage::create(TYPE_USHORT16);
+ break;
+ case 3:
+ mRaw = RawImage::create(TYPE_FLOAT32);
+ break;
+ default:
+ ThrowRDE("Only 16 bit unsigned or float point data supported. Sample "
+ "format %u is not supported.",
+ sample_format);
+ }
+
+ mRaw->isCFA = (raw->getEntry(PHOTOMETRICINTERPRETATION)->getU16() == 32803);
+
+ if (mRaw->isCFA)
+ writeLog(DEBUG_PRIO_EXTRA, "This is a CFA image");
+ else {
+ writeLog(DEBUG_PRIO_EXTRA, "This is NOT a CFA image");
+ }
+
+ if (sample_format == 1 && bps > 16)
+ ThrowRDE("Integer precision larger than 16 bits currently not supported.");
+
+ if (sample_format == 3 && bps != 32 && compression != 8)
+ ThrowRDE("Uncompressed float point must be 32 bits per sample.");
+
+ mRaw->dim.x = raw->getEntry(IMAGEWIDTH)->getU32();
+ mRaw->dim.y = raw->getEntry(IMAGELENGTH)->getU32();
+
+ if (mRaw->dim.x == 0 || mRaw->dim.y == 0)
+ ThrowRDE("Image has zero size");
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ // Yeah, sure, here it would be just dumb to leave this for production :)
+ if (mRaw->dim.x > 7424 || mRaw->dim.y > 5552) {
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x,
+ mRaw->dim.y);
+ }
+#endif
+
+ if (mRaw->isCFA)
+ parseCFA(raw);
+
+ uint32 cpp = raw->getEntry(SAMPLESPERPIXEL)->getU32();
+
+ if (cpp < 1 || cpp > 4)
+ ThrowRDE("Unsupported samples per pixel count: %u.", cpp);
+
+ mRaw->setCpp(cpp);
+
+ // Now load the image
+ decodeData(raw, sample_format);
+
+ handleMetadata(raw);
+
+ return mRaw;
+}
+
+void DngDecoder::handleMetadata(const TiffIFD* raw) {
+ // Crop
+ if (raw->hasEntry(ACTIVEAREA)) {
+ TiffEntry *active_area = raw->getEntry(ACTIVEAREA);
+ if (active_area->count != 4)
+ ThrowRDE("active area has %d values instead of 4", active_area->count);
+
+ const iRectangle2D fullImage(0, 0, mRaw->dim.x, mRaw->dim.y);
+
+ const auto corners = active_area->getU32Array(4);
+ const iPoint2D topLeft(corners[1], corners[0]);
+ const iPoint2D bottomRight(corners[3], corners[2]);
+
+ if (!(fullImage.isPointInsideInclusive(topLeft) &&
+ fullImage.isPointInsideInclusive(bottomRight) &&
+ bottomRight >= topLeft)) {
+ ThrowRDE("Rectangle (%u, %u, %u, %u) not inside image (%u, %u, %u, %u).",
+ topLeft.x, topLeft.y, bottomRight.x, bottomRight.y,
+ fullImage.getTopLeft().x, fullImage.getTopLeft().y,
+ fullImage.getBottomRight().x, fullImage.getBottomRight().y);
+ }
+
+ iRectangle2D crop;
+ crop.setTopLeft(topLeft);
+ crop.setBottomRightAbsolute(bottomRight);
+ assert(fullImage.isThisInside(fullImage));
+
+ mRaw->subFrame(crop);
+ }
+
+ if (raw->hasEntry(DEFAULTCROPORIGIN) && raw->hasEntry(DEFAULTCROPSIZE)) {
+ iRectangle2D cropped(0, 0, mRaw->dim.x, mRaw->dim.y);
+ TiffEntry *origin_entry = raw->getEntry(DEFAULTCROPORIGIN);
+ TiffEntry *size_entry = raw->getEntry(DEFAULTCROPSIZE);
+
+ /* Read crop position (sometimes is rational so use float) */
+ const auto tl = origin_entry->getFloatArray(2);
+ if (std::any_of(tl.cbegin(), tl.cend(), [](const auto v) {
+ return v < std::numeric_limits<iPoint2D::value_type>::min() ||
+ v > std::numeric_limits<iPoint2D::value_type>::max();
+ }))
+ ThrowRDE("Error decoding default crop origin");
+
+ iPoint2D cropOrigin(tl[0], tl[1]);
+ if (cropped.isPointInsideInclusive(cropOrigin))
+ cropped = iRectangle2D(cropOrigin, {0, 0});
+
+ cropped.dim = mRaw->dim - cropped.pos;
+
+ /* Read size (sometimes is rational so use float) */
+ const auto sz = size_entry->getFloatArray(2);
+ if (std::any_of(sz.cbegin(), sz.cend(), [](const auto v) {
+ return v < std::numeric_limits<iPoint2D::value_type>::min() ||
+ v > std::numeric_limits<iPoint2D::value_type>::max();
+ }))
+ ThrowRDE("Error decoding default crop size");
+
+ iPoint2D size(sz[0], sz[1]);
+ if ((size + cropped.pos).isThisInside(mRaw->dim))
+ cropped.dim = size;
+
+ if (!cropped.hasPositiveArea())
+ ThrowRDE("No positive crop area");
+
+ mRaw->subFrame(cropped);
+ }
+ if (mRaw->dim.area() <= 0)
+ ThrowRDE("No image left after crop");
+
+ // Apply stage 1 opcodes
+ if (applyStage1DngOpcodes && raw->hasEntry(OPCODELIST1)) {
+ try {
+ DngOpcodes codes(mRaw, raw->getEntry(OPCODELIST1));
+ codes.applyOpCodes(mRaw);
+ } catch (RawDecoderException& e) {
+ // We push back errors from the opcode parser, since the image may still
+ // be usable
+ mRaw->setError(e.what());
+ }
+ }
+
+ // Linearization
+ if (raw->hasEntry(LINEARIZATIONTABLE) &&
+ raw->getEntry(LINEARIZATIONTABLE)->count > 0) {
+ TiffEntry *lintable = raw->getEntry(LINEARIZATIONTABLE);
+ auto table = lintable->getU16Array(lintable->count);
+ RawImageCurveGuard curveHandler(&mRaw, table, uncorrectedRawValues);
+ if (!uncorrectedRawValues)
+ mRaw->sixteenBitLookup();
+ }
+
+ // Default white level is (2 ** BitsPerSample) - 1
+ mRaw->whitePoint = (1UL << bps) - 1UL;
+
+ if (raw->hasEntry(WHITELEVEL)) {
+ TiffEntry *whitelevel = raw->getEntry(WHITELEVEL);
+ if (whitelevel->isInt())
+ mRaw->whitePoint = whitelevel->getU32();
+ }
+ // Set black
+ setBlack(raw);
+
+ // Apply opcodes to lossy DNG
+ if (compression == 0x884c && !uncorrectedRawValues &&
+ raw->hasEntry(OPCODELIST2)) {
+ // We must apply black/white scaling
+ mRaw->scaleBlackWhite();
+
+ // Apply stage 2 codes
+ try {
+ DngOpcodes codes(mRaw, raw->getEntry(OPCODELIST2));
+ codes.applyOpCodes(mRaw);
+ } catch (RawDecoderException& e) {
+ // We push back errors from the opcode parser, since the image may still
+ // be usable
+ mRaw->setError(e.what());
+ }
+ mRaw->blackAreas.clear();
+ mRaw->blackLevel = 0;
+ mRaw->blackLevelSeparate[0] = mRaw->blackLevelSeparate[1] =
+ mRaw->blackLevelSeparate[2] = mRaw->blackLevelSeparate[3] = 0;
+ mRaw->whitePoint = 65535;
+ }
+}
+
+void DngDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
+ mRaw->metadata.isoSpeed = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32();
+
+ TiffID id;
+
+ try {
+ id = mRootIFD->getID();
+ } catch (RawspeedException& e) {
+ mRaw->setError(e.what());
+ // not all dngs have MAKE/MODEL entries,
+ // will be dealt with by using UNIQUECAMERAMODEL below
+ }
+
+ // Set the make and model
+ mRaw->metadata.make = id.make;
+ mRaw->metadata.model = id.model;
+
+ const Camera* cam = meta->getCamera(id.make, id.model, "dng");
+ if (!cam) //Also look for non-DNG cameras in case it's a converted file
+ cam = meta->getCamera(id.make, id.model, "");
+ if (!cam) // Worst case scenario, look for any such camera.
+ cam = meta->getCamera(id.make, id.model);
+ if (cam) {
+ mRaw->metadata.canonical_make = cam->canonical_make;
+ mRaw->metadata.canonical_model = cam->canonical_model;
+ mRaw->metadata.canonical_alias = cam->canonical_alias;
+ mRaw->metadata.canonical_id = cam->canonical_id;
+ } else {
+ mRaw->metadata.canonical_make = id.make;
+ mRaw->metadata.canonical_model = mRaw->metadata.canonical_alias = id.model;
+ if (mRootIFD->hasEntryRecursive(UNIQUECAMERAMODEL)) {
+ mRaw->metadata.canonical_id = mRootIFD->getEntryRecursive(UNIQUECAMERAMODEL)->getString();
+ } else {
+ mRaw->metadata.canonical_id = id.make + " " + id.model;
+ }
+ }
+
+ // Fetch the white balance
+ if (mRootIFD->hasEntryRecursive(ASSHOTNEUTRAL)) {
+ TiffEntry* as_shot_neutral = mRootIFD->getEntryRecursive(ASSHOTNEUTRAL);
+ if (as_shot_neutral->count == 3) {
+ for (uint32 i = 0; i < 3; i++) {
+ float c = as_shot_neutral->getFloat(i);
+ mRaw->metadata.wbCoeffs[i] = (c > 0.0F) ? (1.0F / c) : 0.0F;
+ }
+ }
+ } else if (mRootIFD->hasEntryRecursive(ASSHOTWHITEXY)) {
+ TiffEntry* as_shot_white_xy = mRootIFD->getEntryRecursive(ASSHOTWHITEXY);
+ if (as_shot_white_xy->count == 2) {
+ mRaw->metadata.wbCoeffs[0] = as_shot_white_xy->getFloat(0);
+ mRaw->metadata.wbCoeffs[1] = as_shot_white_xy->getFloat(1);
+ mRaw->metadata.wbCoeffs[2] =
+ 1 - mRaw->metadata.wbCoeffs[0] - mRaw->metadata.wbCoeffs[1];
+
+ const float d65_white[3] = {0.950456, 1, 1.088754};
+ for (uint32 i = 0; i < 3; i++)
+ mRaw->metadata.wbCoeffs[i] /= d65_white[i];
+ }
+ }
+}
+
+/* DNG Images are assumed to be decodable unless explicitly set so */
+void DngDecoder::checkSupportInternal(const CameraMetaData* meta) {
+ // We set this, since DNG's are not explicitly added.
+ failOnUnknown = false;
+
+ if (!(mRootIFD->hasEntryRecursive(MAKE) && mRootIFD->hasEntryRecursive(MODEL))) {
+ // Check "Unique Camera Model" instead, uses this for both make + model.
+ if (mRootIFD->hasEntryRecursive(UNIQUECAMERAMODEL)) {
+ string unique = mRootIFD->getEntryRecursive(UNIQUECAMERAMODEL)->getString();
+ checkCameraSupported(meta, {unique, unique}, "dng");
+ return;
+ }
+ // If we don't have make/model we cannot tell, but still assume yes.
+ return;
+ }
+
+ checkCameraSupported(meta, mRootIFD->getID(), "dng");
+}
+
+/* Decodes DNG masked areas into blackareas in the image */
+bool DngDecoder::decodeMaskedAreas(const TiffIFD* raw) {
+ TiffEntry *masked = raw->getEntry(MASKEDAREAS);
+
+ if (masked->type != TIFF_SHORT && masked->type != TIFF_LONG)
+ return false;
+
+ uint32 nrects = masked->count/4;
+ if (0 == nrects)
+ return false;
+
+ /* Since we may both have short or int, copy it to int array. */
+ auto rects = masked->getU32Array(nrects*4);
+
+ const iRectangle2D fullImage(0, 0, mRaw->getUncroppedDim().x - 1,
+ mRaw->getUncroppedDim().y - 1);
+ const iPoint2D top = mRaw->getCropOffset();
+
+ for (uint32 i = 0; i < nrects; i++) {
+ iPoint2D topleft = iPoint2D(rects[i * 4UL + 1UL], rects[i * 4UL]);
+ iPoint2D bottomright = iPoint2D(rects[i * 4UL + 3UL], rects[i * 4UL + 2UL]);
+
+ if (!(fullImage.isPointInsideInclusive(topleft) &&
+ fullImage.isPointInsideInclusive(bottomright) &&
+ (topleft < bottomright)))
+ ThrowRDE("Bad masked area.");
+
+ // Is this a horizontal box, only add it if it covers the active width of the image
+ if (topleft.x <= top.x && bottomright.x >= (mRaw->dim.x + top.x)) {
+ mRaw->blackAreas.emplace_back(topleft.y, bottomright.y - topleft.y,
+ false);
+ }
+ // Is it a vertical box, only add it if it covers the active height of the
+ // image
+ else if (topleft.y <= top.y && bottomright.y >= (mRaw->dim.y + top.y)) {
+ mRaw->blackAreas.emplace_back(topleft.x, bottomright.x - topleft.x, true);
+ }
+ }
+ return !mRaw->blackAreas.empty();
+}
+
+bool DngDecoder::decodeBlackLevels(const TiffIFD* raw) {
+ iPoint2D blackdim(1,1);
+ if (raw->hasEntry(BLACKLEVELREPEATDIM)) {
+ TiffEntry *bleveldim = raw->getEntry(BLACKLEVELREPEATDIM);
+ if (bleveldim->count != 2)
+ return false;
+ blackdim = iPoint2D(bleveldim->getU32(0), bleveldim->getU32(1));
+ }
+
+ if (blackdim.x == 0 || blackdim.y == 0)
+ return false;
+
+ if (!raw->hasEntry(BLACKLEVEL))
+ return true;
+
+ if (mRaw->getCpp() != 1)
+ return false;
+
+ TiffEntry* black_entry = raw->getEntry(BLACKLEVEL);
+ if (black_entry->count < blackdim.area())
+ ThrowRDE("BLACKLEVEL entry is too small");
+
+ using BlackType = decltype(mRaw->blackLevelSeparate)::value_type;
+
+ if (blackdim.x < 2 || blackdim.y < 2) {
+ // We so not have enough to fill all individually, read a single and copy it
+ float value = black_entry->getFloat();
+
+ if (value < std::numeric_limits<BlackType>::min() ||
+ value > std::numeric_limits<BlackType>::max())
+ ThrowRDE("Error decoding black level");
+
+ for (int y = 0; y < 2; y++) {
+ for (int x = 0; x < 2; x++)
+ mRaw->blackLevelSeparate[y*2+x] = value;
+ }
+ } else {
+ for (int y = 0; y < 2; y++) {
+ for (int x = 0; x < 2; x++) {
+ float value = black_entry->getFloat(y * blackdim.x + x);
+
+ if (value < std::numeric_limits<BlackType>::min() ||
+ value > std::numeric_limits<BlackType>::max())
+ ThrowRDE("Error decoding black level");
+
+ mRaw->blackLevelSeparate[y * 2 + x] = value;
+ }
+ }
+ }
+
+ // DNG Spec says we must add black in deltav and deltah
+ if (raw->hasEntry(BLACKLEVELDELTAV)) {
+ TiffEntry *blackleveldeltav = raw->getEntry(BLACKLEVELDELTAV);
+ if (static_cast<int>(blackleveldeltav->count) < mRaw->dim.y)
+ ThrowRDE("BLACKLEVELDELTAV array is too small");
+ float black_sum[2] = {0.0F, 0.0F};
+ for (int i = 0; i < mRaw->dim.y; i++)
+ black_sum[i&1] += blackleveldeltav->getFloat(i);
+
+ for (int i = 0; i < 4; i++) {
+ const float value =
+ black_sum[i >> 1] / static_cast<float>(mRaw->dim.y) * 2.0F;
+ if (value < std::numeric_limits<BlackType>::min() ||
+ value > std::numeric_limits<BlackType>::max())
+ ThrowRDE("Error decoding black level");
+
+ if (__builtin_sadd_overflow(mRaw->blackLevelSeparate[i], value,
+ &mRaw->blackLevelSeparate[i]))
+ ThrowRDE("Integer overflow when calculating black level");
+ }
+ }
+
+ if (raw->hasEntry(BLACKLEVELDELTAH)){
+ TiffEntry *blackleveldeltah = raw->getEntry(BLACKLEVELDELTAH);
+ if (static_cast<int>(blackleveldeltah->count) < mRaw->dim.x)
+ ThrowRDE("BLACKLEVELDELTAH array is too small");
+ float black_sum[2] = {0.0F, 0.0F};
+ for (int i = 0; i < mRaw->dim.x; i++)
+ black_sum[i&1] += blackleveldeltah->getFloat(i);
+
+ for (int i = 0; i < 4; i++) {
+ const float value =
+ black_sum[i & 1] / static_cast<float>(mRaw->dim.x) * 2.0F;
+ if (value < std::numeric_limits<BlackType>::min() ||
+ value > std::numeric_limits<BlackType>::max())
+ ThrowRDE("Error decoding black level");
+
+ if (__builtin_sadd_overflow(mRaw->blackLevelSeparate[i], value,
+ &mRaw->blackLevelSeparate[i]))
+ ThrowRDE("Integer overflow when calculating black level");
+ }
+ }
+ return true;
+}
+
+void DngDecoder::setBlack(const TiffIFD* raw) {
+
+ if (raw->hasEntry(MASKEDAREAS) && decodeMaskedAreas(raw))
+ return;
+
+ // Black defaults to 0
+ mRaw->blackLevelSeparate.fill(0);
+
+ if (raw->hasEntry(BLACKLEVEL))
+ decodeBlackLevels(raw);
+}
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/DngDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/DngDecoder.h
new file mode 100644
index 000000000..c4e44bcf0
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/DngDecoder.h
@@ -0,0 +1,62 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffIFD (ptr only), TiffRo...
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+class Buffer;
+
+class DngDecoder final : public AbstractTiffDecoder
+{
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ DngDecoder(TiffRootIFDOwner&& rootIFD, const Buffer* file);
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+ void checkSupportInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+ bool mFixLjpeg;
+ void dropUnsuportedChunks(std::vector<const TiffIFD*>* data);
+ void parseCFA(const TiffIFD* raw);
+ void decodeData(const TiffIFD* raw, uint32 sample_format);
+ void handleMetadata(const TiffIFD* raw);
+ bool decodeMaskedAreas(const TiffIFD* raw);
+ bool decodeBlackLevels(const TiffIFD* raw);
+ void setBlack(const TiffIFD* raw);
+
+private:
+ int bps = -1;
+ int compression = -1;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/ErfDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/ErfDecoder.cpp
new file mode 100644
index 000000000..d6f475784
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/ErfDecoder.cpp
@@ -0,0 +1,77 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/ErfDecoder.h"
+#include "decoders/RawDecoderException.h" // for RawDecoderExcept...
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/Endianness.h" // for Endianness::big
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffRootIFD
+#include "tiff/TiffTag.h" // for TiffTag::EPSONWB
+#include <memory> // for unique_ptr
+#include <string> // for operator==, string
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+bool ErfDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "SEIKO EPSON CORP.";
+}
+
+void ErfDecoder::checkImageDimensions() {
+ if (width > 3040 || height > 2024)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+}
+
+RawImage ErfDecoder::decodeRawInternal() {
+ SimpleTiffDecoder::prepareForRawDecoding();
+
+ UncompressedDecompressor u(*mFile, off, c2, mRaw);
+
+ u.decode12BitRaw<Endianness::big, false, true>(width, height);
+
+ return mRaw;
+}
+
+void ErfDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ setMetaData(meta, "", 0);
+
+ if (mRootIFD->hasEntryRecursive(EPSONWB)) {
+ TiffEntry *wb = mRootIFD->getEntryRecursive(EPSONWB);
+ if (wb->count == 256) {
+ // Magic values taken directly from dcraw
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(wb->getU16(24)) * 508.0F *
+ 1.078F / static_cast<float>(0x10000);
+ mRaw->metadata.wbCoeffs[1] = 1.0F;
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(wb->getU16(25)) * 382.0F *
+ 1.173F / static_cast<float>(0x10000);
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/ErfDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/ErfDecoder.h
new file mode 100644
index 000000000..b884b4099
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/ErfDecoder.h
@@ -0,0 +1,51 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/SimpleTiffDecoder.h" // for SimpleTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class Buffer;
+
+class CameraMetaData;
+
+class ErfDecoder final : public SimpleTiffDecoder {
+ void checkImageDimensions() override;
+
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ ErfDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : SimpleTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/IiqDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/IiqDecoder.cpp
new file mode 100644
index 000000000..7afa70f4f
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/IiqDecoder.cpp
@@ -0,0 +1,384 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014-2015 Pedro Côrte-Real
+ Copyright (C) 2017-2018 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/IiqDecoder.h"
+#include "common/Common.h" // for uint32, int32, ushort16
+#include "common/Point.h" // for iPoint2D
+#include "common/Spline.h" // for calculateCurve
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "io/BitPumpMSB32.h" // for BitPumpMSB32
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::li...
+#include "tiff/TiffIFD.h" // for TiffRootIFD, TiffID
+#include <algorithm> // for move, sort, adjacent_find
+#include <cassert> // for assert
+#include <functional> // for greater_equal
+#include <iterator> // for advance, begin, end, next
+#include <memory> // for unique_ptr
+#include <string> // for operator==, string
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+bool IiqDecoder::isAppropriateDecoder(const Buffer* file) {
+ assert(file);
+
+ const DataBuffer db(*file, Endianness::little);
+
+ // The IIQ magic. Is present for all IIQ raws.
+ return db.get<uint32>(8) == 0x49494949;
+}
+
+bool IiqDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ return IiqDecoder::isAppropriateDecoder(file) &&
+ (make == "Phase One A/S" || make == "Leaf");
+}
+
+// FIXME: this is very close to SamsungV0Decompressor::computeStripes()
+std::vector<IiqDecoder::IiqStrip>
+IiqDecoder::computeSripes(const Buffer& raw_data,
+ std::vector<IiqOffset>&& offsets,
+ uint32 height) const {
+ assert(height > 0);
+ assert(offsets.size() == (1 + height));
+
+ ByteStream bs(DataBuffer(raw_data, Endianness::little));
+
+ // so... here's the thing. offsets are not guaranteed to be in
+ // monotonically increasing order. so for each element of 'offsets',
+ // we need to find element which specifies next larger offset.
+ // and only then by subtracting those two offsets we get the slice size.
+
+ std::sort(offsets.begin(), offsets.end(),
+ [](const IiqOffset& a, const IiqOffset& b) {
+ if (a.offset == b.offset && &a != &b)
+ ThrowRDE("Two identical offsets found. Corrupt raw.");
+ return a.offset < b.offset;
+ });
+
+ std::vector<IiqDecoder::IiqStrip> slices;
+ slices.reserve(height);
+
+ auto offset_iterator = std::begin(offsets);
+ bs.skipBytes(offset_iterator->offset);
+
+ auto next_offset_iterator = std::next(offset_iterator);
+ while (next_offset_iterator < std::end(offsets)) {
+ assert(next_offset_iterator->offset > offset_iterator->offset);
+ const auto size = next_offset_iterator->offset - offset_iterator->offset;
+ assert(size > 0);
+
+ slices.emplace_back(offset_iterator->n, bs.getStream(size));
+
+ std::advance(offset_iterator, 1);
+ std::advance(next_offset_iterator, 1);
+ }
+
+ assert(slices.size() == height);
+
+ return slices;
+}
+
+RawImage IiqDecoder::decodeRawInternal() {
+ const Buffer buf(mFile->getSubView(8));
+ const DataBuffer db(buf, Endianness::little);
+ ByteStream bs(db);
+
+ bs.skipBytes(4); // Phase One magic
+ bs.skipBytes(4); // padding?
+
+ const auto origPos = bs.getPosition();
+
+ const uint32 entries_offset = bs.getU32();
+
+ bs.setPosition(entries_offset);
+
+ const uint32 entries_count = bs.getU32();
+ bs.skipBytes(4); // ???
+
+ // this is how much is to be read for all the entries
+ ByteStream es(bs.getStream(entries_count, 16));
+
+ bs.setPosition(origPos);
+
+ uint32 width = 0;
+ uint32 height = 0;
+ uint32 split_row = 0;
+ uint32 split_col = 0;
+
+ Buffer raw_data;
+ ByteStream block_offsets;
+ ByteStream wb;
+ ByteStream correction_meta_data;
+
+ for (uint32 entry = 0; entry < entries_count; entry++) {
+ const uint32 tag = es.getU32();
+ es.skipBytes(4); // type
+ const uint32 len = es.getU32();
+ const uint32 data = es.getU32();
+
+ switch (tag) {
+ case 0x107:
+ wb = bs.getSubStream(data, len);
+ break;
+ case 0x108:
+ width = data;
+ break;
+ case 0x109:
+ height = data;
+ break;
+ case 0x10f:
+ raw_data = bs.getSubView(data, len);
+ break;
+ case 0x110:
+ correction_meta_data = bs.getSubStream(data);
+ break;
+ case 0x21c:
+ // they are not guaranteed to be sequential!
+ block_offsets = bs.getSubStream(data, len);
+ break;
+ case 0x21d:
+ black_level = data >> 2;
+ break;
+ case 0x222:
+ split_col = data;
+ break;
+ case 0x224:
+ split_row = data;
+ break;
+ default:
+ // FIXME: is there a "block_sizes" entry?
+ break;
+ }
+ }
+
+ // FIXME: could be wrong. max "active pixels" in "Sensor+" mode - "101 MP"
+ if (width == 0 || height == 0 || width > 11608 || height > 8708)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ if (split_col > width || split_row > height)
+ ThrowRDE("Invalid sensor quadrant split values (%u, %u)", split_row,
+ split_col);
+
+ block_offsets = block_offsets.getStream(height, sizeof(uint32));
+
+ std::vector<IiqOffset> offsets;
+ offsets.reserve(1 + height);
+
+ for (uint32 row = 0; row < height; row++)
+ offsets.emplace_back(row, block_offsets.getU32());
+
+ // to simplify slice size calculation, we insert a dummy offset,
+ // which will be used much like end()
+ offsets.emplace_back(height, raw_data.getSize());
+
+ const std::vector<IiqStrip> strips(
+ computeSripes(raw_data, std::move(offsets), height));
+
+ mRaw->dim = iPoint2D(width, height);
+ mRaw->createData();
+
+ DecodePhaseOneC(strips, width, height);
+ if (correction_meta_data.getSize() != 0 && iiq)
+ CorrectPhaseOneC(correction_meta_data, split_row, split_col);
+
+ for (int i = 0; i < 3; i++)
+ mRaw->metadata.wbCoeffs[i] = wb.getFloat();
+
+ return mRaw;
+}
+
+void IiqDecoder::DecodeStrip(const IiqStrip& strip, uint32 width,
+ uint32 height) {
+ const int length[] = {8, 7, 6, 9, 11, 10, 5, 12, 14, 13};
+
+ BitPumpMSB32 pump(strip.bs);
+
+ int32 pred[2];
+ uint32 len[2];
+ pred[0] = pred[1] = 0;
+ auto* img = reinterpret_cast<ushort16*>(mRaw->getData(0, strip.n));
+ for (uint32 col = 0; col < width; col++) {
+ if (col >= (width & -8))
+ len[0] = len[1] = 14;
+ else if ((col & 7) == 0) {
+ for (unsigned int& i : len) {
+ int j = 0;
+
+ for (; j < 5; j++) {
+ if (pump.getBits(1) != 0) {
+ if (col == 0)
+ ThrowRDE("Can not initialize lenghts. Data is corrupt.");
+
+ // else, we have previously initialized lenghts, so we are fine
+ break;
+ }
+ }
+
+ assert((col == 0 && j > 0) || col != 0);
+ if (j > 0)
+ i = length[2 * (j - 1) + pump.getBits(1)];
+ }
+ }
+
+ int i = len[col & 1];
+ if (i == 14)
+ img[col] = pred[col & 1] = pump.getBits(16);
+ else
+ img[col] = pred[col & 1] +=
+ static_cast<signed>(pump.getBits(i)) + 1 - (1 << (i - 1));
+ }
+}
+
+void IiqDecoder::DecodePhaseOneC(const std::vector<IiqStrip>& strips,
+ uint32 width, uint32 height) {
+ for (const auto& strip : strips)
+ DecodeStrip(strip, width, height);
+}
+
+void IiqDecoder::CorrectPhaseOneC(ByteStream meta_data, uint32 split_row,
+ uint32 split_col) {
+ meta_data.skipBytes(8);
+ const uint32 bytes_to_entries = meta_data.getU32();
+ meta_data.setPosition(bytes_to_entries);
+ const uint32 entries_count = meta_data.getU32();
+ meta_data.skipBytes(4);
+
+ // this is how much is to be read for all the entries
+ ByteStream entries(meta_data.getStream(entries_count, 12));
+ meta_data.setPosition(0);
+
+ for (uint32 entry = 0; entry < entries_count; entry++) {
+ const uint32 tag = entries.getU32();
+ const uint32 len = entries.getU32();
+ const uint32 offset = entries.getU32();
+
+ switch (tag) {
+ case 0x431:
+ if (!iiq.quadrantMultipliers)
+ return;
+
+ CorrectQuadrantMultipliersCombined(meta_data.getSubStream(offset, len),
+ split_row, split_col);
+ return;
+ default:
+ break;
+ }
+ }
+}
+
+// This method defines a correction that compensates for the fact that
+// IIQ files may come from a camera with multiple (four, in this case)
+// sensors combined into a single "sensor." Because the different
+// sensors may have slightly different responses, we need to multiply
+// the pixels in each by a correction factor to ensure that they blend
+// together smoothly. The correction factor is not a single
+// multiplier, but a curve defined by seven control points. Each
+// curve's control points share the same seven X-coordinates.
+void IiqDecoder::CorrectQuadrantMultipliersCombined(ByteStream data,
+ uint32 split_row,
+ uint32 split_col) {
+ std::array<uint32, 9> shared_x_coords;
+
+ // Read the middle seven points from the file
+ std::generate_n(std::next(shared_x_coords.begin()), 7,
+ [&data] { return data.getU32(); });
+
+ // All the curves include (0, 0) and (65535, 65535),
+ // so the first and last points are predefined
+ shared_x_coords.front() = 0;
+ shared_x_coords.back() = 65535;
+
+ // Check that the middle coordinates make sense.
+ if (std::adjacent_find(shared_x_coords.cbegin(), shared_x_coords.cend(),
+ std::greater_equal<>()) != shared_x_coords.cend())
+ ThrowRDE("The X coordinates must all be strictly increasing");
+
+ std::array<std::array<std::vector<iPoint2D>, 2>, 2> control_points;
+ for (auto& quadRow : control_points) {
+ for (auto& quadrant : quadRow) {
+ quadrant.reserve(9);
+ quadrant.emplace_back(0, 0);
+
+ for (int i = 1; i < 8; i++) {
+ // These multipliers are expressed in ten-thousandths in the
+ // file
+ const uint64 y_coord =
+ (uint64(data.getU32()) * shared_x_coords[i]) / 10000ULL;
+ if (y_coord > 65535)
+ ThrowRDE("The Y coordinate %llu is too large", y_coord);
+ quadrant.emplace_back(shared_x_coords[i], y_coord);
+ }
+
+ quadrant.emplace_back(65535, 65535);
+ assert(quadrant.size() == 9);
+ }
+ }
+
+ for (int quadRow = 0; quadRow < 2; quadRow++) {
+ for (int quadCol = 0; quadCol < 2; quadCol++) {
+ const Spline<> s(control_points[quadRow][quadCol]);
+ const std::vector<ushort16> curve = s.calculateCurve();
+
+ int row_start = quadRow == 0 ? 0 : split_row;
+ int row_end = quadRow == 0 ? split_row : mRaw->dim.y;
+ int col_start = quadCol == 0 ? 0 : split_col;
+ int col_end = quadCol == 0 ? split_col : mRaw->dim.x;
+
+ for (int row = row_start; row < row_end; row++) {
+ auto* pixel =
+ reinterpret_cast<ushort16*>(mRaw->getData(col_start, row));
+ for (int col = col_start; col < col_end; col++, pixel++) {
+ // This adjustment is expected to be made with the
+ // black-level already subtracted from the pixel values.
+ // Because this is kept as metadata and not subtracted at
+ // this point, to make the correction work we subtract the
+ // appropriate amount before indexing into the curve and
+ // then add it back so that subtracting the black level
+ // later will work as expected
+ const ushort16 diff = *pixel < black_level ? *pixel : black_level;
+ *pixel = curve[*pixel - diff] + diff;
+ }
+ }
+ }
+ }
+}
+
+void IiqDecoder::checkSupportInternal(const CameraMetaData* meta) {
+ checkCameraSupported(meta, mRootIFD->getID(), "");
+}
+
+void IiqDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ setMetaData(meta, "", 0);
+
+ if (black_level)
+ mRaw->blackLevel = black_level;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/IiqDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/IiqDecoder.h
new file mode 100644
index 000000000..d414b2dbe
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/IiqDecoder.h
@@ -0,0 +1,82 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "io/ByteStream.h" // for ByteStream
+#include "tiff/TiffIFD.h" // for TiffRootIFD (ptr only)
+#include <algorithm> // for move
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class CameraMetaData;
+class Buffer;
+
+class IiqDecoder final : public AbstractTiffDecoder {
+ struct IiqOffset {
+ uint32 n;
+ uint32 offset;
+
+ IiqOffset() = default;
+ IiqOffset(uint32 block, uint32 offset_) : n(block), offset(offset_) {}
+ };
+
+ struct IiqStrip {
+ const int n;
+ const ByteStream bs;
+
+ IiqStrip(int block, ByteStream bs_) : n(block), bs(std::move(bs_)) {}
+ };
+
+ std::vector<IiqStrip> computeSripes(const Buffer& raw_data,
+ std::vector<IiqOffset>&& offsets,
+ uint32 height) const;
+
+ void DecodeStrip(const IiqStrip& strip, uint32 width, uint32 height);
+
+public:
+ static bool isAppropriateDecoder(const Buffer* file);
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+
+ IiqDecoder(TiffRootIFDOwner&& rootIFD, const Buffer* file)
+ : AbstractTiffDecoder(move(rootIFD), file) {}
+
+ RawImage decodeRawInternal() override;
+ void checkSupportInternal(const CameraMetaData* meta) override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+ uint32 black_level = 0;
+ void DecodePhaseOneC(const std::vector<IiqStrip>& strips, uint32 width,
+ uint32 height);
+ void CorrectPhaseOneC(ByteStream meta_data, uint32 split_row,
+ uint32 split_col);
+ void CorrectQuadrantMultipliersCombined(ByteStream data, uint32 split_row,
+ uint32 split_col);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/KdcDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/KdcDecoder.cpp
new file mode 100644
index 000000000..6c83d073a
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/KdcDecoder.cpp
@@ -0,0 +1,135 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014-2015 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/KdcDecoder.h"
+#include "common/Common.h" // for uint32, ushort16
+#include "common/NORangesSet.h" // for NORangesSet
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for RawDecoderExcept...
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/Buffer.h" // for Buffer
+#include "io/Endianness.h" // for Endiannes
+#include "metadata/Camera.h" // for Hints
+#include "parsers/TiffParserException.h" // for TiffParserException
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffRootIFD
+#include "tiff/TiffTag.h" // for TiffTag::COMPRES...
+#include <cassert> // for assert
+#include <memory> // for unique_ptr
+#include <string> // for operator==, string
+
+namespace rawspeed {
+
+bool KdcDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "EASTMAN KODAK COMPANY";
+}
+
+RawImage KdcDecoder::decodeRawInternal() {
+ if (!mRootIFD->hasEntryRecursive(COMPRESSION))
+ ThrowRDE("Couldn't find compression setting");
+
+ int compression = mRootIFD->getEntryRecursive(COMPRESSION)->getU32();
+ if (7 != compression)
+ ThrowRDE("Unsupported compression %d", compression);
+
+ uint32 width = 0;
+ uint32 height = 0;
+ TiffEntry *ew = mRootIFD->getEntryRecursive(KODAK_KDC_WIDTH);
+ TiffEntry *eh = mRootIFD->getEntryRecursive(KODAK_KDC_HEIGHT);
+ if (ew && eh) {
+ width = ew->getU32()+80;
+ height = eh->getU32()+70;
+ } else
+ ThrowRDE("Unable to retrieve image size");
+
+ TiffEntry *offset = mRootIFD->getEntryRecursive(KODAK_KDC_OFFSET);
+ if (!offset || offset->count < 13)
+ ThrowRDE("Couldn't find the KDC offset");
+
+ assert(offset != nullptr);
+ uint32 off = offset->getU32(4) + offset->getU32(12);
+
+ // Offset hardcoding gotten from dcraw
+ if (hints.has("easyshare_offset_hack"))
+ off = off < 0x15000 ? 0x15000 : 0x17000;
+
+ if (off > mFile->getSize())
+ ThrowRDE("offset is out of bounds");
+
+ mRaw->dim = iPoint2D(width, height);
+ mRaw->createData();
+
+ UncompressedDecompressor u(*mFile, off, mRaw);
+
+ u.decode12BitRaw<Endianness::big>(width, height);
+
+ return mRaw;
+}
+
+void KdcDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ setMetaData(meta, "", 0);
+
+ // Try the kodak hidden IFD for WB
+ if (mRootIFD->hasEntryRecursive(KODAK_IFD2)) {
+ TiffEntry *ifdoffset = mRootIFD->getEntryRecursive(KODAK_IFD2);
+ try {
+ NORangesSet<Buffer> ifds;
+
+ TiffRootIFD kodakifd(nullptr, &ifds, ifdoffset->getRootIfdData(),
+ ifdoffset->getU32());
+
+ if (kodakifd.hasEntryRecursive(KODAK_KDC_WB)) {
+ TiffEntry *wb = kodakifd.getEntryRecursive(KODAK_KDC_WB);
+ if (wb->count == 3) {
+ mRaw->metadata.wbCoeffs[0] = wb->getFloat(0);
+ mRaw->metadata.wbCoeffs[1] = wb->getFloat(1);
+ mRaw->metadata.wbCoeffs[2] = wb->getFloat(2);
+ }
+ }
+ } catch (TiffParserException &e) {
+ mRaw->setError(e.what());
+ }
+ }
+
+ // Use the normal WB if available
+ if (mRootIFD->hasEntryRecursive(KODAKWB)) {
+ TiffEntry *wb = mRootIFD->getEntryRecursive(KODAKWB);
+ if (wb->count == 734 || wb->count == 1502) {
+ mRaw->metadata.wbCoeffs[0] =
+ static_cast<float>(((static_cast<ushort16>(wb->getByte(148))) << 8) |
+ wb->getByte(149)) /
+ 256.0F;
+ mRaw->metadata.wbCoeffs[1] = 1.0F;
+ mRaw->metadata.wbCoeffs[2] =
+ static_cast<float>(((static_cast<ushort16>(wb->getByte(150))) << 8) |
+ wb->getByte(151)) /
+ 256.0F;
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/KdcDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/KdcDecoder.h
new file mode 100644
index 000000000..ebd20372d
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/KdcDecoder.h
@@ -0,0 +1,50 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class Buffer;
+
+class CameraMetaData;
+
+class KdcDecoder final : public AbstractTiffDecoder
+{
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ KdcDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : AbstractTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/MefDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/MefDecoder.cpp
new file mode 100644
index 000000000..72209e6ae
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/MefDecoder.cpp
@@ -0,0 +1,59 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/MefDecoder.h"
+#include "decoders/RawDecoderException.h" // for RawDecoderException (ptr o...
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/Endianness.h" // for Endianness::big
+#include <string> // for operator==, string
+
+namespace rawspeed {
+
+bool MefDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "Mamiya-OP Co.,Ltd.";
+}
+
+void MefDecoder::checkImageDimensions() {
+ if (width > 4016 || height > 5344)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+}
+
+RawImage MefDecoder::decodeRawInternal() {
+ SimpleTiffDecoder::prepareForRawDecoding();
+
+ UncompressedDecompressor u(*mFile, off, mRaw);
+
+ u.decode12BitRaw<Endianness::big>(width, height);
+
+ return mRaw;
+}
+
+void MefDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ setMetaData(meta, "", 0);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/MefDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/MefDecoder.h
new file mode 100644
index 000000000..eb336f1b7
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/MefDecoder.h
@@ -0,0 +1,50 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/SimpleTiffDecoder.h" // for SimpleTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class CameraMetaData;
+class Buffer;
+
+class MefDecoder final : public SimpleTiffDecoder {
+ void checkImageDimensions() override;
+
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ MefDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : SimpleTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/MosDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/MosDecoder.cpp
new file mode 100644
index 000000000..3c2e0bbfd
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/MosDecoder.cpp
@@ -0,0 +1,181 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014-2015 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/MosDecoder.h"
+#include "common/Common.h" // for uint32, uchar8
+#include "common/Point.h" // for iPoint2D
+#include "decoders/IiqDecoder.h" // for IiqDecoder::isAppr...
+#include "decoders/RawDecoder.h" // for RawDecoder
+#include "decoders/RawDecoderException.h" // for RawDecoderExcept...
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for getU32LE, getLE
+#include "parsers/TiffParserException.h" // for TiffParserException
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffRootIFD, Tif...
+#include "tiff/TiffTag.h" // for TiffTag::TILEOFF...
+#include <algorithm> // for move
+#include <cassert> // for assert
+#include <cstring> // for memchr
+#include <istream> // for istringstream
+#include <memory> // for unique_ptr
+#include <string> // for string, allocator
+
+using std::string;
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+bool MosDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ try {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // This is messy. see https://github.com/darktable-org/rawspeed/issues/116
+ // Old Leafs are MOS, new ones are IIQ. Use IIQ's magic to differentiate.
+ return make == "Leaf" && !IiqDecoder::isAppropriateDecoder(file);
+ } catch (const TiffParserException&) {
+ // Last ditch effort to identify Leaf cameras that don't have a Tiff Make
+ // set
+ TiffEntry* softwareIFD = rootIFD->getEntryRecursive(SOFTWARE);
+ if (!softwareIFD)
+ return false;
+
+ const string software = trimSpaces(softwareIFD->getString());
+ return software == "Camera Library";
+ }
+}
+
+MosDecoder::MosDecoder(TiffRootIFDOwner&& rootIFD, const Buffer* file)
+ : AbstractTiffDecoder(move(rootIFD), file) {
+ if (mRootIFD->getEntryRecursive(MAKE)) {
+ auto id = mRootIFD->getID();
+ make = id.make;
+ model = id.model;
+ } else {
+ TiffEntry *xmp = mRootIFD->getEntryRecursive(XMP);
+ if (!xmp)
+ ThrowRDE("Couldn't find the XMP");
+
+ assert(xmp != nullptr);
+ string xmpText = xmp->getString();
+ make = getXMPTag(xmpText, "Make");
+ model = getXMPTag(xmpText, "Model");
+ }
+}
+
+string MosDecoder::getXMPTag(const string &xmp, const string &tag) {
+ string::size_type start = xmp.find("<tiff:"+tag+">");
+ string::size_type end = xmp.find("</tiff:"+tag+">");
+ if (start == string::npos || end == string::npos || end <= start)
+ ThrowRDE("Couldn't find tag '%s' in the XMP", tag.c_str());
+ int startlen = tag.size()+7;
+ return xmp.substr(start+startlen, end-start-startlen);
+}
+
+RawImage MosDecoder::decodeRawInternal() {
+ uint32 off = 0;
+
+ const TiffIFD *raw = nullptr;
+
+ if (mRootIFD->hasEntryRecursive(TILEOFFSETS)) {
+ raw = mRootIFD->getIFDWithTag(TILEOFFSETS);
+ off = raw->getEntry(TILEOFFSETS)->getU32();
+ } else {
+ raw = mRootIFD->getIFDWithTag(CFAPATTERN);
+ off = raw->getEntry(STRIPOFFSETS)->getU32();
+ }
+
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+
+ // FIXME: could be wrong. max "active pixels" - "80 MP"
+ if (width == 0 || height == 0 || width > 10328 || height > 7760)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ mRaw->dim = iPoint2D(width, height);
+ mRaw->createData();
+
+ UncompressedDecompressor u(*mFile, off, mRaw);
+
+ int compression = raw->getEntry(COMPRESSION)->getU32();
+ if (1 == compression) {
+ const DataBuffer db(*mFile);
+ const ByteStream bs(db);
+ const Endianness endianness = getTiffByteOrder(bs, 0);
+
+ if (Endianness::big == endianness)
+ u.decodeRawUnpacked<16, Endianness::big>(width, height);
+ else
+ u.decodeRawUnpacked<16, Endianness::little>(width, height);
+ }
+ else if (99 == compression || 7 == compression) {
+ ThrowRDE("Leaf LJpeg not yet supported");
+ //LJpegPlain l(mFile, mRaw);
+ //l.startDecoder(off, mFile->getSize()-off, 0, 0);
+ } else
+ ThrowRDE("Unsupported compression: %d", compression);
+
+ return mRaw;
+}
+
+void MosDecoder::checkSupportInternal(const CameraMetaData* meta) {
+ RawDecoder::checkCameraSupported(meta, make, model, "");
+}
+
+void MosDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ RawDecoder::setMetaData(meta, make, model, "", 0);
+
+ // Fetch the white balance (see dcraw.c parse_mos for more metadata that can be gotten)
+ if (mRootIFD->hasEntryRecursive(LEAFMETADATA)) {
+ ByteStream bs = mRootIFD->getEntryRecursive(LEAFMETADATA)->getData();
+
+ // We need at least a couple of bytes:
+ // "NeutObj_neutrals" + 28 bytes binay + 4x uint as strings + 3x space + \0
+ const uint32 minSize = 16+28+4+3+1;
+
+ // dcraw does actual parsing, since we just want one field we bruteforce it
+ while (bs.getRemainSize() > minSize) {
+ if (bs.skipPrefix("NeutObj_neutrals", 16)) {
+ bs.skipBytes(28);
+ // check for nulltermination of string inside bounds
+ if (!memchr(bs.peekData(bs.getRemainSize()), 0, bs.getRemainSize()))
+ break;
+ uint32 tmp[4] = {0};
+ std::istringstream iss(bs.peekString());
+ iss >> tmp[0] >> tmp[1] >> tmp[2] >> tmp[3];
+ if (!iss.fail() && tmp[0] > 0 && tmp[1] > 0 && tmp[2] > 0 &&
+ tmp[3] > 0) {
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(tmp[0]) / tmp[1];
+ mRaw->metadata.wbCoeffs[1] = static_cast<float>(tmp[0]) / tmp[2];
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(tmp[0]) / tmp[3];
+ }
+ break;
+ }
+ bs.skipBytes(1);
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/MosDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/MosDecoder.h
new file mode 100644
index 000000000..b64d95db6
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/MosDecoder.h
@@ -0,0 +1,51 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffRootIFD (ptr only)
+#include <string> // for string
+
+namespace rawspeed {
+
+class CameraMetaData;
+class Buffer;
+
+class MosDecoder final : public AbstractTiffDecoder
+{
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ MosDecoder(TiffRootIFDOwner&& rootIFD, const Buffer* file);
+
+ RawImage decodeRawInternal() override;
+ void checkSupportInternal(const CameraMetaData* meta) override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+ std::string make, model;
+ std::string getXMPTag(const std::string &xmp, const std::string &tag);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/MrwDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/MrwDecoder.cpp
new file mode 100644
index 000000000..7ed63a086
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/MrwDecoder.cpp
@@ -0,0 +1,204 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014-2015 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/MrwDecoder.h"
+#include "common/Common.h" // for uint32
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for RawDecoderExcept...
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/Buffer.h" // for Buffer, DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness::big
+#include "io/IOException.h" // for IOException
+#include "metadata/Camera.h" // for Hints
+#include "parsers/TiffParser.h" // for TiffParser
+#include "tiff/TiffIFD.h" // for TiffID, TiffRoot...
+#include <cassert> // for assert
+#include <cstring> // for memcmp, size_t
+#include <memory> // for unique_ptr
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+MrwDecoder::MrwDecoder(const Buffer* file) : RawDecoder(file) { parseHeader(); }
+
+int MrwDecoder::isMRW(const Buffer* input) {
+ static const char magic[] = {0x00, 'M', 'R', 'M'};
+ static const size_t magic_size = sizeof(magic);
+ static_assert(4 == magic_size, "wrong magic size");
+
+ const unsigned char* data = input->getData(0, magic_size);
+ return 0 == memcmp(&data[0], magic, magic_size);
+}
+
+void MrwDecoder::parseHeader() {
+ if (!isMRW(mFile))
+ ThrowRDE("This isn't actually a MRW file, why are you calling me?");
+
+ const DataBuffer db(*mFile, Endianness::big);
+ ByteStream bs(db);
+
+ // magic
+ bs.skipBytes(4);
+
+ // the size of the rest of the header, up to the image data
+ const auto headerSize = bs.getU32();
+ bs.check(headerSize);
+
+ // ... and offset to the image data at the same time
+ const auto dataOffset = bs.getPosition() + headerSize;
+ assert(bs.getPosition() == 8);
+
+ // now, let's parse rest of the header.
+ bs = bs.getSubStream(0, dataOffset);
+ bs.skipBytes(8);
+
+ bool foundPRD = false;
+ while (bs.getRemainSize() > 0) {
+ uint32 tag = bs.getU32();
+ uint32 len = bs.getU32();
+ bs.check(len);
+ if (!len)
+ ThrowRDE("Found entry of zero lenght, MRW is corrupt.");
+
+ const auto origPos = bs.getPosition();
+
+ switch (tag) {
+ case 0x505244: { // PRD
+ foundPRD = true;
+ bs.skipBytes(8); // Version Number
+ raw_height = bs.getU16(); // CCD Size Y
+ raw_width = bs.getU16(); // CCD Size X
+
+ if (!raw_width || !raw_height || raw_width > 3280 || raw_height > 2456) {
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", raw_width,
+ raw_height);
+ }
+
+ bs.skipBytes(2); // Image Size Y
+ bs.skipBytes(2); // Image Size X
+
+ bpp = bs.getByte(); // DataSize
+ if (12 != bpp && 16 != bpp)
+ ThrowRDE("Unknown data size");
+
+ if ((raw_height * raw_width * bpp) % 8 != 0)
+ ThrowRDE("Bad combination of image size and raw dimensions.");
+
+ if (12 != bs.getByte()) // PixelSize
+ ThrowRDE("Unexpected pixel size");
+
+ const auto SM = bs.getByte(); // StorageMethod
+ if (0x52 != SM && 0x59 != SM)
+ ThrowRDE("Unknown storage method");
+ packed = (0x59 == SM);
+
+ if ((12 == bpp) != packed)
+ ThrowRDE("Packed/BPP sanity check failed!");
+
+ bs.skipBytes(1); // Unknown1
+ bs.skipBytes(2); // Unknown2
+ bs.skipBytes(2); // BayerPattern
+ break;
+ }
+ case 0x545457: // TTW
+ // Base value for offsets needs to be at the beginning of the TIFF block,
+ // not the file
+ rootIFD = TiffParser::parse(bs.getBuffer(len));
+ break;
+ case 0x574247: // WBG
+ bs.skipBytes(4); // 4 factors
+ static_assert(4 == (sizeof(wb_coeffs) / sizeof(wb_coeffs[0])),
+ "wrong coeff count");
+ for (auto& wb_coeff : wb_coeffs)
+ wb_coeff = static_cast<float>(bs.getU16()); // gain
+
+ // FIXME?
+ // Gf = Gr / 2^(6+F)
+ break;
+ default:
+ // unknown block, let's just ignore
+ break;
+ }
+
+ bs.setPosition(origPos + len);
+ }
+
+ if (!foundPRD)
+ ThrowRDE("Did not find PRD tag. Image corrupt.");
+
+ // processed all of the header. the image data is directly next
+
+ const auto imageBits = raw_height * raw_width * bpp;
+ assert(imageBits > 0);
+ assert(imageBits % 8 == 0);
+
+ imageData = db.getSubView(bs.getPosition(), imageBits / 8);
+}
+
+RawImage MrwDecoder::decodeRawInternal() {
+ mRaw->dim = iPoint2D(raw_width, raw_height);
+ mRaw->createData();
+
+ DataBuffer db(imageData, Endianness::big);
+ ByteStream bs(db);
+ UncompressedDecompressor u(bs, mRaw);
+
+ if (packed)
+ u.decode12BitRaw<Endianness::big>(raw_width, raw_height);
+ else
+ u.decodeRawUnpacked<12, Endianness::big>(raw_width, raw_height);
+
+ return mRaw;
+}
+
+void MrwDecoder::checkSupportInternal(const CameraMetaData* meta) {
+ if (!rootIFD)
+ ThrowRDE("Couldn't find make and model");
+
+ auto id = rootIFD->getID();
+ this->checkCameraSupported(meta, id.make, id.model, "");
+}
+
+void MrwDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ //Default
+ int iso = 0;
+
+ if (!rootIFD)
+ ThrowRDE("Couldn't find make and model");
+
+ auto id = rootIFD->getID();
+ setMetaData(meta, id.make, id.model, "", iso);
+
+ if (hints.has("swapped_wb")) {
+ mRaw->metadata.wbCoeffs[0] = wb_coeffs[2];
+ mRaw->metadata.wbCoeffs[1] = wb_coeffs[0];
+ mRaw->metadata.wbCoeffs[2] = wb_coeffs[1];
+ } else {
+ mRaw->metadata.wbCoeffs[0] = wb_coeffs[0];
+ mRaw->metadata.wbCoeffs[1] = wb_coeffs[1];
+ mRaw->metadata.wbCoeffs[2] = wb_coeffs[3];
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/MrwDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/MrwDecoder.h
new file mode 100644
index 000000000..59611896a
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/MrwDecoder.h
@@ -0,0 +1,57 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "common/RawImage.h" // for RawImage
+#include "decoders/RawDecoder.h" // for RawDecoder
+#include "io/Buffer.h" // for Buffer
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <cmath> // for NAN
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+class MrwDecoder final : public RawDecoder {
+ TiffRootIFDOwner rootIFD;
+
+ uint32 raw_width = 0;
+ uint32 raw_height = 0;
+ Buffer imageData;
+ uint32 bpp = 0;
+ uint32 packed = 0;
+ float wb_coeffs[4] = {NAN, NAN, NAN, NAN};
+
+public:
+ explicit MrwDecoder(const Buffer* file);
+ RawImage decodeRawInternal() override;
+ void checkSupportInternal(const CameraMetaData* meta) override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+ static int isMRW(const Buffer* input);
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+ void parseHeader();
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/NakedDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/NakedDecoder.cpp
new file mode 100644
index 000000000..aaa1aa0b2
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/NakedDecoder.cpp
@@ -0,0 +1,109 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/NakedDecoder.h"
+#include "common/Common.h" // for BitOrder, BitOrd...
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for RawDecoderExcept...
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "metadata/Camera.h" // for Camera, Hints
+#include <map> // for map
+#include <stdexcept> // for out_of_range
+#include <string> // for string, basic_st...
+
+using std::map;
+using std::string;
+
+namespace rawspeed {
+
+class Buffer;
+class CameraMetaData;
+
+NakedDecoder::NakedDecoder(const Buffer* file, const Camera* c)
+ : RawDecoder(file), cam(c) {}
+
+const map<string, BitOrder> NakedDecoder::order2enum = {
+ {"plain", BitOrder_LSB},
+ {"jpeg", BitOrder_MSB},
+ {"jpeg16", BitOrder_MSB16},
+ {"jpeg32", BitOrder_MSB32},
+};
+
+void NakedDecoder::parseHints() {
+ const auto& cHints = cam->hints;
+ const auto& make = cam->make.c_str();
+ const auto& model = cam->model.c_str();
+
+ auto parseHint = [&cHints, &make, &model](const string& name) {
+ if (!cHints.has(name))
+ ThrowRDE("%s %s: couldn't find %s", make, model, name.c_str());
+
+ return cHints.get(name, 0U);
+ };
+
+ width = parseHint("full_width");
+ height = parseHint("full_height");
+
+ if (width == 0 || height == 0)
+ ThrowRDE("%s %s: image is of zero size?", make, model);
+
+ filesize = parseHint("filesize");
+ offset = cHints.get("offset", 0);
+ if (filesize == 0 || offset >= filesize)
+ ThrowRDE("%s %s: no image data found", make, model);
+
+ bits = cHints.get("bits", (filesize-offset)*8/width/height);
+ if (bits == 0)
+ ThrowRDE("%s %s: image bpp is invalid: %u", make, model, bits);
+
+ auto order = cHints.get("order", string());
+ if (!order.empty()) {
+ try {
+ bo = order2enum.at(order);
+ } catch (std::out_of_range&) {
+ ThrowRDE("%s %s: unknown order: %s", make, model, order.c_str());
+ }
+ }
+}
+
+RawImage NakedDecoder::decodeRawInternal() {
+ parseHints();
+
+ mRaw->dim = iPoint2D(width, height);
+ mRaw->createData();
+
+ UncompressedDecompressor u(*mFile, offset, mRaw);
+
+ iPoint2D pos(0, 0);
+ u.readUncompressedRaw(mRaw->dim, pos, width * bits / 8, bits, bo);
+
+ return mRaw;
+}
+
+void NakedDecoder::checkSupportInternal(const CameraMetaData* meta) {
+ this->checkCameraSupported(meta, cam->make, cam->model, cam->mode);
+}
+
+void NakedDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ setMetaData(meta, cam->make, cam->model, cam->mode, 0);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/NakedDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/NakedDecoder.h
new file mode 100644
index 000000000..38b799d18
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/NakedDecoder.h
@@ -0,0 +1,59 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, BitOrder::BitOrder_MSB16
+#include "common/RawImage.h" // for RawImage
+#include "decoders/RawDecoder.h" // for RawDecoder
+#include <map> // for map
+#include <string> // for string, basic_st...
+
+namespace rawspeed {
+
+class Camera;
+class CameraMetaData;
+class Buffer;
+
+class NakedDecoder final : public RawDecoder {
+ const Camera* cam;
+
+ uint32 width{0};
+ uint32 height{0};
+ uint32 filesize{0};
+ uint32 bits{0};
+ uint32 offset{0};
+ BitOrder bo{BitOrder_MSB16};
+
+ static const std::map<std::string, BitOrder> order2enum;
+ void parseHints();
+
+public:
+ NakedDecoder(const Buffer* file, const Camera* c);
+ RawImage decodeRawInternal() override;
+ void checkSupportInternal(const CameraMetaData* meta) override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/NefDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/NefDecoder.cpp
new file mode 100644
index 000000000..efd3d77d8
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/NefDecoder.cpp
@@ -0,0 +1,752 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2015 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/NefDecoder.h"
+#include "common/Common.h" // for uint32, uchar8
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for ThrowRDE, RawDec...
+#include "decompressors/NikonDecompressor.h" // for NikonDecompressor
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/BitPumpMSB.h" // for BitPumpMSB
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for getU16BE, getU32LE
+#include "io/IOException.h" // for IOException, Thr...
+#include "metadata/Camera.h" // for Hints
+#include "metadata/CameraMetaData.h" // for CameraMetaData
+#include "metadata/ColorFilterArray.h" // for CFAColor::CFA_GREEN
+#include "tiff/TiffEntry.h" // for TiffEntry, TiffD...
+#include "tiff/TiffIFD.h" // for TiffRootIFD, Tif...
+#include "tiff/TiffTag.h" // for TiffTag, TiffTag...
+#include <cassert> // for assert
+#include <cmath> // for pow, exp, log
+#include <cstring> // for strncmp
+#include <memory> // for unique_ptr, allo...
+#include <sstream> // for operator<<, ostr...
+#include <string> // for string, operator==
+#include <vector> // for vector
+// IWYU pragma: no_include <ext/alloc_traits.h>
+
+using std::vector;
+using std::string;
+using std::min;
+using std::ostringstream;
+
+namespace rawspeed {
+
+bool NefDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "NIKON CORPORATION" || make == "NIKON";
+}
+
+RawImage NefDecoder::decodeRawInternal() {
+ auto raw = mRootIFD->getIFDWithTag(CFAPATTERN);
+ int compression = raw->getEntry(COMPRESSION)->getU32();
+
+ TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
+ TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);
+
+ if (mRootIFD->getEntryRecursive(MODEL)->getString() == "NIKON D100 ") { /**Sigh**/
+ if (!mFile->isValid(offsets->getU32()))
+ ThrowRDE("Image data outside of file.");
+ if (!D100IsCompressed(offsets->getU32())) {
+ DecodeD100Uncompressed();
+ return mRaw;
+ }
+ }
+
+ if (compression == 1 || (hints.has("force_uncompressed")) ||
+ NEFIsUncompressed(raw)) {
+ DecodeUncompressed();
+ return mRaw;
+ }
+
+ if (NEFIsUncompressedRGB(raw)) {
+ DecodeSNefUncompressed();
+ return mRaw;
+ }
+
+ if (offsets->count != 1) {
+ ThrowRDE("Multiple Strips found: %u", offsets->count);
+ }
+ if (counts->count != offsets->count) {
+ ThrowRDE(
+ "Byte count number does not match strip size: count:%u, strips:%u ",
+ counts->count, offsets->count);
+ }
+ if (!mFile->isValid(offsets->getU32(), counts->getU32()))
+ ThrowRDE("Invalid strip byte count. File probably truncated.");
+
+ if (34713 != compression)
+ ThrowRDE("Unsupported compression");
+
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+ uint32 bitPerPixel = raw->getEntry(BITSPERSAMPLE)->getU32();
+
+ mRaw->dim = iPoint2D(width, height);
+
+ raw = mRootIFD->getIFDWithTag(static_cast<TiffTag>(0x8c));
+
+ TiffEntry *meta;
+ if (raw->hasEntry(static_cast<TiffTag>(0x96))) {
+ meta = raw->getEntry(static_cast<TiffTag>(0x96));
+ } else {
+ meta = raw->getEntry(static_cast<TiffTag>(0x8c)); // Fall back
+ }
+
+ ByteStream rawData(mFile, offsets->getU32(), counts->getU32());
+
+ NikonDecompressor n(mRaw, bitPerPixel);
+ mRaw->createData();
+ n.decompress(meta->getData(), rawData, uncorrectedRawValues);
+
+ return mRaw;
+}
+
+/*
+Figure out if a NEF file is compressed. These fancy heuristics
+are only needed for the D100, thanks to a bug in some cameras
+that tags all images as "compressed".
+*/
+bool NefDecoder::D100IsCompressed(uint32 offset) {
+ const uchar8 *test = mFile->getData(offset, 256);
+ int i;
+
+ for (i = 15; i < 256; i += 16)
+ if (test[i])
+ return true;
+
+ return false;
+}
+
+/* At least the D810 has a broken firmware that tags uncompressed images
+ as if they were compressed. For those cases we set uncompressed mode
+ by figuring out that the image is the size of uncompressed packing */
+bool NefDecoder::NEFIsUncompressed(const TiffIFD* raw) {
+ TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+ uint32 bitPerPixel = raw->getEntry(BITSPERSAMPLE)->getU32();
+
+ const uint64 bitCount = uint64(8) * counts->getU32(0);
+ if (!bitPerPixel || bitCount % bitPerPixel != 0)
+ return false;
+
+ const auto pixelCount = bitCount / bitPerPixel;
+ return pixelCount == iPoint2D(width, height).area();
+}
+
+/* At least the D810 has a broken firmware that tags uncompressed images
+ as if they were compressed. For those cases we set uncompressed mode
+ by figuring out that the image is the size of uncompressed packing */
+bool NefDecoder::NEFIsUncompressedRGB(const TiffIFD* raw) {
+ uint32 byteCount = raw->getEntry(STRIPBYTECOUNTS)->getU32(0);
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+
+ if (byteCount % 3 != 0)
+ return false;
+
+ return byteCount / 3 == iPoint2D(width, height).area();
+}
+
+void NefDecoder::DecodeUncompressed() {
+ auto raw = getIFDWithLargestImage(CFAPATTERN);
+ TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
+ TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);
+ uint32 yPerSlice = raw->getEntry(ROWSPERSTRIP)->getU32();
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+ uint32 bitPerPixel = raw->getEntry(BITSPERSAMPLE)->getU32();
+
+ mRaw->dim = iPoint2D(width, height);
+
+ if (width == 0 || height == 0 || width > 8288 || height > 5520)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ if (counts->count != offsets->count) {
+ ThrowRDE("Byte count number does not match strip size: "
+ "count:%u, stips:%u ",
+ counts->count, offsets->count);
+ }
+
+ if (yPerSlice == 0 || yPerSlice > static_cast<uint32>(mRaw->dim.y) ||
+ roundUpDivision(mRaw->dim.y, yPerSlice) != counts->count) {
+ ThrowRDE("Invalid y per slice %u or strip count %u (height = %u)",
+ yPerSlice, counts->count, mRaw->dim.y);
+ }
+
+ vector<NefSlice> slices;
+ slices.reserve(counts->count);
+ uint32 offY = 0;
+
+ for (uint32 s = 0; s < counts->count; s++) {
+ NefSlice slice;
+ slice.offset = offsets->getU32(s);
+ slice.count = counts->getU32(s);
+
+ if (slice.count < 1)
+ ThrowRDE("Slice %u is empty", s);
+
+ if (offY + yPerSlice > height)
+ slice.h = height - offY;
+ else
+ slice.h = yPerSlice;
+
+ offY = min(height, offY + yPerSlice);
+
+ if (!mFile->isValid(slice.offset, slice.count))
+ ThrowRDE("Slice offset/count invalid");
+
+ slices.push_back(slice);
+ }
+
+ if (slices.empty())
+ ThrowRDE("No valid slices found. File probably truncated.");
+
+ assert(height == offY);
+ assert(slices.size() == counts->count);
+
+ mRaw->createData();
+ if (bitPerPixel == 14 && width*slices[0].h*2 == slices[0].count)
+ bitPerPixel = 16; // D3 & D810
+
+ bitPerPixel = hints.get("real_bpp", bitPerPixel);
+
+ switch (bitPerPixel) {
+ case 12:
+ case 14:
+ case 16:
+ break;
+ default:
+ ThrowRDE("Invalid bpp found: %u", bitPerPixel);
+ }
+
+ bool bitorder = ! hints.has("msb_override");
+
+ offY = 0;
+ for (const NefSlice& slice : slices) {
+ ByteStream in(mFile, slice.offset, slice.count);
+ iPoint2D size(width, slice.h);
+ iPoint2D pos(0, offY);
+
+ if (hints.has("coolpixmangled")) {
+ UncompressedDecompressor u(in, mRaw);
+ u.readUncompressedRaw(size, pos, width * bitPerPixel / 8, 12,
+ BitOrder_MSB32);
+ } else {
+ if (hints.has("coolpixsplit"))
+ readCoolpixSplitRaw(in, size, pos, width * bitPerPixel / 8);
+ else {
+ UncompressedDecompressor u(in, mRaw);
+ u.readUncompressedRaw(size, pos, width * bitPerPixel / 8, bitPerPixel,
+ bitorder ? BitOrder_MSB : BitOrder_LSB);
+ }
+ }
+
+ offY += slice.h;
+ }
+}
+
+void NefDecoder::readCoolpixSplitRaw(const ByteStream& input,
+ const iPoint2D& size,
+ const iPoint2D& offset, int inputPitch) {
+ uchar8* data = mRaw->getData();
+ uint32 outPitch = mRaw->pitch;
+ uint32 w = size.x;
+ uint32 h = size.y;
+ uint32 cpp = mRaw->getCpp();
+ if (input.getRemainSize() < (inputPitch*h)) {
+ if (static_cast<int>(input.getRemainSize()) > inputPitch)
+ h = input.getRemainSize() / inputPitch - 1;
+ else
+ ThrowIOE(
+ "Not enough data to decode a single line. Image file truncated.");
+ }
+
+ if (offset.y > mRaw->dim.y)
+ ThrowRDE("Invalid y offset");
+ if (offset.x + size.x > mRaw->dim.x)
+ ThrowRDE("Invalid x offset");
+
+ uint32 y = offset.y;
+ h = min(h + static_cast<uint32>(offset.y), static_cast<uint32>(mRaw->dim.y));
+ w *= cpp;
+ h /= 2;
+ BitPumpMSB in(input);
+ for (; y < h; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(
+ &data[offset.x * sizeof(ushort16) * cpp + y * 2 * outPitch]);
+ for (uint32 x = 0 ; x < w; x++) {
+ dest[x] = in.getBits(12);
+ }
+ }
+ for (y = offset.y; y < h; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(
+ &data[offset.x * sizeof(ushort16) * cpp + (y * 2 + 1) * outPitch]);
+ for (uint32 x = 0 ; x < w; x++) {
+ dest[x] = in.getBits(12);
+ }
+ }
+}
+
+void NefDecoder::DecodeD100Uncompressed() {
+ auto ifd = mRootIFD->getIFDWithTag(STRIPOFFSETS, 1);
+
+ uint32 offset = ifd->getEntry(STRIPOFFSETS)->getU32();
+ // Hardcode the sizes as at least the width is not correctly reported
+ uint32 width = 3040;
+ uint32 height = 2024;
+
+ mRaw->dim = iPoint2D(width, height);
+ mRaw->createData();
+
+ UncompressedDecompressor u(*mFile, offset, mRaw);
+
+ u.decode12BitRaw<Endianness::big, false, true>(width, height);
+}
+
+void NefDecoder::DecodeSNefUncompressed() {
+ auto raw = getIFDWithLargestImage(CFAPATTERN);
+ uint32 offset = raw->getEntry(STRIPOFFSETS)->getU32();
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+
+ if (width == 0 || height == 0 || width % 2 != 0 || width > 3680 ||
+ height > 2456)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ mRaw->dim = iPoint2D(width, height);
+ mRaw->setCpp(3);
+ mRaw->isCFA = false;
+ mRaw->createData();
+
+ ByteStream in(mFile, offset);
+
+ DecodeNikonSNef(&in, width, height);
+}
+
+void NefDecoder::checkSupportInternal(const CameraMetaData* meta) {
+ auto id = mRootIFD->getID();
+ string mode = getMode();
+ string extended_mode = getExtendedMode(mode);
+
+ if (meta->hasCamera(id.make, id.model, extended_mode))
+ checkCameraSupported(meta, id, extended_mode);
+ else
+ checkCameraSupported(meta, id, mode);
+}
+
+string NefDecoder::getMode() {
+ ostringstream mode;
+ auto raw = getIFDWithLargestImage(CFAPATTERN);
+ int compression = raw->getEntry(COMPRESSION)->getU32();
+ uint32 bitPerPixel = raw->getEntry(BITSPERSAMPLE)->getU32();
+
+ if (NEFIsUncompressedRGB(raw))
+ mode << "sNEF-uncompressed";
+ else {
+ if (1 == compression || NEFIsUncompressed(raw))
+ mode << bitPerPixel << "bit-uncompressed";
+ else
+ mode << bitPerPixel << "bit-compressed";
+ }
+ return mode.str();
+}
+
+string NefDecoder::getExtendedMode(const string &mode) {
+ ostringstream extended_mode;
+
+ auto ifd = mRootIFD->getIFDWithTag(CFAPATTERN);
+ uint32 width = ifd->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = ifd->getEntry(IMAGELENGTH)->getU32();
+
+ extended_mode << width << "x" << height << "-" << mode;
+ return extended_mode.str();
+}
+
+// We use this for the D50 and D2X whacky WB "encryption"
+const std::array<uchar8, 256> NefDecoder::serialmap = {
+ {0xc1, 0xbf, 0x6d, 0x0d, 0x59, 0xc5, 0x13, 0x9d, 0x83, 0x61, 0x6b, 0x4f,
+ 0xc7, 0x7f, 0x3d, 0x3d, 0x53, 0x59, 0xe3, 0xc7, 0xe9, 0x2f, 0x95, 0xa7,
+ 0x95, 0x1f, 0xdf, 0x7f, 0x2b, 0x29, 0xc7, 0x0d, 0xdf, 0x07, 0xef, 0x71,
+ 0x89, 0x3d, 0x13, 0x3d, 0x3b, 0x13, 0xfb, 0x0d, 0x89, 0xc1, 0x65, 0x1f,
+ 0xb3, 0x0d, 0x6b, 0x29, 0xe3, 0xfb, 0xef, 0xa3, 0x6b, 0x47, 0x7f, 0x95,
+ 0x35, 0xa7, 0x47, 0x4f, 0xc7, 0xf1, 0x59, 0x95, 0x35, 0x11, 0x29, 0x61,
+ 0xf1, 0x3d, 0xb3, 0x2b, 0x0d, 0x43, 0x89, 0xc1, 0x9d, 0x9d, 0x89, 0x65,
+ 0xf1, 0xe9, 0xdf, 0xbf, 0x3d, 0x7f, 0x53, 0x97, 0xe5, 0xe9, 0x95, 0x17,
+ 0x1d, 0x3d, 0x8b, 0xfb, 0xc7, 0xe3, 0x67, 0xa7, 0x07, 0xf1, 0x71, 0xa7,
+ 0x53, 0xb5, 0x29, 0x89, 0xe5, 0x2b, 0xa7, 0x17, 0x29, 0xe9, 0x4f, 0xc5,
+ 0x65, 0x6d, 0x6b, 0xef, 0x0d, 0x89, 0x49, 0x2f, 0xb3, 0x43, 0x53, 0x65,
+ 0x1d, 0x49, 0xa3, 0x13, 0x89, 0x59, 0xef, 0x6b, 0xef, 0x65, 0x1d, 0x0b,
+ 0x59, 0x13, 0xe3, 0x4f, 0x9d, 0xb3, 0x29, 0x43, 0x2b, 0x07, 0x1d, 0x95,
+ 0x59, 0x59, 0x47, 0xfb, 0xe5, 0xe9, 0x61, 0x47, 0x2f, 0x35, 0x7f, 0x17,
+ 0x7f, 0xef, 0x7f, 0x95, 0x95, 0x71, 0xd3, 0xa3, 0x0b, 0x71, 0xa3, 0xad,
+ 0x0b, 0x3b, 0xb5, 0xfb, 0xa3, 0xbf, 0x4f, 0x83, 0x1d, 0xad, 0xe9, 0x2f,
+ 0x71, 0x65, 0xa3, 0xe5, 0x07, 0x35, 0x3d, 0x0d, 0xb5, 0xe9, 0xe5, 0x47,
+ 0x3b, 0x9d, 0xef, 0x35, 0xa3, 0xbf, 0xb3, 0xdf, 0x53, 0xd3, 0x97, 0x53,
+ 0x49, 0x71, 0x07, 0x35, 0x61, 0x71, 0x2f, 0x43, 0x2f, 0x11, 0xdf, 0x17,
+ 0x97, 0xfb, 0x95, 0x3b, 0x7f, 0x6b, 0xd3, 0x25, 0xbf, 0xad, 0xc7, 0xc5,
+ 0xc5, 0xb5, 0x8b, 0xef, 0x2f, 0xd3, 0x07, 0x6b, 0x25, 0x49, 0x95, 0x25,
+ 0x49, 0x6d, 0x71, 0xc7}};
+const std::array<uchar8, 256> NefDecoder::keymap = {
+ {0xa7, 0xbc, 0xc9, 0xad, 0x91, 0xdf, 0x85, 0xe5, 0xd4, 0x78, 0xd5, 0x17,
+ 0x46, 0x7c, 0x29, 0x4c, 0x4d, 0x03, 0xe9, 0x25, 0x68, 0x11, 0x86, 0xb3,
+ 0xbd, 0xf7, 0x6f, 0x61, 0x22, 0xa2, 0x26, 0x34, 0x2a, 0xbe, 0x1e, 0x46,
+ 0x14, 0x68, 0x9d, 0x44, 0x18, 0xc2, 0x40, 0xf4, 0x7e, 0x5f, 0x1b, 0xad,
+ 0x0b, 0x94, 0xb6, 0x67, 0xb4, 0x0b, 0xe1, 0xea, 0x95, 0x9c, 0x66, 0xdc,
+ 0xe7, 0x5d, 0x6c, 0x05, 0xda, 0xd5, 0xdf, 0x7a, 0xef, 0xf6, 0xdb, 0x1f,
+ 0x82, 0x4c, 0xc0, 0x68, 0x47, 0xa1, 0xbd, 0xee, 0x39, 0x50, 0x56, 0x4a,
+ 0xdd, 0xdf, 0xa5, 0xf8, 0xc6, 0xda, 0xca, 0x90, 0xca, 0x01, 0x42, 0x9d,
+ 0x8b, 0x0c, 0x73, 0x43, 0x75, 0x05, 0x94, 0xde, 0x24, 0xb3, 0x80, 0x34,
+ 0xe5, 0x2c, 0xdc, 0x9b, 0x3f, 0xca, 0x33, 0x45, 0xd0, 0xdb, 0x5f, 0xf5,
+ 0x52, 0xc3, 0x21, 0xda, 0xe2, 0x22, 0x72, 0x6b, 0x3e, 0xd0, 0x5b, 0xa8,
+ 0x87, 0x8c, 0x06, 0x5d, 0x0f, 0xdd, 0x09, 0x19, 0x93, 0xd0, 0xb9, 0xfc,
+ 0x8b, 0x0f, 0x84, 0x60, 0x33, 0x1c, 0x9b, 0x45, 0xf1, 0xf0, 0xa3, 0x94,
+ 0x3a, 0x12, 0x77, 0x33, 0x4d, 0x44, 0x78, 0x28, 0x3c, 0x9e, 0xfd, 0x65,
+ 0x57, 0x16, 0x94, 0x6b, 0xfb, 0x59, 0xd0, 0xc8, 0x22, 0x36, 0xdb, 0xd2,
+ 0x63, 0x98, 0x43, 0xa1, 0x04, 0x87, 0x86, 0xf7, 0xa6, 0x26, 0xbb, 0xd6,
+ 0x59, 0x4d, 0xbf, 0x6a, 0x2e, 0xaa, 0x2b, 0xef, 0xe6, 0x78, 0xb6, 0x4e,
+ 0xe0, 0x2f, 0xdc, 0x7c, 0xbe, 0x57, 0x19, 0x32, 0x7e, 0x2a, 0xd0, 0xb8,
+ 0xba, 0x29, 0x00, 0x3c, 0x52, 0x7d, 0xa8, 0x49, 0x3b, 0x2d, 0xeb, 0x25,
+ 0x49, 0xfa, 0xa3, 0xaa, 0x39, 0xa7, 0xc5, 0xa7, 0x50, 0x11, 0x36, 0xfb,
+ 0xc6, 0x67, 0x4a, 0xf5, 0xa5, 0x12, 0x65, 0x7e, 0xb0, 0xdf, 0xaf, 0x4e,
+ 0xb3, 0x61, 0x7f, 0x2f}};
+
+void NefDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ int iso = 0;
+ mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN, CFA_BLUE);
+
+ int white = mRaw->whitePoint;
+ int black = mRaw->blackLevel;
+
+ if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
+ iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32();
+
+ // Read the whitebalance
+
+ if (mRootIFD->hasEntryRecursive(static_cast<TiffTag>(12))) {
+ TiffEntry* wb = mRootIFD->getEntryRecursive(static_cast<TiffTag>(12));
+ if (wb->count == 4) {
+ mRaw->metadata.wbCoeffs[0] = wb->getFloat(0);
+ mRaw->metadata.wbCoeffs[1] = wb->getFloat(2);
+ mRaw->metadata.wbCoeffs[2] = wb->getFloat(1);
+ if (mRaw->metadata.wbCoeffs[1] <= 0.0F)
+ mRaw->metadata.wbCoeffs[1] = 1.0F;
+ }
+ } else if (mRootIFD->hasEntryRecursive(static_cast<TiffTag>(0x0097))) {
+ TiffEntry* wb = mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x0097));
+ if (wb->count > 4) {
+ uint32 version = 0;
+ for (uint32 i = 0; i < 4; i++) {
+ const auto v = wb->getByte(i);
+ if (v < '0' || v > '9')
+ ThrowRDE("Bad version component: %c - not a digit", v);
+ version = (version << 4) + v - '0';
+ }
+
+ if (version == 0x100 && wb->count >= 80 && wb->type == TIFF_UNDEFINED) {
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(wb->getU16(36));
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(wb->getU16(37));
+ mRaw->metadata.wbCoeffs[1] = static_cast<float>(wb->getU16(38));
+ } else if (version == 0x103 && wb->count >= 26 && wb->type == TIFF_UNDEFINED) {
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(wb->getU16(10));
+ mRaw->metadata.wbCoeffs[1] = static_cast<float>(wb->getU16(11));
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(wb->getU16(12));
+ } else if (((version == 0x204 && wb->count >= 564) ||
+ (version == 0x205 && wb->count >= 284)) &&
+ mRootIFD->hasEntryRecursive(static_cast<TiffTag>(0x001d)) &&
+ mRootIFD->hasEntryRecursive(static_cast<TiffTag>(0x00a7))) {
+ // Get the serial number
+ string serial =
+ mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x001d))
+ ->getString();
+ if (serial.length() > 9)
+ ThrowRDE("Serial number is too long (%lu)", serial.length());
+ uint32 serialno = 0;
+ for (unsigned char c : serial) {
+ if (c >= '0' && c <= '9')
+ serialno = serialno*10 + c-'0';
+ else
+ serialno = serialno*10 + c%10;
+ }
+
+ // Get the decryption key
+ TiffEntry* key =
+ mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x00a7));
+ const uchar8 *keydata = key->getData(4);
+ uint32 keyno = keydata[0]^keydata[1]^keydata[2]^keydata[3];
+
+ // "Decrypt" the block using the serial and key
+ uchar8 ci = serialmap[serialno & 0xff];
+ uchar8 cj = keymap[keyno & 0xff];
+ uchar8 ck = 0x60;
+
+ ByteStream bs = wb->getData();
+ bs.skipBytes(version == 0x204 ? 284 : 4);
+
+ uchar8 buf[14+8];
+ for (unsigned char& i : buf) {
+ cj += ci * ck;
+ i = bs.getByte() ^ cj;
+ ck++;
+ }
+
+ // Finally set the WB coeffs
+ uint32 off = (version == 0x204) ? 6 : 14;
+ mRaw->metadata.wbCoeffs[0] =
+ static_cast<float>(getU16BE(buf + off + 0));
+ mRaw->metadata.wbCoeffs[1] =
+ static_cast<float>(getU16BE(buf + off + 2));
+ mRaw->metadata.wbCoeffs[2] =
+ static_cast<float>(getU16BE(buf + off + 6));
+ }
+ }
+ } else if (mRootIFD->hasEntryRecursive(static_cast<TiffTag>(0x0014))) {
+ TiffEntry* wb = mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x0014));
+ ByteStream bs = wb->getData();
+ if (wb->count == 2560 && wb->type == TIFF_UNDEFINED) {
+ bs.skipBytes(1248);
+ bs.setByteOrder(Endianness::big);
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(bs.getU16()) / 256.0;
+ mRaw->metadata.wbCoeffs[1] = 1.0F;
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(bs.getU16()) / 256.0;
+ } else if (bs.hasPatternAt("NRW ", 4, 0)) {
+ uint32 offset = 0;
+ if (!bs.hasPatternAt("0100", 4, 4) && wb->count > 72)
+ offset = 56;
+ else if (wb->count > 1572)
+ offset = 1556;
+
+ if (offset) {
+ bs.skipBytes(offset);
+ bs.setByteOrder(Endianness::little);
+ mRaw->metadata.wbCoeffs[0] = 4.0 * bs.getU32();
+ mRaw->metadata.wbCoeffs[1] = bs.getU32();
+ mRaw->metadata.wbCoeffs[1] += bs.getU32();
+ mRaw->metadata.wbCoeffs[2] = 4.0 * bs.getU32();
+ }
+ }
+ }
+
+ if (hints.has("nikon_wb_adjustment")) {
+ mRaw->metadata.wbCoeffs[0] *= 256/527.0;
+ mRaw->metadata.wbCoeffs[2] *= 256/317.0;
+ }
+
+ auto id = mRootIFD->getID();
+ string mode = getMode();
+ string extended_mode = getExtendedMode(mode);
+ if (meta->hasCamera(id.make, id.model, extended_mode)) {
+ setMetaData(meta, id, extended_mode, iso);
+ } else if (meta->hasCamera(id.make, id.model, mode)) {
+ setMetaData(meta, id, mode, iso);
+ } else {
+ setMetaData(meta, id, "", iso);
+ }
+
+ if (white != 65536)
+ mRaw->whitePoint = white;
+ if (black != -1)
+ mRaw->blackLevel = black;
+}
+
+
+// DecodeNikonYUY2 decodes 12 bit data in an YUY2-like pattern (2 Luma, 1 Chroma per 2 pixels).
+// We un-apply the whitebalance, so output matches lossless.
+// Note that values are scaled. See comment below on details.
+// OPTME: It would be trivial to run this multithreaded.
+void NefDecoder::DecodeNikonSNef(ByteStream* input, uint32 w, uint32 h) {
+ if (w < 6)
+ ThrowIOE("got a %u wide sNEF, aborting", w);
+
+ if (input->getRemainSize() < (w * h * 3))
+ ThrowIOE("Not enough data to decode. Image file truncated.");
+
+ // We need to read the applied whitebalance, since we should return
+ // data before whitebalance, so we "unapply" it.
+ TiffEntry* wb = mRootIFD->getEntryRecursive(static_cast<TiffTag>(12));
+ if (!wb)
+ ThrowRDE("Unable to locate whitebalance needed for decompression");
+
+ assert(wb != nullptr);
+ if (wb->count != 4 || wb->type != TIFF_RATIONAL)
+ ThrowRDE("Whitebalance has unknown count or type");
+
+ float wb_r = wb->getFloat(0);
+ float wb_b = wb->getFloat(1);
+
+ // ((1024/x)*((1<<16)-1)+(1<<9))<=((1<<31)-1), x>0 gives: (0.0312495)
+ const float lower_limit = 13'421'568.0 / 429'496'627.0;
+ if (wb_r < lower_limit || wb_b < lower_limit || wb_r > 10.0F || wb_b > 10.0F)
+ ThrowRDE("Whitebalance has bad values (%f, %f)", wb_r, wb_b);
+
+ mRaw->metadata.wbCoeffs[0] = wb_r;
+ mRaw->metadata.wbCoeffs[1] = 1.0F;
+ mRaw->metadata.wbCoeffs[2] = wb_b;
+
+ auto inv_wb_r = static_cast<int>(1024.0 / wb_r);
+ auto inv_wb_b = static_cast<int>(1024.0 / wb_b);
+
+ auto curve = gammaCurve(1 / 2.4, 12.92, 1, 4095);
+
+ // Scale output values to 16 bits.
+ for (int i = 0 ; i < 4096; i++) {
+ curve[i] = clampBits(static_cast<int>(curve[i]) << 2, 16);
+ }
+
+ curve.resize(4095);
+
+ RawImageCurveGuard curveHandler(&mRaw, curve, false);
+
+ ushort16 tmp;
+ auto* tmpch = reinterpret_cast<uchar8*>(&tmp);
+
+ uchar8* data = mRaw->getData();
+ uint32 pitch = mRaw->pitch;
+ const uchar8* in = input->getData(w * h * 3);
+
+ for (uint32 y = 0; y < h; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
+ uint32 random = in[0] + (in[1] << 8) + (in[2] << 16);
+ for (uint32 x = 0 ; x < w*3; x += 6) {
+ uint32 g1 = in[0];
+ uint32 g2 = in[1];
+ uint32 g3 = in[2];
+ uint32 g4 = in[3];
+ uint32 g5 = in[4];
+ uint32 g6 = in[5];
+
+ in+=6;
+ auto y1 = static_cast<float>(g1 | ((g2 & 0x0f) << 8));
+ auto y2 = static_cast<float>((g2 >> 4) | (g3 << 4));
+ auto cb = static_cast<float>(g4 | ((g5 & 0x0f) << 8));
+ auto cr = static_cast<float>((g5 >> 4) | (g6 << 4));
+
+ float cb2 = cb;
+ float cr2 = cr;
+ // Interpolate right pixel. We assume the sample is aligned with left pixel.
+ if ((x+6) < w*3) {
+ g4 = in[3];
+ g5 = in[4];
+ g6 = in[5];
+ cb2 = (static_cast<float>((g4 | ((g5 & 0x0f) << 8))) + cb) * 0.5F;
+ cr2 = (static_cast<float>(((g5 >> 4) | (g6 << 4))) + cr) * 0.5F;
+ }
+
+ cb -= 2048;
+ cr -= 2048;
+ cb2 -= 2048;
+ cr2 -= 2048;
+
+ mRaw->setWithLookUp(clampBits(static_cast<int>(y1 + 1.370705 * cr), 12),
+ tmpch, &random);
+ dest[x] = clampBits((inv_wb_r * tmp + (1<<9)) >> 10, 15);
+
+ mRaw->setWithLookUp(
+ clampBits(static_cast<int>(y1 - 0.337633 * cb - 0.698001 * cr), 12),
+ reinterpret_cast<uchar8*>(&dest[x + 1]), &random);
+
+ mRaw->setWithLookUp(clampBits(static_cast<int>(y1 + 1.732446 * cb), 12),
+ tmpch, &random);
+ dest[x+2] = clampBits((inv_wb_b * tmp + (1<<9)) >> 10, 15);
+
+ mRaw->setWithLookUp(clampBits(static_cast<int>(y2 + 1.370705 * cr2), 12),
+ tmpch, &random);
+ dest[x+3] = clampBits((inv_wb_r * tmp + (1<<9)) >> 10, 15);
+
+ mRaw->setWithLookUp(
+ clampBits(static_cast<int>(y2 - 0.337633 * cb2 - 0.698001 * cr2), 12),
+ reinterpret_cast<uchar8*>(&dest[x + 4]), &random);
+
+ mRaw->setWithLookUp(clampBits(static_cast<int>(y2 + 1.732446 * cb2), 12),
+ tmpch, &random);
+ dest[x+5] = clampBits((inv_wb_b * tmp + (1<<9)) >> 10, 15);
+ }
+ }
+}
+
+// From: dcraw.c -- Dave Coffin's raw photo decoder
+#define SQR(x) ((x)*(x))
+std::vector<ushort16> NefDecoder::gammaCurve(double pwr, double ts, int mode,
+ int imax) {
+ std::vector<ushort16> curve(65536);
+
+ int i;
+ double g[6], bnd[2]={0,0}, r;
+ g[0] = pwr;
+ g[1] = ts;
+ g[2] = g[3] = g[4] = 0;
+ bnd[g[1] >= 1] = 1;
+ if (g[1] && (g[1]-1)*(g[0]-1) <= 0) {
+ for (i=0; i < 48; i++) {
+ g[2] = (bnd[0] + bnd[1])/2;
+ if (g[0])
+ bnd[(pow(g[2] / g[1], -g[0]) - 1) / g[0] - 1 / g[2] > -1] = g[2];
+ else
+ bnd[g[2] / exp(1 - 1 / g[2]) < g[1]] = g[2];
+ }
+ g[3] = g[2] / g[1];
+ if (g[0])
+ g[4] = g[2] * (1 / g[0] - 1);
+ }
+ if (g[0]) {
+ g[5] = 1 / (g[1] * SQR(g[3]) / 2 - g[4] * (1 - g[3]) +
+ (1 - pow(g[3], 1 + g[0])) * (1 + g[4]) / (1 + g[0])) -
+ 1;
+ } else {
+ g[5] = 1 / (g[1] * SQR(g[3]) / 2 + 1 - g[2] - g[3] -
+ g[2] * g[3] * (log(g[3]) - 1)) -
+ 1;
+ }
+
+ if (mode == 0)
+ ThrowRDE("Unimplemented mode");
+
+ mode--;
+
+ for (i=0; i < 0x10000; i++) {
+ curve[i] = 0xffff;
+ if ((r = static_cast<double>(i) / imax) < 1) {
+ curve[i] = static_cast<ushort16>(
+ 0x10000 *
+ (mode ? (r < g[3] ? r * g[1]
+ : (g[0] ? pow(r, g[0]) * (1 + g[4]) - g[4]
+ : log(r) * g[2] + 1))
+ : (r < g[2] ? r / g[1]
+ : (g[0] ? pow((r + g[4]) / (1 + g[4]), 1 / g[0])
+ : exp((r - 1) / g[2])))));
+ }
+ }
+
+ assert(curve.size() == 65536);
+
+ return curve;
+}
+#undef SQR
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/NefDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/NefDecoder.h
new file mode 100644
index 000000000..1d14aa830
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/NefDecoder.h
@@ -0,0 +1,75 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, ushort16
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "decoders/RawDecoder.h" // for RawDecoder::RawSlice
+#include "tiff/TiffIFD.h" // for TiffIFD (ptr only), TiffRo...
+#include <algorithm> // for move
+#include <array> // for array
+#include <string> // for string
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class ByteStream;
+class CameraMetaData;
+class iPoint2D;
+class Buffer;
+
+class NefDecoder final : public AbstractTiffDecoder
+{
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ NefDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : AbstractTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+ void checkSupportInternal(const CameraMetaData* meta) override;
+
+protected:
+ struct NefSlice final : RawSlice {};
+
+private:
+ int getDecoderVersion() const override { return 5; }
+ bool D100IsCompressed(uint32 offset);
+ bool NEFIsUncompressed(const TiffIFD* raw);
+ bool NEFIsUncompressedRGB(const TiffIFD* raw);
+ void DecodeUncompressed();
+ void DecodeD100Uncompressed();
+ void DecodeSNefUncompressed();
+ void readCoolpixSplitRaw(const ByteStream& input, const iPoint2D& size,
+ const iPoint2D& offset, int inputPitch);
+ void DecodeNikonSNef(ByteStream* input, uint32 w, uint32 h);
+ std::string getMode();
+ std::string getExtendedMode(const std::string &mode);
+ std::vector<ushort16> gammaCurve(double pwr, double ts, int mode, int imax);
+
+ // We use this for the D50 and D2X whacky WB "encryption"
+ static const std::array<uchar8, 256> serialmap;
+ static const std::array<uchar8, 256> keymap;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/OrfDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/OrfDecoder.cpp
new file mode 100644
index 000000000..0063dd128
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/OrfDecoder.cpp
@@ -0,0 +1,228 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014-2015 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/OrfDecoder.h"
+#include "common/Common.h" // for uint32, ushort16
+#include "common/NORangesSet.h" // for NORangesSet
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for RawDecoderExcept...
+#include "decompressors/OlympusDecompressor.h" // for OlympusDecompressor
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/BitPumpMSB.h" // for BitPumpMSB
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness
+#include "io/IOException.h" // for IOException
+#include "metadata/Camera.h" // for Hints
+#include "metadata/ColorFilterArray.h" // for ColorFilterArray
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffRootIFD, Tif...
+#include "tiff/TiffTag.h" // for TiffTag, TiffTag...
+#include <algorithm> // for min
+#include <cassert> // for assert
+#include <cmath> // for signbit
+#include <cstdlib> // for abs
+#include <memory> // for unique_ptr
+#include <string> // for operator==, string
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+bool OrfDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "OLYMPUS IMAGING CORP." || make == "OLYMPUS CORPORATION" ||
+ make == "OLYMPUS OPTICAL CO.,LTD";
+}
+
+ByteStream OrfDecoder::handleSlices() const {
+ auto raw = mRootIFD->getIFDWithTag(STRIPOFFSETS);
+
+ TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
+ TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);
+
+ if (counts->count != offsets->count) {
+ ThrowRDE(
+ "Byte count number does not match strip size: count:%u, strips:%u ",
+ counts->count, offsets->count);
+ }
+
+ const uint32 off = offsets->getU32(0);
+ uint32 size = counts->getU32(0);
+ auto end = [&off, &size]() -> uint32 { return off + size; };
+
+ for (uint32 i = 0; i < counts->count; i++) {
+ const auto offset = offsets->getU32(i);
+ const auto count = counts->getU32(i);
+ if (!mFile->isValid(offset, count))
+ ThrowRDE("Truncated file");
+
+ if (count < 1)
+ ThrowRDE("Empty slice");
+
+ if (i == 0)
+ continue;
+
+ if (offset < end())
+ ThrowRDE("Slices overlap");
+
+ // Now, everything would be great, but some uncompressed raws
+ // (packed_with_control i believe) have "padding" between at least
+ // the first two slices, and we need to account for it.
+ const uint32 padding = offset - end();
+
+ size += padding;
+ size += count;
+ }
+
+ ByteStream input(offsets->getRootIfdData());
+ input.setPosition(off);
+
+ return input.getStream(size);
+}
+
+RawImage OrfDecoder::decodeRawInternal() {
+ auto raw = mRootIFD->getIFDWithTag(STRIPOFFSETS);
+
+ int compression = raw->getEntry(COMPRESSION)->getU32();
+ if (1 != compression)
+ ThrowRDE("Unsupported compression");
+
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+
+ if (!width || !height || width % 2 != 0 || width > 10400 || height > 7792)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ mRaw->dim = iPoint2D(width, height);
+
+ ByteStream input(handleSlices());
+
+ if (raw->getEntry(STRIPOFFSETS)->count != 1 ||
+ hints.has("force_uncompressed")) {
+ mRaw->createData();
+ decodeUncompressed(input, width, height, input.getSize());
+ } else {
+ OlympusDecompressor o(mRaw);
+ mRaw->createData();
+ o.decompress(std::move(input));
+ }
+
+ return mRaw;
+}
+
+void OrfDecoder::decodeUncompressed(const ByteStream& s, uint32 w, uint32 h,
+ uint32 size) {
+ UncompressedDecompressor u(s, mRaw);
+ if (hints.has("packed_with_control"))
+ u.decode12BitRaw<Endianness::little, false, true>(w, h);
+ else if (hints.has("jpeg32_bitorder")) {
+ iPoint2D dimensions(w, h);
+ iPoint2D pos(0, 0);
+ u.readUncompressedRaw(dimensions, pos, w * 12 / 8, 12, BitOrder_MSB32);
+ } else if (size >= w * h * 2) { // We're in an unpacked raw
+ // FIXME: seems fishy
+ if (s.getByteOrder() == getHostEndianness())
+ u.decodeRawUnpacked<12, Endianness::little>(w, h);
+ else
+ u.decode12BitRawUnpackedLeftAligned<Endianness::big>(w, h);
+ } else if (size >= w*h*3/2) { // We're in one of those weird interlaced packed raws
+ u.decode12BitRaw<Endianness::big, true>(w, h);
+ } else {
+ ThrowRDE("Don't know how to handle the encoding in this file");
+ }
+}
+
+void OrfDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ int iso = 0;
+ mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN, CFA_BLUE);
+
+ if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
+ iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32();
+
+ setMetaData(meta, "", iso);
+
+ if (mRootIFD->hasEntryRecursive(OLYMPUSREDMULTIPLIER) &&
+ mRootIFD->hasEntryRecursive(OLYMPUSBLUEMULTIPLIER)) {
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(
+ mRootIFD->getEntryRecursive(OLYMPUSREDMULTIPLIER)->getU16());
+ mRaw->metadata.wbCoeffs[1] = 256.0F;
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(
+ mRootIFD->getEntryRecursive(OLYMPUSBLUEMULTIPLIER)->getU16());
+ } else if (mRootIFD->hasEntryRecursive(OLYMPUSIMAGEPROCESSING)) {
+ // Newer cameras process the Image Processing SubIFD in the makernote
+ TiffEntry* img_entry = mRootIFD->getEntryRecursive(OLYMPUSIMAGEPROCESSING);
+ // get makernote ifd with containing Buffer
+ NORangesSet<Buffer> ifds;
+
+ TiffRootIFD image_processing(nullptr, &ifds, img_entry->getRootIfdData(),
+ img_entry->getU32());
+
+ // Get the WB
+ if (image_processing.hasEntry(static_cast<TiffTag>(0x0100))) {
+ TiffEntry* wb = image_processing.getEntry(static_cast<TiffTag>(0x0100));
+ if (wb->count == 2 || wb->count == 4) {
+ mRaw->metadata.wbCoeffs[0] = wb->getFloat(0);
+ mRaw->metadata.wbCoeffs[1] = 256.0F;
+ mRaw->metadata.wbCoeffs[2] = wb->getFloat(1);
+ }
+ }
+
+ // Get the black levels
+ if (image_processing.hasEntry(static_cast<TiffTag>(0x0600))) {
+ TiffEntry* blackEntry =
+ image_processing.getEntry(static_cast<TiffTag>(0x0600));
+ // Order is assumed to be RGGB
+ if (blackEntry->count == 4) {
+ for (int i = 0; i < 4; i++) {
+ auto c = mRaw->cfa.getColorAt(i & 1, i >> 1);
+ int j;
+ switch (c) {
+ case CFA_RED:
+ j = 0;
+ break;
+ case CFA_GREEN:
+ j = i < 2 ? 1 : 2;
+ break;
+ case CFA_BLUE:
+ j = 3;
+ break;
+ default:
+ ThrowRDE("Unexpected CFA color: %u", c);
+ }
+
+ mRaw->blackLevelSeparate[i] = blackEntry->getU16(j);
+ }
+ // Adjust whitelevel based on the read black (we assume the dynamic
+ // range is the same)
+ mRaw->whitePoint -= (mRaw->blackLevel - mRaw->blackLevelSeparate[0]);
+ }
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/OrfDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/OrfDecoder.h
new file mode 100644
index 000000000..3a7a7d038
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/OrfDecoder.h
@@ -0,0 +1,55 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "io/ByteStream.h" // for ByteStream
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class ByteStream;
+class CameraMetaData;
+class Buffer;
+
+class OrfDecoder final : public AbstractTiffDecoder
+{
+ ByteStream handleSlices() const;
+
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ OrfDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : AbstractTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+private:
+ int getDecoderVersion() const override { return 3; }
+ void decodeUncompressed(const ByteStream& s, uint32 w, uint32 h, uint32 size);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/PefDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/PefDecoder.cpp
new file mode 100644
index 000000000..b68db8af9
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/PefDecoder.cpp
@@ -0,0 +1,128 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2015 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/PefDecoder.h"
+#include "common/Common.h" // for uint32, BitOrder::BitO...
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for RawDecoderException (p...
+#include "decompressors/PentaxDecompressor.h" // for PentaxDecompressor
+#include "io/ByteStream.h" // for ByteStream
+#include "io/IOException.h" // for IOException
+#include "metadata/ColorFilterArray.h" // for CFAColor::CFA_GREEN
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffRootIFD, TiffIFD
+#include "tiff/TiffTag.h" // for TiffTag, TiffTag::ISOS...
+#include <memory> // for unique_ptr
+#include <string> // for operator==, string
+
+namespace rawspeed {
+
+bool PefDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "PENTAX Corporation" ||
+ make == "RICOH IMAGING COMPANY, LTD." || make == "PENTAX";
+}
+
+RawImage PefDecoder::decodeRawInternal() {
+ auto raw = mRootIFD->getIFDWithTag(STRIPOFFSETS);
+
+ int compression = raw->getEntry(COMPRESSION)->getU32();
+
+ if (1 == compression || compression == 32773) {
+ decodeUncompressed(raw, BitOrder_MSB);
+ return mRaw;
+ }
+
+ if (65535 != compression)
+ ThrowRDE("Unsupported compression");
+
+ TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
+ TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);
+
+ if (offsets->count != 1) {
+ ThrowRDE("Multiple Strips found: %u", offsets->count);
+ }
+ if (counts->count != offsets->count) {
+ ThrowRDE(
+ "Byte count number does not match strip size: count:%u, strips:%u ",
+ counts->count, offsets->count);
+ }
+ ByteStream bs(mFile, offsets->getU32(), counts->getU32());
+
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+
+ mRaw->dim = iPoint2D(width, height);
+
+ ByteStream* metaData = nullptr;
+ ByteStream stream;
+ if (getRootIFD()->hasEntryRecursive(static_cast<TiffTag>(0x220))) {
+ /* Attempt to read huffman table, if found in makernote */
+ TiffEntry* t = getRootIFD()->getEntryRecursive(static_cast<TiffTag>(0x220));
+ if (t->type != TIFF_UNDEFINED)
+ ThrowRDE("Unknown Huffman table type.");
+
+ stream = t->getData();
+ metaData = &stream;
+ }
+
+ PentaxDecompressor p(mRaw, metaData);
+ mRaw->createData();
+ p.decompress(bs);
+
+ return mRaw;
+}
+
+void PefDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ int iso = 0;
+ mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN, CFA_BLUE);
+
+ if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
+ iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32();
+
+ setMetaData(meta, "", iso);
+
+ // Read black level
+ if (mRootIFD->hasEntryRecursive(static_cast<TiffTag>(0x200))) {
+ TiffEntry* black = mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x200));
+ if (black->count == 4) {
+ for (int i = 0; i < 4; i++)
+ mRaw->blackLevelSeparate[i] = black->getU32(i);
+ }
+ }
+
+ // Set the whitebalance
+ if (mRootIFD->hasEntryRecursive(static_cast<TiffTag>(0x0201))) {
+ TiffEntry* wb = mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x0201));
+ if (wb->count == 4) {
+ mRaw->metadata.wbCoeffs[0] = wb->getU32(0);
+ mRaw->metadata.wbCoeffs[1] = wb->getU32(1);
+ mRaw->metadata.wbCoeffs[2] = wb->getU32(3);
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/PefDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/PefDecoder.h
new file mode 100644
index 000000000..4a4893377
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/PefDecoder.h
@@ -0,0 +1,48 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class CameraMetaData;
+class Buffer;
+
+class PefDecoder final : public AbstractTiffDecoder
+{
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ PefDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : AbstractTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 3; }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/RafDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/RafDecoder.cpp
new file mode 100644
index 000000000..01445b1df
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/RafDecoder.cpp
@@ -0,0 +1,349 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014-2015 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/RafDecoder.h"
+#include "common/Common.h" // for uint32, ushort16
+#include "common/Point.h" // for iPoint2D, iRecta...
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/FujiDecompressor.h" // for FujiDecompressor
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, getH...
+#include "metadata/Camera.h" // for Camera, Hints
+#include "metadata/CameraMetaData.h" // for CameraMetaData
+#include "metadata/CameraSensorInfo.h" // for CameraSensorInfo
+#include "metadata/ColorFilterArray.h" // for ColorFilterArray
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffRootIFD, Tif...
+#include "tiff/TiffTag.h" // for TiffTag::FUJI_RA...
+#include <cassert> // for assert
+#include <cstdio> // for size_t
+#include <cstring> // for memcmp
+#include <memory> // for unique_ptr
+#include <string> // for string, operator==
+#include <vector> // for vector
+
+namespace rawspeed {
+
+bool RafDecoder::isRAF(const Buffer* input) {
+ static const char magic[] = "FUJIFILMCCD-RAW ";
+ static const size_t magic_size = sizeof(magic) - 1; // excluding \0
+ const unsigned char* data = input->getData(0, magic_size);
+ return 0 == memcmp(&data[0], magic, magic_size);
+}
+
+bool RafDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "FUJIFILM";
+}
+
+RawImage RafDecoder::decodeRawInternal() {
+ auto raw = mRootIFD->getIFDWithTag(FUJI_STRIPOFFSETS);
+ uint32 height = 0;
+ uint32 width = 0;
+
+ if (raw->hasEntry(FUJI_RAWIMAGEFULLHEIGHT)) {
+ height = raw->getEntry(FUJI_RAWIMAGEFULLHEIGHT)->getU32();
+ width = raw->getEntry(FUJI_RAWIMAGEFULLWIDTH)->getU32();
+ } else if (raw->hasEntry(IMAGEWIDTH)) {
+ TiffEntry *e = raw->getEntry(IMAGEWIDTH);
+ height = e->getU16(0);
+ width = e->getU16(1);
+ } else
+ ThrowRDE("Unable to locate image size");
+
+ if (width == 0 || height == 0 || width > 9216 || height > 6210)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ if (raw->hasEntry(FUJI_LAYOUT)) {
+ TiffEntry *e = raw->getEntry(FUJI_LAYOUT);
+ alt_layout = !(e->getByte(0) >> 7);
+ }
+
+ TiffEntry *offsets = raw->getEntry(FUJI_STRIPOFFSETS);
+ TiffEntry *counts = raw->getEntry(FUJI_STRIPBYTECOUNTS);
+
+ if (offsets->count != 1 || counts->count != 1)
+ ThrowRDE("Multiple Strips found: %u %u", offsets->count, counts->count);
+
+ ByteStream input(offsets->getRootIfdData());
+ input = input.getSubStream(offsets->getU32(), counts->getU32());
+
+ if (isCompressed()) {
+ mRaw->metadata.mode = "compressed";
+
+ mRaw->dim = iPoint2D(width, height);
+
+ FujiDecompressor f(mRaw, input);
+
+ mRaw->createData();
+
+ f.decompress();
+
+ return mRaw;
+ }
+
+ // x-trans sensors report 14bpp, but data isn't packed
+ // thus, unless someone has any better ideas, let's autodetect it.
+ int bps;
+
+ // Some fuji SuperCCD cameras include a second raw image next to the first one
+ // that is identical but darker to the first. The two combined can produce
+ // a higher dynamic range image. Right now we're ignoring it.
+ bool double_width;
+
+ assert(!isCompressed());
+
+ if (8UL * counts->getU32() >= 2UL * 16UL * width * height) {
+ bps = 16;
+ double_width = true;
+ } else if (8UL * counts->getU32() >= 2UL * 14UL * width * height) {
+ bps = 14;
+ double_width = true;
+ } else if (8UL * counts->getU32() >= 2UL * 12UL * width * height) {
+ bps = 12;
+ double_width = true;
+ } else if (8UL * counts->getU32() >= 16UL * width * height) {
+ bps = 16;
+ double_width = false;
+ } else if (8UL * counts->getU32() >= 14UL * width * height) {
+ bps = 14;
+ double_width = false;
+ } else if (8UL * counts->getU32() >= 12UL * width * height) {
+ bps = 12;
+ double_width = false;
+ } else {
+ ThrowRDE("Can not detect bitdepth. StripByteCounts = %u, width = %u, "
+ "height = %u",
+ counts->getU32(), width, height);
+ }
+
+ double_width = hints.has("double_width_unpacked");
+ const uint32 real_width = double_width ? 2U * width : width;
+
+ mRaw->dim = iPoint2D(real_width, height);
+ mRaw->createData();
+
+ UncompressedDecompressor u(input, mRaw);
+
+ if (double_width) {
+ u.decodeRawUnpacked<16, Endianness::little>(width * 2, height);
+ } else if (input.getByteOrder() == Endianness::big &&
+ getHostEndianness() == Endianness::little) {
+ // FIXME: ^ that if seems fishy
+ u.decodeRawUnpacked<16, Endianness::big>(width, height);
+ } else {
+ iPoint2D pos(0, 0);
+ if (hints.has("jpeg32_bitorder")) {
+ u.readUncompressedRaw(mRaw->dim, pos, width * bps / 8, bps,
+ BitOrder_MSB32);
+ } else {
+ u.readUncompressedRaw(mRaw->dim, pos, width * bps / 8, bps, BitOrder_LSB);
+ }
+ }
+
+ return mRaw;
+}
+
+void RafDecoder::checkSupportInternal(const CameraMetaData* meta) {
+ if (!this->checkCameraSupported(meta, mRootIFD->getID(), ""))
+ ThrowRDE("Unknown camera. Will not guess.");
+
+ if (isCompressed()) {
+ mRaw->metadata.mode = "compressed";
+
+ auto id = mRootIFD->getID();
+ const Camera* cam = meta->getCamera(id.make, id.model, mRaw->metadata.mode);
+ if (!cam)
+ ThrowRDE("Couldn't find camera %s %s", id.make.c_str(), id.model.c_str());
+
+ mRaw->cfa = cam->cfa;
+ }
+}
+
+void RafDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ int iso = 0;
+ if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
+ iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32();
+ mRaw->metadata.isoSpeed = iso;
+
+ // This is where we'd normally call setMetaData but since we may still need
+ // to rotate the image for SuperCCD cameras we do everything ourselves
+ auto id = mRootIFD->getID();
+ const Camera* cam = meta->getCamera(id.make, id.model, mRaw->metadata.mode);
+ if (!cam)
+ ThrowRDE("Couldn't find camera");
+
+ assert(cam != nullptr);
+
+ iPoint2D new_size(mRaw->dim);
+ iPoint2D crop_offset = iPoint2D(0,0);
+
+ if (applyCrop) {
+ new_size = cam->cropSize;
+ crop_offset = cam->cropPos;
+ bool double_width = hints.has("double_width_unpacked");
+ // If crop size is negative, use relative cropping
+ if (new_size.x <= 0)
+ new_size.x = mRaw->dim.x / (double_width ? 2 : 1) - cam->cropPos.x + new_size.x;
+ else
+ new_size.x /= (double_width ? 2 : 1);
+ if (new_size.y <= 0)
+ new_size.y = mRaw->dim.y - cam->cropPos.y + new_size.y;
+ }
+
+ bool rotate = hints.has("fuji_rotate");
+ rotate = rotate && fujiRotate;
+
+ // Rotate 45 degrees - could be multithreaded.
+ if (rotate && !this->uncorrectedRawValues) {
+ // Calculate the 45 degree rotated size;
+ uint32 rotatedsize;
+ uint32 rotationPos;
+ if (alt_layout) {
+ rotatedsize = new_size.y+new_size.x/2;
+ rotationPos = new_size.x/2 - 1;
+ }
+ else {
+ rotatedsize = new_size.x+new_size.y/2;
+ rotationPos = new_size.x - 1;
+ }
+
+ iPoint2D final_size(rotatedsize, rotatedsize-1);
+ RawImage rotated = RawImage::create(final_size, TYPE_USHORT16, 1);
+ rotated->clearArea(iRectangle2D(iPoint2D(0,0), rotated->dim));
+ rotated->metadata = mRaw->metadata;
+ rotated->metadata.fujiRotationPos = rotationPos;
+
+ int dest_pitch = static_cast<int>(rotated->pitch) / 2;
+ auto* dst = reinterpret_cast<ushort16*>(rotated->getData(0, 0));
+
+ for (int y = 0; y < new_size.y; y++) {
+ auto* src = reinterpret_cast<ushort16*>(
+ mRaw->getData(crop_offset.x, crop_offset.y + y));
+ for (int x = 0; x < new_size.x; x++) {
+ int h;
+ int w;
+ if (alt_layout) { // Swapped x and y
+ h = rotatedsize - (new_size.y + 1 - y + (x >> 1));
+ w = ((x+1) >> 1) + y;
+ } else {
+ h = new_size.x - 1 - x + (y >> 1);
+ w = ((y+1) >> 1) + x;
+ }
+ if (h < rotated->dim.y && w < rotated->dim.x)
+ dst[w + h * dest_pitch] = src[x];
+ else
+ ThrowRDE("Trying to write out of bounds");
+ }
+ }
+ mRaw = rotated;
+ } else if (applyCrop) {
+ mRaw->subFrame(iRectangle2D(crop_offset, new_size));
+ }
+
+ const CameraSensorInfo *sensor = cam->getSensorInfo(iso);
+ mRaw->blackLevel = sensor->mBlackLevel;
+
+ // at least the (bayer sensor) X100 comes with a tag like this:
+ if (mRootIFD->hasEntryRecursive(FUJI_BLACKLEVEL)) {
+ TiffEntry* sep_black = mRootIFD->getEntryRecursive(FUJI_BLACKLEVEL);
+ if (sep_black->count == 4)
+ {
+ for(int k=0;k<4;k++)
+ mRaw->blackLevelSeparate[k] = sep_black->getU32(k);
+ } else if (sep_black->count == 36) {
+ for (int& k : mRaw->blackLevelSeparate)
+ k = 0;
+
+ for (int y = 0; y < 6; y++) {
+ for (int x = 0; x < 6; x++)
+ mRaw->blackLevelSeparate[2 * (y % 2) + (x % 2)] +=
+ sep_black->getU32(6 * y + x);
+ }
+
+ for (int& k : mRaw->blackLevelSeparate)
+ k /= 9;
+ }
+ }
+
+ mRaw->whitePoint = sensor->mWhiteLevel;
+ mRaw->blackAreas = cam->blackAreas;
+ mRaw->cfa = cam->cfa;
+ mRaw->metadata.canonical_make = cam->canonical_make;
+ mRaw->metadata.canonical_model = cam->canonical_model;
+ mRaw->metadata.canonical_alias = cam->canonical_alias;
+ mRaw->metadata.canonical_id = cam->canonical_id;
+ mRaw->metadata.make = id.make;
+ mRaw->metadata.model = id.model;
+
+ if (mRootIFD->hasEntryRecursive(FUJI_WB_GRBLEVELS)) {
+ TiffEntry *wb = mRootIFD->getEntryRecursive(FUJI_WB_GRBLEVELS);
+ if (wb->count == 3) {
+ mRaw->metadata.wbCoeffs[0] = wb->getFloat(1);
+ mRaw->metadata.wbCoeffs[1] = wb->getFloat(0);
+ mRaw->metadata.wbCoeffs[2] = wb->getFloat(2);
+ }
+ } else if (mRootIFD->hasEntryRecursive(FUJIOLDWB)) {
+ TiffEntry *wb = mRootIFD->getEntryRecursive(FUJIOLDWB);
+ if (wb->count == 8) {
+ mRaw->metadata.wbCoeffs[0] = wb->getFloat(1);
+ mRaw->metadata.wbCoeffs[1] = wb->getFloat(0);
+ mRaw->metadata.wbCoeffs[2] = wb->getFloat(3);
+ }
+ }
+}
+
+int RafDecoder::isCompressed() {
+ auto raw = mRootIFD->getIFDWithTag(FUJI_STRIPOFFSETS);
+ uint32 height = 0;
+ uint32 width = 0;
+
+ if (raw->hasEntry(FUJI_RAWIMAGEFULLHEIGHT)) {
+ height = raw->getEntry(FUJI_RAWIMAGEFULLHEIGHT)->getU32();
+ width = raw->getEntry(FUJI_RAWIMAGEFULLWIDTH)->getU32();
+ } else if (raw->hasEntry(IMAGEWIDTH)) {
+ TiffEntry* e = raw->getEntry(IMAGEWIDTH);
+ height = e->getU16(0);
+ width = e->getU16(1);
+ } else
+ ThrowRDE("Unable to locate image size");
+
+ if (width == 0 || height == 0 || width > 9216 || height > 6210)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ uint32 count = raw->getEntry(FUJI_STRIPBYTECOUNTS)->getU32();
+
+ // The uncompressed raf's can be 12/14 bpp, so if it is less than that,
+ // then we are likely in compressed raf.
+ // FIXME: this can't be the correct way to detect this. But i'm not seeing
+ // anything in the diff between exiv2/exiftool dumps of {un,}compressed raws.
+ // Maybe we are supposed to check for valid FujiDecompressor::FujiHeader ?
+ return count * 8 / (width * height) < 12;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/RafDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/RafDecoder.h
new file mode 100644
index 000000000..368ac313c
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/RafDecoder.h
@@ -0,0 +1,56 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2013 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffRootIFD (ptr only)
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class CameraMetaData;
+class Buffer;
+
+class RafDecoder final : public AbstractTiffDecoder
+{
+ bool alt_layout = false;
+
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ RafDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : AbstractTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+ void checkSupportInternal(const CameraMetaData* meta) override;
+ static bool isRAF(const Buffer* input);
+
+protected:
+ int getDecoderVersion() const override { return 1; }
+
+private:
+ int isCompressed();
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/RawDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/RawDecoder.cpp
new file mode 100644
index 000000000..fd07adcad
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/RawDecoder.cpp
@@ -0,0 +1,312 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h"
+#include "decoders/RawDecoder.h"
+#include "common/Common.h" // for uint32, splitString
+#include "common/Point.h" // for iPoint2D, iRecta...
+#include "decoders/RawDecoderException.h" // for ThrowRDE, RawDec...
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/Buffer.h" // for Buffer
+#include "io/FileIOException.h" // for FileIOException
+#include "io/IOException.h" // for IOException
+#include "metadata/Camera.h" // for Camera, Hints
+#include "metadata/CameraMetaData.h" // for CameraMetaData
+#include "metadata/CameraSensorInfo.h" // for CameraSensorInfo
+#include "metadata/ColorFilterArray.h" // for ColorFilterArray
+#include "parsers/TiffParserException.h" // for TiffParserException
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffIFD
+#include "tiff/TiffTag.h" // for TiffTag::STRIPOF...
+#include <string> // for string, basic_st...
+#include <vector> // for vector
+
+using std::vector;
+using std::string;
+
+namespace rawspeed {
+
+RawDecoder::RawDecoder(const Buffer* file)
+ : mRaw(RawImage::create()), mFile(file) {
+ failOnUnknown = false;
+ interpolateBadPixels = true;
+ applyStage1DngOpcodes = true;
+ applyCrop = true;
+ uncorrectedRawValues = false;
+ fujiRotate = true;
+}
+
+void RawDecoder::decodeUncompressed(const TiffIFD *rawIFD, BitOrder order) {
+ TiffEntry *offsets = rawIFD->getEntry(STRIPOFFSETS);
+ TiffEntry *counts = rawIFD->getEntry(STRIPBYTECOUNTS);
+ uint32 yPerSlice = rawIFD->getEntry(ROWSPERSTRIP)->getU32();
+ uint32 width = rawIFD->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = rawIFD->getEntry(IMAGELENGTH)->getU32();
+ uint32 bitPerPixel = rawIFD->getEntry(BITSPERSAMPLE)->getU32();
+
+ if (width == 0 || height == 0 || width > 5632 || height > 3720)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ mRaw->dim = iPoint2D(width, height);
+
+ if (counts->count != offsets->count) {
+ ThrowRDE("Byte count number does not match strip size: "
+ "count:%u, stips:%u ",
+ counts->count, offsets->count);
+ }
+
+ if (yPerSlice == 0 || yPerSlice > static_cast<uint32>(mRaw->dim.y) ||
+ roundUpDivision(mRaw->dim.y, yPerSlice) != counts->count) {
+ ThrowRDE("Invalid y per slice %u or strip count %u (height = %u)",
+ yPerSlice, counts->count, mRaw->dim.y);
+ }
+
+ switch (bitPerPixel) {
+ case 12:
+ case 14:
+ break;
+ default:
+ ThrowRDE("Unexpected bits per pixel: %u.", bitPerPixel);
+ };
+
+ vector<RawSlice> slices;
+ slices.reserve(counts->count);
+ uint32 offY = 0;
+
+ for (uint32 s = 0; s < counts->count; s++) {
+ RawSlice slice;
+ slice.offset = offsets->getU32(s);
+ slice.count = counts->getU32(s);
+
+ if (slice.count < 1)
+ ThrowRDE("Slice %u is empty", s);
+
+ if (offY + yPerSlice > height)
+ slice.h = height - offY;
+ else
+ slice.h = yPerSlice;
+
+ offY += yPerSlice;
+
+ if (!mFile->isValid(slice.offset, slice.count))
+ ThrowRDE("Slice offset/count invalid");
+
+ slices.push_back(slice);
+ }
+
+ if (slices.empty())
+ ThrowRDE("No valid slices found. File probably truncated.");
+
+ assert(height <= offY);
+ assert(slices.size() == counts->count);
+
+ mRaw->createData();
+
+ // Default white level is (2 ** BitsPerSample) - 1
+ mRaw->whitePoint = (1UL << bitPerPixel) - 1UL;
+
+ offY = 0;
+ for (uint32 i = 0; i < slices.size(); i++) {
+ RawSlice slice = slices[i];
+ UncompressedDecompressor u(*mFile, slice.offset, slice.count, mRaw);
+ iPoint2D size(width, slice.h);
+ iPoint2D pos(0, offY);
+ bitPerPixel = static_cast<int>(
+ static_cast<uint64>(static_cast<uint64>(slice.count) * 8U) /
+ (slice.h * width));
+ const auto inputPitch = width * bitPerPixel / 8;
+ if (!inputPitch)
+ ThrowRDE("Bad input pitch. Can not decode anything.");
+ try {
+ u.readUncompressedRaw(size, pos, inputPitch, bitPerPixel, order);
+ } catch (RawDecoderException &e) {
+ if (i>0)
+ mRaw->setError(e.what());
+ else
+ throw;
+ } catch (IOException &e) {
+ if (i>0)
+ mRaw->setError(e.what());
+ else {
+ ThrowRDE("IO error occurred in first slice, unable to decode more. "
+ "Error is: %s",
+ e.what());
+ }
+ }
+ offY += slice.h;
+ }
+}
+
+void RawDecoder::askForSamples(const CameraMetaData* meta, const string& make,
+ const string& model, const string& mode) const {
+ if ("dng" == mode)
+ return;
+
+ writeLog(DEBUG_PRIO_WARNING,
+ "Unable to find camera in database: '%s' '%s' "
+ "'%s'\nPlease consider providing samples on "
+ "<https://raw.pixls.us/>, thanks!",
+ make.c_str(), model.c_str(), mode.c_str());
+}
+
+bool RawDecoder::checkCameraSupported(const CameraMetaData* meta,
+ const string& make, const string& model,
+ const string& mode) {
+ mRaw->metadata.make = make;
+ mRaw->metadata.model = model;
+ const Camera* cam = meta->getCamera(make, model, mode);
+ if (!cam) {
+ askForSamples(meta, make, model, mode);
+
+ if (failOnUnknown)
+ ThrowRDE("Camera '%s' '%s', mode '%s' not supported, and not allowed to guess. Sorry.", make.c_str(), model.c_str(), mode.c_str());
+
+ // Assume the camera can be decoded, but return false, so decoders can see that we are unsure.
+ return false;
+ }
+
+ if (!cam->supported)
+ ThrowRDE("Camera not supported (explicit). Sorry.");
+
+ if (cam->decoderVersion > getDecoderVersion())
+ ThrowRDE("Camera not supported in this version. Update RawSpeed for support.");
+
+ hints = cam->hints;
+ return true;
+}
+
+void RawDecoder::setMetaData(const CameraMetaData* meta, const string& make,
+ const string& model, const string& mode,
+ int iso_speed) {
+ mRaw->metadata.isoSpeed = iso_speed;
+ const Camera* cam = meta->getCamera(make, model, mode);
+ if (!cam) {
+ askForSamples(meta, make, model, mode);
+
+ if (failOnUnknown)
+ ThrowRDE("Camera '%s' '%s', mode '%s' not supported, and not allowed to guess. Sorry.", make.c_str(), model.c_str(), mode.c_str());
+
+ return;
+ }
+
+ mRaw->cfa = cam->cfa;
+ mRaw->metadata.canonical_make = cam->canonical_make;
+ mRaw->metadata.canonical_model = cam->canonical_model;
+ mRaw->metadata.canonical_alias = cam->canonical_alias;
+ mRaw->metadata.canonical_id = cam->canonical_id;
+ mRaw->metadata.make = make;
+ mRaw->metadata.model = model;
+ mRaw->metadata.mode = mode;
+
+ if (applyCrop) {
+ iPoint2D new_size = cam->cropSize;
+
+ // If crop size is negative, use relative cropping
+ if (new_size.x <= 0)
+ new_size.x = mRaw->dim.x - cam->cropPos.x + new_size.x;
+
+ if (new_size.y <= 0)
+ new_size.y = mRaw->dim.y - cam->cropPos.y + new_size.y;
+
+ mRaw->subFrame(iRectangle2D(cam->cropPos, new_size));
+ }
+
+ const CameraSensorInfo *sensor = cam->getSensorInfo(iso_speed);
+ mRaw->blackLevel = sensor->mBlackLevel;
+ mRaw->whitePoint = sensor->mWhiteLevel;
+ mRaw->blackAreas = cam->blackAreas;
+ if (mRaw->blackAreas.empty() && !sensor->mBlackLevelSeparate.empty()) {
+ auto cfaArea = mRaw->cfa.getSize().area();
+ if (mRaw->isCFA && cfaArea <= sensor->mBlackLevelSeparate.size()) {
+ for (uint32 i = 0; i < cfaArea; i++) {
+ mRaw->blackLevelSeparate[i] = sensor->mBlackLevelSeparate[i];
+ }
+ } else if (!mRaw->isCFA && mRaw->getCpp() <= sensor->mBlackLevelSeparate.size()) {
+ for (uint32 i = 0; i < mRaw->getCpp(); i++) {
+ mRaw->blackLevelSeparate[i] = sensor->mBlackLevelSeparate[i];
+ }
+ }
+ }
+
+ // Allow overriding individual blacklevels. Values are in CFA order
+ // (the same order as the in the CFA tag)
+ // A hint could be:
+ // <Hint name="override_cfa_black" value="10,20,30,20"/>
+ string cfa_black = hints.get("override_cfa_black", string());
+ if (!cfa_black.empty()) {
+ vector<string> v = splitString(cfa_black, ',');
+ if (v.size() != 4) {
+ mRaw->setError("Expected 4 values '10,20,30,20' as values for override_cfa_black hint.");
+ } else {
+ for (int i = 0; i < 4; i++) {
+ mRaw->blackLevelSeparate[i] = stoi(v[i]);
+ }
+ }
+ }
+}
+
+rawspeed::RawImage RawDecoder::decodeRaw() {
+ try {
+ RawImage raw = decodeRawInternal();
+ raw->checkMemIsInitialized();
+
+ raw->metadata.pixelAspectRatio =
+ hints.get("pixel_aspect_ratio", raw->metadata.pixelAspectRatio);
+ if (interpolateBadPixels) {
+ raw->fixBadPixels();
+ raw->checkMemIsInitialized();
+ }
+
+ return raw;
+ } catch (TiffParserException &e) {
+ ThrowRDE("%s", e.what());
+ } catch (FileIOException &e) {
+ ThrowRDE("%s", e.what());
+ } catch (IOException &e) {
+ ThrowRDE("%s", e.what());
+ }
+}
+
+void RawDecoder::decodeMetaData(const CameraMetaData* meta) {
+ try {
+ decodeMetaDataInternal(meta);
+ } catch (TiffParserException &e) {
+ ThrowRDE("%s", e.what());
+ } catch (FileIOException &e) {
+ ThrowRDE("%s", e.what());
+ } catch (IOException &e) {
+ ThrowRDE("%s", e.what());
+ }
+}
+
+void RawDecoder::checkSupport(const CameraMetaData* meta) {
+ try {
+ checkSupportInternal(meta);
+ } catch (TiffParserException &e) {
+ ThrowRDE("%s", e.what());
+ } catch (FileIOException &e) {
+ ThrowRDE("%s", e.what());
+ } catch (IOException &e) {
+ ThrowRDE("%s", e.what());
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/RawDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/RawDecoder.h
new file mode 100644
index 000000000..d0ec9805a
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/RawDecoder.h
@@ -0,0 +1,166 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, BitOrder
+#include "common/RawImage.h" // for RawImage
+#include "metadata/Camera.h" // for Hints
+#include <string> // for string
+
+namespace rawspeed {
+
+class Buffer;
+
+class CameraMetaData;
+
+class TiffIFD;
+
+class RawDecoder
+{
+public:
+ /* Construct decoder instance - Buffer is a filemap of the file to be decoded
+ */
+ /* The Buffer is not owned by this class, will not be deleted, and must remain
+ */
+ /* valid while this object exists */
+ explicit RawDecoder(const Buffer* file);
+ virtual ~RawDecoder() = default;
+
+ /* Check if the decoder can decode the image from this camera */
+ /* A RawDecoderException will be thrown if the camera isn't supported */
+ /* Unknown cameras does NOT generate any specific feedback */
+ /* This function must be overridden by actual decoders */
+ void checkSupport(const CameraMetaData* meta);
+
+ /* Attempt to decode the image */
+ /* A RawDecoderException will be thrown if the image cannot be decoded, */
+ /* and there will not be any data in the mRaw image. */
+ RawImage decodeRaw();
+
+ /* This will apply metadata information from the camera database, */
+ /* such as crop, black+white level, etc. */
+ /* This function is expected to use the protected "setMetaData" */
+ /* after retrieving make, model and mode if applicate. */
+ /* If meta-data is set during load, this function can be empty. */
+ /* The image is expected to be cropped after this, but black/whitelevel */
+ /* compensation is not expected to be applied to the image */
+ void decodeMetaData(const CameraMetaData* meta);
+
+ /* Allows access to the root IFD structure */
+ /* If image isn't TIFF based NULL will be returned */
+ virtual TiffIFD *getRootIFD() { return nullptr; }
+
+ /* The decoded image - undefined if image has not or could not be decoded. */
+ /* Remember this is automatically refcounted, so a reference is retained until this class is destroyed */
+ RawImage mRaw;
+
+ /* You can set this if you do not want Rawspeed to attempt to decode images, */
+ /* where it does not have reliable information about CFA, cropping, black and white point */
+ /* It is pretty safe to leave this disabled (default behaviour), but if you do not want to */
+ /* support unknown cameras, you can enable this */
+ /* DNGs are always attempted to be decoded, so this variable has no effect on DNGs */
+ bool failOnUnknown;
+
+ /* Set how to handle bad pixels. */
+ /* If you disable this parameter, no bad pixel interpolation will be done */
+ bool interpolateBadPixels;
+
+ /* Apply stage 1 DNG opcodes. */
+ /* This usually maps out bad pixels, etc */
+ bool applyStage1DngOpcodes;
+
+ /* Apply crop - if false uncropped image is delivered */
+ bool applyCrop;
+
+ /* This will skip all corrections, and deliver the raw data */
+ /* This will skip any compression curves or other things that */
+ /* is needed to get the correct values */
+ /* Only enable if you are sure that is what you want */
+ bool uncorrectedRawValues;
+
+ /* Should Fuji images be rotated? */
+ bool fujiRotate;
+
+ struct {
+ /* Should Quadrant Multipliers be applied to the IIQ raws? */
+ bool quadrantMultipliers = true;
+
+ // Is *any* of the corrections enabled?
+ explicit operator bool() const { return quadrantMultipliers /*|| ...*/; }
+ } iiq;
+
+ /* Retrieve the main RAW chunk */
+ /* Returns NULL if unknown */
+ virtual Buffer* getCompressedData() { return nullptr; }
+
+protected:
+ /* Attempt to decode the image */
+ /* A RawDecoderException will be thrown if the image cannot be decoded, */
+ /* and there will not be any data in the mRaw image. */
+ /* This function must be overridden by actual decoders. */
+ virtual RawImage decodeRawInternal() = 0;
+ virtual void decodeMetaDataInternal(const CameraMetaData* meta) = 0;
+ virtual void checkSupportInternal(const CameraMetaData* meta) = 0;
+
+ /* Ask for sample submisson, if makes sense */
+ void askForSamples(const CameraMetaData* meta, const std::string& make,
+ const std::string& model, const std::string& mode) const;
+
+ /* Check the camera and mode against the camera database. */
+ /* A RawDecoderException will be thrown if the camera isn't supported */
+ /* Unknown cameras does NOT generate any errors, but returns false */
+ bool checkCameraSupported(const CameraMetaData* meta, const std::string& make,
+ const std::string& model, const std::string& mode);
+
+ /* Helper function for decodeMetaData(), that find the camera in the CameraMetaData DB */
+ /* and sets common settings such as crop, black- white level, and sets CFA information */
+ virtual void setMetaData(const CameraMetaData* meta, const std::string& make,
+ const std::string& model, const std::string& mode,
+ int iso_speed = 0);
+
+ /* Generic decompressor for uncompressed images */
+ /* order: Order of the bits - see Common.h for possibilities. */
+ void decodeUncompressed(const TiffIFD* rawIFD, BitOrder order);
+
+ /* The Raw input file to be decoded */
+ const Buffer* mFile;
+
+ /* Decoder version */
+ /* This can be used to avoid newer version of an xml file to indicate that a file */
+ /* can be decoded, when a specific version of the code is needed */
+ /* Higher number in camera xml file: Files for this camera will not be decoded */
+ /* Higher number in code than xml: Image will be decoded. */
+ virtual int getDecoderVersion() const = 0;
+
+ /* Hints set for the camera after checkCameraSupported has been called from the implementation*/
+ Hints hints;
+
+ struct RawSlice;
+};
+
+struct RawDecoder::RawSlice {
+ uint32 h = 0;
+ uint32 offset = 0;
+ uint32 count = 0;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/RawDecoderException.h b/src/external/rawspeed/src/librawspeed/decoders/RawDecoderException.h
new file mode 100644
index 000000000..c29d1d09e
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/RawDecoderException.h
@@ -0,0 +1,39 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawspeedException.h" // for ThrowException, RawspeedException
+#include <string> // for string
+
+namespace rawspeed {
+
+class RawDecoderException : public RawspeedException {
+public:
+ explicit RawDecoderException(const std::string& msg)
+ : RawspeedException(msg) {}
+ explicit RawDecoderException(const char* msg) : RawspeedException(msg) {}
+};
+
+#define ThrowRDE(...) \
+ ThrowExceptionHelper(rawspeed::RawDecoderException, __VA_ARGS__)
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/Rw2Decoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/Rw2Decoder.cpp
new file mode 100644
index 000000000..6a9c0e744
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/Rw2Decoder.cpp
@@ -0,0 +1,249 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/Rw2Decoder.h"
+#include "common/Common.h" // for writeLog, uint32
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/PanasonicDecompressor.h" // for PanasonicDecompr...
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endi...
+#include "metadata/Camera.h" // for Hints
+#include "metadata/ColorFilterArray.h" // for CFAColor::CFA_GREEN
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffIFD, TiffRoo...
+#include "tiff/TiffTag.h" // for TiffTag, TiffTag...
+#include <cmath> // for fabs
+#include <memory> // for unique_ptr
+#include <string> // for string, operator==
+
+using std::string;
+using std::fabs;
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+bool Rw2Decoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "Panasonic" || make == "LEICA";
+}
+
+RawImage Rw2Decoder::decodeRawInternal() {
+
+ const TiffIFD* raw = nullptr;
+ bool isOldPanasonic = ! mRootIFD->hasEntryRecursive(PANASONIC_STRIPOFFSET);
+
+ if (! isOldPanasonic)
+ raw = mRootIFD->getIFDWithTag(PANASONIC_STRIPOFFSET);
+ else
+ raw = mRootIFD->getIFDWithTag(STRIPOFFSETS);
+
+ uint32 height = raw->getEntry(static_cast<TiffTag>(3))->getU16();
+ uint32 width = raw->getEntry(static_cast<TiffTag>(2))->getU16();
+
+ if (isOldPanasonic) {
+ if (width == 0 || height == 0 || width > 4330 || height > 2751)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
+
+ if (offsets->count != 1) {
+ ThrowRDE("Multiple Strips found: %u", offsets->count);
+ }
+ offset = offsets->getU32();
+ if (!mFile->isValid(offset))
+ ThrowRDE("Invalid image data offset, cannot decode.");
+
+ mRaw->dim = iPoint2D(width, height);
+
+ uint32 size = mFile->getSize() - offset;
+
+ UncompressedDecompressor u(ByteStream(mFile, offset), mRaw);
+
+ if (size >= width*height*2) {
+ // It's completely unpacked little-endian
+ mRaw->createData();
+ u.decodeRawUnpacked<12, Endianness::little>(width, height);
+ } else if (size >= width*height*3/2) {
+ // It's a packed format
+ mRaw->createData();
+ u.decode12BitRaw<Endianness::little, false, true>(width, height);
+ } else {
+ // It's using the new .RW2 decoding method
+ load_flags = 0;
+ // It's using the new .RW2 decoding method
+ PanasonicDecompressor p(mRaw, ByteStream(mFile, offset),
+ hints.has("zero_is_not_bad"), load_flags);
+ mRaw->createData();
+ p.decompress();
+ }
+ } else {
+ mRaw->dim = iPoint2D(width, height);
+
+ TiffEntry *offsets = raw->getEntry(PANASONIC_STRIPOFFSET);
+
+ if (offsets->count != 1) {
+ ThrowRDE("Multiple Strips found: %u", offsets->count);
+ }
+
+ offset = offsets->getU32();
+
+ if (!mFile->isValid(offset))
+ ThrowRDE("Invalid image data offset, cannot decode.");
+
+ // It's using the new .RW2 decoding method
+ load_flags = 0x2008;
+ // It's using the new .RW2 decoding method
+ PanasonicDecompressor p(mRaw, ByteStream(mFile, offset),
+ hints.has("zero_is_not_bad"), load_flags);
+ mRaw->createData();
+ p.decompress();
+ }
+
+ return mRaw;
+}
+
+void Rw2Decoder::checkSupportInternal(const CameraMetaData* meta) {
+ auto id = mRootIFD->getID();
+ if (!checkCameraSupported(meta, id, guessMode()))
+ checkCameraSupported(meta, id, "");
+}
+
+void Rw2Decoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ mRaw->cfa.setCFA(iPoint2D(2,2), CFA_BLUE, CFA_GREEN, CFA_GREEN, CFA_RED);
+
+ auto id = mRootIFD->getID();
+ string mode = guessMode();
+ int iso = 0;
+ if (mRootIFD->hasEntryRecursive(PANASONIC_ISO_SPEED))
+ iso = mRootIFD->getEntryRecursive(PANASONIC_ISO_SPEED)->getU32();
+
+ if (this->checkCameraSupported(meta, id, mode)) {
+ setMetaData(meta, id, mode, iso);
+ } else {
+ mRaw->metadata.mode = mode;
+ writeLog(DEBUG_PRIO_EXTRA, "Mode not found in DB: %s", mode.c_str());
+ setMetaData(meta, id, "", iso);
+ }
+
+ const TiffIFD* raw = mRootIFD->hasEntryRecursive(PANASONIC_STRIPOFFSET)
+ ? mRootIFD->getIFDWithTag(PANASONIC_STRIPOFFSET)
+ : mRootIFD->getIFDWithTag(STRIPOFFSETS);
+
+ // Read blacklevels
+ if (raw->hasEntry(static_cast<TiffTag>(0x1c)) &&
+ raw->hasEntry(static_cast<TiffTag>(0x1d)) &&
+ raw->hasEntry(static_cast<TiffTag>(0x1e))) {
+ const auto getBlack = [&raw](TiffTag t) -> int {
+ const auto val = raw->getEntry(t)->getU32();
+ int out;
+ if (__builtin_sadd_overflow(val, 15, &out))
+ ThrowRDE("Integer overflow when calculating black level");
+ return out;
+ };
+
+ const int blackRed = getBlack(static_cast<TiffTag>(0x1c));
+ const int blackGreen = getBlack(static_cast<TiffTag>(0x1d));
+ const int blackBlue = getBlack(static_cast<TiffTag>(0x1e));
+
+ for(int i = 0; i < 2; i++) {
+ for(int j = 0; j < 2; j++) {
+ const int k = i + 2 * j;
+ const CFAColor c = mRaw->cfa.getColorAt(i, j);
+ switch (c) {
+ case CFA_RED:
+ mRaw->blackLevelSeparate[k] = blackRed;
+ break;
+ case CFA_GREEN:
+ mRaw->blackLevelSeparate[k] = blackGreen;
+ break;
+ case CFA_BLUE:
+ mRaw->blackLevelSeparate[k] = blackBlue;
+ break;
+ default:
+ ThrowRDE("Unexpected CFA color %s.",
+ ColorFilterArray::colorToString(c).c_str());
+ }
+ }
+ }
+ }
+
+ // Read WB levels
+ if (raw->hasEntry(static_cast<TiffTag>(0x0024)) &&
+ raw->hasEntry(static_cast<TiffTag>(0x0025)) &&
+ raw->hasEntry(static_cast<TiffTag>(0x0026))) {
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(
+ raw->getEntry(static_cast<TiffTag>(0x0024))->getU16());
+ mRaw->metadata.wbCoeffs[1] = static_cast<float>(
+ raw->getEntry(static_cast<TiffTag>(0x0025))->getU16());
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(
+ raw->getEntry(static_cast<TiffTag>(0x0026))->getU16());
+ } else if (raw->hasEntry(static_cast<TiffTag>(0x0011)) &&
+ raw->hasEntry(static_cast<TiffTag>(0x0012))) {
+ mRaw->metadata.wbCoeffs[0] = static_cast<float>(
+ raw->getEntry(static_cast<TiffTag>(0x0011))->getU16());
+ mRaw->metadata.wbCoeffs[1] = 256.0F;
+ mRaw->metadata.wbCoeffs[2] = static_cast<float>(
+ raw->getEntry(static_cast<TiffTag>(0x0012))->getU16());
+ }
+}
+
+std::string Rw2Decoder::guessMode() {
+ float ratio = 3.0F / 2.0F; // Default
+
+ if (!mRaw->isAllocated())
+ return "";
+
+ ratio = static_cast<float>(mRaw->dim.x) / static_cast<float>(mRaw->dim.y);
+
+ float min_diff = fabs(ratio - 16.0F / 9.0F);
+ std::string closest_match = "16:9";
+
+ float t = fabs(ratio - 3.0F / 2.0F);
+ if (t < min_diff) {
+ closest_match = "3:2";
+ min_diff = t;
+ }
+
+ t = fabs(ratio - 4.0F / 3.0F);
+ if (t < min_diff) {
+ closest_match = "4:3";
+ min_diff = t;
+ }
+
+ t = fabs(ratio - 1.0F);
+ if (t < min_diff) {
+ closest_match = "1:1";
+ min_diff = t;
+ }
+ writeLog(DEBUG_PRIO_EXTRA, "Mode guess: '%s'", closest_match.c_str());
+ return closest_match;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/Rw2Decoder.h b/src/external/rawspeed/src/librawspeed/decoders/Rw2Decoder.h
new file mode 100644
index 000000000..5f5b4f999
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/Rw2Decoder.h
@@ -0,0 +1,57 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <algorithm> // for move
+#include <string> // for string
+
+namespace rawspeed {
+
+class CameraMetaData;
+class Buffer;
+
+class Rw2Decoder final : public AbstractTiffDecoder
+{
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ Rw2Decoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : AbstractTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+ void checkSupportInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 2; }
+
+private:
+ std::string guessMode();
+ uint32 offset = 0;
+ uint32 load_flags = 0;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/SimpleTiffDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/SimpleTiffDecoder.cpp
new file mode 100644
index 000000000..a031f212a
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/SimpleTiffDecoder.cpp
@@ -0,0 +1,56 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/SimpleTiffDecoder.h"
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decoders/RawDecoderException.h" // for RawDecoderException (ptr o...
+#include "io/Buffer.h" // for Buffer
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffIFD
+#include "tiff/TiffTag.h" // for TiffTag::IMAGELENGTH, Tiff...
+
+namespace rawspeed {
+
+void SimpleTiffDecoder::prepareForRawDecoding() {
+ raw = getIFDWithLargestImage();
+ width = raw->getEntry(IMAGEWIDTH)->getU32();
+ height = raw->getEntry(IMAGELENGTH)->getU32();
+ off = raw->getEntry(STRIPOFFSETS)->getU32();
+ c2 = raw->getEntry(STRIPBYTECOUNTS)->getU32();
+
+ if (!mFile->isValid(off, c2))
+ ThrowRDE("Image is truncated.");
+
+ if (c2 == 0)
+ ThrowRDE("No image data found.");
+
+ if (0 == width || 0 == height)
+ ThrowRDE("Image has zero size.");
+
+ checkImageDimensions();
+
+ mRaw->dim = iPoint2D(width, height);
+ mRaw->createData();
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/SimpleTiffDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/SimpleTiffDecoder.h
new file mode 100644
index 000000000..fecf038ea
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/SimpleTiffDecoder.h
@@ -0,0 +1,51 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffIFD (ptr only), TiffRo...
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class Buffer;
+
+class SimpleTiffDecoder : public AbstractTiffDecoder {
+ virtual void checkImageDimensions() {}
+
+public:
+ SimpleTiffDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : AbstractTiffDecoder(move(root), file) {}
+
+ void prepareForRawDecoding();
+
+protected:
+ const TiffIFD* raw;
+ uint32 width;
+ uint32 height;
+ uint32 off;
+ uint32 c2;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/SrwDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/SrwDecoder.cpp
new file mode 100644
index 000000000..57e1e2449
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/SrwDecoder.cpp
@@ -0,0 +1,178 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2010 Klaus Post
+ Copyright (C) 2014-2015 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/SrwDecoder.h"
+#include "common/Common.h" // for BitOrder::BitOrder_LSB
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/SamsungV0Decompressor.h" // for SamsungV0Decompressor
+#include "decompressors/SamsungV1Decompressor.h" // for SamsungV1Decompressor
+#include "decompressors/SamsungV2Decompressor.h" // for SamsungV2Decompressor
+#include "io/ByteStream.h" // for ByteStream
+#include "metadata/Camera.h" // for Hints
+#include "metadata/CameraMetaData.h" // for CameraMetaData
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffRootIFD, TiffIFD
+#include "tiff/TiffTag.h" // for TiffTag::BITSPERSAMPLE
+#include <memory> // for unique_ptr
+#include <sstream> // for operator<<, ostring...
+#include <string> // for string, operator==
+#include <vector> // for vector
+
+namespace rawspeed {
+
+bool SrwDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "SAMSUNG";
+}
+
+RawImage SrwDecoder::decodeRawInternal() {
+ auto raw = mRootIFD->getIFDWithTag(STRIPOFFSETS);
+
+ int compression = raw->getEntry(COMPRESSION)->getU32();
+ const int bits = raw->getEntry(BITSPERSAMPLE)->getU32();
+
+ if (12 != bits && 14 != bits)
+ ThrowRDE("Unsupported bits per sample");
+
+ if (32769 != compression && 32770 != compression && 32772 != compression && 32773 != compression)
+ ThrowRDE("Unsupported compression");
+
+ uint32 nslices = raw->getEntry(STRIPOFFSETS)->count;
+ if (nslices != 1)
+ ThrowRDE("Only one slice supported, found %u", nslices);
+
+ const auto wrongComp =
+ 32770 == compression && !raw->hasEntry(static_cast<TiffTag>(40976));
+ if (32769 == compression || wrongComp) {
+ bool bit_order = hints.get("msb_override", wrongComp ? bits == 12 : false);
+ this->decodeUncompressed(raw, bit_order ? BitOrder_MSB : BitOrder_LSB);
+ return mRaw;
+ }
+
+ const uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ const uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+ mRaw->dim = iPoint2D(width, height);
+
+ if (32770 == compression)
+ {
+ const TiffEntry* sliceOffsets = raw->getEntry(static_cast<TiffTag>(40976));
+ if (sliceOffsets->type != TIFF_LONG || sliceOffsets->count != 1)
+ ThrowRDE("Entry 40976 is corrupt");
+
+ ByteStream bso(DataBuffer(*mFile, Endianness::little));
+ bso.skipBytes(sliceOffsets->getU32());
+ bso = bso.getStream(height, 4);
+
+ const uint32 offset = raw->getEntry(STRIPOFFSETS)->getU32();
+ const uint32 count = raw->getEntry(STRIPBYTECOUNTS)->getU32();
+ Buffer rbuf(mFile->getSubView(offset, count));
+ ByteStream bsr(DataBuffer(rbuf, Endianness::little));
+
+ SamsungV0Decompressor s0(mRaw, bso, bsr);
+
+ mRaw->createData();
+
+ s0.decompress();
+
+ return mRaw;
+ }
+ if (32772 == compression)
+ {
+ uint32 offset = raw->getEntry(STRIPOFFSETS)->getU32();
+ uint32 count = raw->getEntry(STRIPBYTECOUNTS)->getU32();
+ const ByteStream bs(mFile, offset, count);
+
+ SamsungV1Decompressor s1(mRaw, &bs, bits);
+
+ mRaw->createData();
+
+ s1.decompress();
+
+ return mRaw;
+ }
+ if (32773 == compression)
+ {
+ uint32 offset = raw->getEntry(STRIPOFFSETS)->getU32();
+ uint32 count = raw->getEntry(STRIPBYTECOUNTS)->getU32();
+ const ByteStream bs(mFile, offset, count);
+
+ SamsungV2Decompressor s2(mRaw, bs, bits);
+
+ mRaw->createData();
+
+ s2.decompress();
+
+ return mRaw;
+ }
+ ThrowRDE("Unsupported compression");
+}
+
+std::string SrwDecoder::getMode() {
+ std::vector<const TiffIFD*> data = mRootIFD->getIFDsWithTag(CFAPATTERN);
+ std::ostringstream mode;
+ if (!data.empty() && data[0]->hasEntryRecursive(BITSPERSAMPLE)) {
+ mode << data[0]->getEntryRecursive(BITSPERSAMPLE)->getU32() << "bit";
+ return mode.str();
+ }
+ return "";
+}
+
+void SrwDecoder::checkSupportInternal(const CameraMetaData* meta) {
+ auto id = mRootIFD->getID();
+ std::string mode = getMode();
+ if (meta->hasCamera(id.make, id.model, mode))
+ this->checkCameraSupported(meta, id, getMode());
+ else
+ this->checkCameraSupported(meta, id, "");
+}
+
+void SrwDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ int iso = 0;
+ if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
+ iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getU32();
+
+ auto id = mRootIFD->getID();
+ std::string mode = getMode();
+ if (meta->hasCamera(id.make, id.model, mode))
+ setMetaData(meta, id, mode, iso);
+ else
+ setMetaData(meta, id, "", iso);
+
+ // Set the whitebalance
+ if (mRootIFD->hasEntryRecursive(SAMSUNG_WB_RGGBLEVELSUNCORRECTED) &&
+ mRootIFD->hasEntryRecursive(SAMSUNG_WB_RGGBLEVELSBLACK)) {
+ TiffEntry *wb_levels = mRootIFD->getEntryRecursive(SAMSUNG_WB_RGGBLEVELSUNCORRECTED);
+ TiffEntry *wb_black = mRootIFD->getEntryRecursive(SAMSUNG_WB_RGGBLEVELSBLACK);
+ if (wb_levels->count == 4 && wb_black->count == 4) {
+ mRaw->metadata.wbCoeffs[0] = wb_levels->getFloat(0) - wb_black->getFloat(0);
+ mRaw->metadata.wbCoeffs[1] = wb_levels->getFloat(1) - wb_black->getFloat(1);
+ mRaw->metadata.wbCoeffs[2] = wb_levels->getFloat(3) - wb_black->getFloat(3);
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/SrwDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/SrwDecoder.h
new file mode 100644
index 000000000..a1b540f9f
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/SrwDecoder.h
@@ -0,0 +1,51 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2010 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffIFD (ptr only), TiffRo...
+#include <algorithm> // for move
+#include <string> // for string
+
+namespace rawspeed {
+
+class CameraMetaData;
+class Buffer;
+
+class SrwDecoder final : public AbstractTiffDecoder
+{
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ SrwDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : AbstractTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+ void checkSupportInternal(const CameraMetaData* meta) override;
+
+private:
+ int getDecoderVersion() const override { return 3; }
+ std::string getMode();
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/ThreefrDecoder.cpp b/src/external/rawspeed/src/librawspeed/decoders/ThreefrDecoder.cpp
new file mode 100644
index 000000000..7eb575a37
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/ThreefrDecoder.cpp
@@ -0,0 +1,91 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decoders/ThreefrDecoder.h"
+#include "common/Common.h" // for uint32
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/HasselbladDecompressor.h" // for HasselbladDecompre...
+#include "io/ByteStream.h" // for ByteStream
+#include "io/IOException.h" // for IOException
+#include "metadata/Camera.h" // for Hints
+#include "metadata/ColorFilterArray.h" // for CFAColor::CFA_GREEN
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffRootIFD, TiffIFD
+#include "tiff/TiffTag.h" // for TiffTag::ASSHOTNEU...
+#include <memory> // for unique_ptr
+#include <string> // for operator==, string
+
+namespace rawspeed {
+
+class CameraMetaData;
+
+bool ThreefrDecoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file) {
+ const auto id = rootIFD->getID();
+ const std::string& make = id.make;
+
+ // FIXME: magic
+
+ return make == "Hasselblad";
+}
+
+RawImage ThreefrDecoder::decodeRawInternal() {
+ auto raw = mRootIFD->getIFDWithTag(STRIPOFFSETS, 1);
+ uint32 width = raw->getEntry(IMAGEWIDTH)->getU32();
+ uint32 height = raw->getEntry(IMAGELENGTH)->getU32();
+ uint32 off = raw->getEntry(STRIPOFFSETS)->getU32();
+ // STRIPBYTECOUNTS is strange/invalid for the existing 3FR samples...
+
+ const ByteStream bs(mFile->getSubView(off), 0);
+
+ mRaw->dim = iPoint2D(width, height);
+
+ HasselbladDecompressor l(bs, mRaw);
+ mRaw->createData();
+
+ int pixelBaseOffset = hints.get("pixelBaseOffset", 0);
+ l.decode(pixelBaseOffset);
+
+ return mRaw;
+}
+
+void ThreefrDecoder::decodeMetaDataInternal(const CameraMetaData* meta) {
+ mRaw->cfa.setCFA(iPoint2D(2,2), CFA_RED, CFA_GREEN, CFA_GREEN, CFA_BLUE);
+
+ setMetaData(meta, "", 0);
+
+ // Fetch the white balance
+ if (mRootIFD->hasEntryRecursive(ASSHOTNEUTRAL)) {
+ TiffEntry *wb = mRootIFD->getEntryRecursive(ASSHOTNEUTRAL);
+ if (wb->count == 3) {
+ for (uint32 i = 0; i < 3; i++) {
+ const float div = wb->getFloat(i);
+ if (div == 0.0f)
+ ThrowRDE("Can not decode WB, multiplier is zero/");
+
+ mRaw->metadata.wbCoeffs[i] = 1.0F / div;
+ }
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decoders/ThreefrDecoder.h b/src/external/rawspeed/src/librawspeed/decoders/ThreefrDecoder.h
new file mode 100644
index 000000000..fc3d03db4
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decoders/ThreefrDecoder.h
@@ -0,0 +1,49 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decoders/AbstractTiffDecoder.h" // for AbstractTiffDecoder
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class CameraMetaData;
+class Buffer;
+
+class ThreefrDecoder final : public AbstractTiffDecoder
+{
+public:
+ static bool isAppropriateDecoder(const TiffRootIFD* rootIFD,
+ const Buffer* file);
+ ThreefrDecoder(TiffRootIFDOwner&& root, const Buffer* file)
+ : AbstractTiffDecoder(move(root), file) {}
+
+ RawImage decodeRawInternal() override;
+ void decodeMetaDataInternal(const CameraMetaData* meta) override;
+
+protected:
+ int getDecoderVersion() const override { return 0; }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/AbstractDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/AbstractDecompressor.h
new file mode 100644
index 000000000..3538ca509
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/AbstractDecompressor.h
@@ -0,0 +1,27 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+namespace rawspeed {
+
+class AbstractDecompressor {};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/AbstractDngDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/AbstractDngDecompressor.cpp
new file mode 100644
index 000000000..30c7a44a4
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/AbstractDngDecompressor.cpp
@@ -0,0 +1,169 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h" // for HAVE_JPEG, HAVE_...
+#include "decompressors/AbstractDngDecompressor.h"
+#include "common/Common.h" // for BitOrder::BitOrd...
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImageData
+#include "decoders/RawDecoderException.h" // for RawDecoderException
+#include "decompressors/DeflateDecompressor.h" // for DeflateDecompressor
+#include "decompressors/JpegDecompressor.h" // for JpegDecompressor
+#include "decompressors/LJpegDecompressor.h" // for LJpegDecompressor
+#include "decompressors/UncompressedDecompressor.h" // for UncompressedDeco...
+#include "io/Buffer.h" // for Buffer (ptr only)
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endi...
+#include "io/IOException.h" // for IOException
+#include "tiff/TiffIFD.h" // for getTiffByteOrder
+#include <cassert> // for assert
+#include <cstdio> // for size_t
+#include <limits> // for numeric_limits
+#include <memory> // for unique_ptr
+#include <vector> // for vector
+
+namespace rawspeed {
+
+void AbstractDngDecompressor::decompress() const {
+ startThreading(slices.size());
+}
+
+void AbstractDngDecompressor::decompressThreaded(
+ const RawDecompressorThread* t) const {
+ assert(t);
+ assert(mRaw->dim.x > 0);
+ assert(mRaw->dim.y > 0);
+ assert(mRaw->getCpp() > 0 && mRaw->getCpp() <= 4);
+ assert(mBps > 0 && mBps <= 32);
+
+ if (compression == 1) {
+ for (size_t i = t->start; i < t->end && i < slices.size(); i++) {
+ auto e = &slices[i];
+
+ UncompressedDecompressor decompressor(e->bs, mRaw);
+
+ size_t thisTileLength =
+ e->offY + e->height > static_cast<uint32>(mRaw->dim.y)
+ ? mRaw->dim.y - e->offY
+ : e->height;
+
+ size_t thisTileWidth =
+ e->offX + e->width > static_cast<uint32>(mRaw->dim.x)
+ ? mRaw->dim.x - e->offX
+ : e->width;
+
+ if (thisTileLength == 0)
+ ThrowRDE("Tile is empty. Can not decode!");
+
+ iPoint2D tileSize(thisTileWidth, thisTileLength);
+ iPoint2D pos(e->offX, e->offY);
+
+ // FIXME: does bytestream have correct byteorder from the src file?
+ bool big_endian = e->bs.getByteOrder() == Endianness::big;
+
+ // DNG spec says that if not 8 or 16 bit/sample, always use big endian
+ if (mBps != 8 && mBps != 16)
+ big_endian = true;
+
+ try {
+ const uint32 inputPixelBits = mRaw->getCpp() * mBps;
+
+ if (e->width > std::numeric_limits<int>::max() / inputPixelBits)
+ ThrowIOE("Integer overflow when calculating input pitch");
+
+ const int inputPitchBits = inputPixelBits * e->width;
+ assert(inputPitchBits > 0);
+
+ if (inputPitchBits % 8 != 0) {
+ ThrowRDE("Bad combination of cpp (%u), bps (%u) and width (%u), the "
+ "pitch is %u bits, which is not a multiple of 8 (1 byte)",
+ mRaw->getCpp(), mBps, e->width, inputPitchBits);
+ }
+
+ const int inputPitch = inputPitchBits / 8;
+ if (inputPitch == 0)
+ ThrowRDE("Data input pitch is too short. Can not decode!");
+
+ decompressor.readUncompressedRaw(tileSize, pos, inputPitch, mBps,
+ big_endian ? BitOrder_MSB
+ : BitOrder_LSB);
+ } catch (RawDecoderException& err) {
+ mRaw->setError(err.what());
+ } catch (IOException& err) {
+ mRaw->setError(err.what());
+ }
+ }
+ } else if (compression == 7) {
+ for (size_t i = t->start; i < t->end && i < slices.size(); i++) {
+ auto e = &slices[i];
+ LJpegDecompressor d(e->bs, mRaw);
+ try {
+ d.decode(e->offX, e->offY, e->width, e->height, mFixLjpeg);
+ } catch (RawDecoderException& err) {
+ mRaw->setError(err.what());
+ } catch (IOException& err) {
+ mRaw->setError(err.what());
+ }
+ }
+ /* Deflate compression */
+ } else if (compression == 8) {
+#ifdef HAVE_ZLIB
+ std::unique_ptr<unsigned char[]> uBuffer;
+ for (size_t i = t->start; i < t->end && i < slices.size(); i++) {
+ auto e = &slices[i];
+
+ DeflateDecompressor z(e->bs, mRaw, mPredictor, mBps);
+ try {
+ z.decode(&uBuffer, e->width, e->height, e->offX, e->offY);
+ } catch (RawDecoderException& err) {
+ mRaw->setError(err.what());
+ } catch (IOException& err) {
+ mRaw->setError(err.what());
+ }
+ }
+#else
+#pragma message \
+ "ZLIB is not present! Deflate compression will not be supported!"
+ ThrowRDE("deflate support is disabled.");
+#endif
+ /* Lossy DNG */
+ } else if (compression == 0x884c) {
+#ifdef HAVE_JPEG
+ /* Each slice is a JPEG image */
+ for (size_t i = t->start; i < t->end && i < slices.size(); i++) {
+ auto e = &slices[i];
+ JpegDecompressor j(e->bs, mRaw);
+ try {
+ j.decode(e->offX, e->offY);
+ } catch (RawDecoderException& err) {
+ mRaw->setError(err.what());
+ } catch (IOException& err) {
+ mRaw->setError(err.what());
+ }
+ }
+#else
+#pragma message "JPEG is not present! Lossy JPEG DNG will not be supported!"
+ ThrowRDE("jpeg support is disabled.");
+#endif
+ } else
+ mRaw->setError("AbstractDngDecompressor: Unknown compression");
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/AbstractDngDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/AbstractDngDecompressor.h
new file mode 100644
index 000000000..3a48d6eb9
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/AbstractDngDecompressor.h
@@ -0,0 +1,64 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "decompressors/AbstractParallelizedDecompressor.h" // for Abstract...
+#include "io/ByteStream.h" // for ByteStream
+#include <utility> // for move
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class RawImage;
+
+struct DngSliceElement {
+ DngSliceElement(ByteStream bs_, uint32 offsetX, uint32 offsetY, uint32 w,
+ uint32 h)
+ : bs(std::move(bs_)), offX(offsetX), offY(offsetY), width(w), height(h) {}
+
+ const ByteStream bs;
+ const uint32 offX;
+ const uint32 offY;
+ const uint32 width;
+ const uint32 height;
+};
+
+class AbstractDngDecompressor final : public AbstractParallelizedDecompressor {
+ void decompressThreaded(const RawDecompressorThread* t) const final;
+
+public:
+ AbstractDngDecompressor(const RawImage& img, int compression_,
+ bool mFixLjpeg_, uint32 mBps_, uint32 mPredictor_)
+ : AbstractParallelizedDecompressor(img), compression(compression_),
+ mFixLjpeg(mFixLjpeg_), mBps(mBps_), mPredictor(mPredictor_) {}
+
+ void decompress() const final;
+
+ std::vector<DngSliceElement> slices;
+
+ const int compression;
+ const bool mFixLjpeg = false;
+ const uint32 mBps;
+ const uint32 mPredictor;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/AbstractLJpegDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/AbstractLJpegDecompressor.cpp
new file mode 100644
index 000000000..442b6c9a7
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/AbstractLJpegDecompressor.cpp
@@ -0,0 +1,264 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/AbstractLJpegDecompressor.h"
+#include "common/Common.h" // for uint32, make_unique, uchar8
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/ByteStream.h" // for ByteStream
+#include <array> // for array
+#include <memory> // for unique_ptr, allocator
+#include <utility> // for move
+#include <vector> // for vector
+
+namespace rawspeed {
+
+AbstractLJpegDecompressor::AbstractLJpegDecompressor(ByteStream bs,
+ const RawImage& img)
+ : input(std::move(bs)), mRaw(img) {
+ input.setByteOrder(Endianness::big);
+
+ if (mRaw->dim.x == 0 || mRaw->dim.y == 0)
+ ThrowRDE("Image has zero size");
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ // Yeah, sure, here it would be just dumb to leave this for production :)
+ if (mRaw->dim.x > 8896 || mRaw->dim.y > 6304) {
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x,
+ mRaw->dim.y);
+ }
+#endif
+}
+
+void AbstractLJpegDecompressor::decode() {
+ if (getNextMarker(false) != M_SOI)
+ ThrowRDE("Image did not start with SOI. Probably not an LJPEG");
+
+ struct FoundMarkers {
+ bool DHT = false;
+ bool SOF = false;
+ bool SOS = false;
+ } FoundMarkers;
+
+ JpegMarker m;
+ do {
+ m = getNextMarker(true);
+
+ if (m == M_EOI)
+ break;
+
+ ByteStream data(input.getStream(input.peekU16()));
+ data.skipBytes(2); // headerLength
+
+ switch (m) {
+ case M_DHT:
+ if (FoundMarkers.SOS)
+ ThrowRDE("Found second DHT marker after SOS");
+ // there can be more than one DHT markers.
+ // FIXME: do we really want to reparse and use the last one?
+ parseDHT(data);
+ FoundMarkers.DHT = true;
+ break;
+ case M_SOF3:
+ if (FoundMarkers.SOS)
+ ThrowRDE("Found second SOF marker after SOS");
+ if (FoundMarkers.SOF)
+ ThrowRDE("Found second SOF marker");
+ // SOF is not required to be after DHT
+ parseSOF(data, &frame);
+ FoundMarkers.SOF = true;
+ break;
+ case M_SOS:
+ if (FoundMarkers.SOS)
+ ThrowRDE("Found second SOS marker");
+ if (!FoundMarkers.DHT)
+ ThrowRDE("Did not find DHT marker before SOS.");
+ if (!FoundMarkers.SOF)
+ ThrowRDE("Did not find SOF marker before SOS.");
+ parseSOS(data);
+ FoundMarkers.SOS = true;
+ break;
+ case M_DQT:
+ ThrowRDE("Not a valid RAW file.");
+ default: // Just let it skip to next marker
+ break;
+ }
+ } while (m != M_EOI);
+
+ if (!FoundMarkers.SOS)
+ ThrowRDE("Did not find SOS marker.");
+}
+
+void AbstractLJpegDecompressor::parseSOF(ByteStream sofInput, SOFInfo* sof) {
+ sof->prec = sofInput.getByte();
+ sof->h = sofInput.getU16();
+ sof->w = sofInput.getU16();
+ sof->cps = sofInput.getByte();
+
+ if (sof->prec < 2 || sof->prec > 16)
+ ThrowRDE("Invalid precision (%u).", sof->prec);
+
+ if (sof->h == 0 || sof->w == 0)
+ ThrowRDE("Frame width or height set to zero");
+
+ if (sof->cps > 4 || sof->cps < 1)
+ ThrowRDE("Only from 1 to 4 components are supported.");
+
+ if (sof->cps < mRaw->getCpp()) {
+ ThrowRDE("Component count should be no less than sample count (%u vs %u).",
+ sof->cps, mRaw->getCpp());
+ }
+
+ if (sof->cps > static_cast<uint32>(mRaw->dim.x)) {
+ ThrowRDE("Component count should be no greater than row length (%u vs %u).",
+ sof->cps, mRaw->dim.x);
+ }
+
+ if (sofInput.getRemainSize() != 3 * sof->cps)
+ ThrowRDE("Header size mismatch.");
+
+ for (uint32 i = 0; i < sof->cps; i++) {
+ sof->compInfo[i].componentId = sofInput.getByte();
+
+ uint32 subs = sofInput.getByte();
+ frame.compInfo[i].superV = subs & 0xf;
+ frame.compInfo[i].superH = subs >> 4;
+
+ if (frame.compInfo[i].superV < 1 || frame.compInfo[i].superV > 4)
+ ThrowRDE("Horizontal sampling factor is invalid.");
+
+ if (frame.compInfo[i].superH < 1 || frame.compInfo[i].superH > 4)
+ ThrowRDE("Horizontal sampling factor is invalid.");
+
+ uint32 Tq = sofInput.getByte();
+ if (Tq != 0)
+ ThrowRDE("Quantized components not supported.");
+ }
+
+ sof->initialized = true;
+
+ mRaw->metadata.subsampling.x = sof->compInfo[0].superH;
+ mRaw->metadata.subsampling.y = sof->compInfo[0].superV;
+}
+
+void AbstractLJpegDecompressor::parseSOS(ByteStream sos) {
+ assert(frame.initialized);
+
+ if (sos.getRemainSize() != 1 + 2 * frame.cps + 3)
+ ThrowRDE("Invalid SOS header length.");
+
+ uint32 soscps = sos.getByte();
+ if (frame.cps != soscps)
+ ThrowRDE("Component number mismatch.");
+
+ for (uint32 i = 0; i < frame.cps; i++) {
+ uint32 cs = sos.getByte();
+ uint32 td = sos.getByte() >> 4;
+
+ if (td >= huff.size() || !huff[td])
+ ThrowRDE("Invalid Huffman table selection.");
+
+ int ciIndex = -1;
+ for (uint32 j = 0; j < frame.cps; ++j) {
+ if (frame.compInfo[j].componentId == cs)
+ ciIndex = j;
+ }
+
+ if (ciIndex == -1)
+ ThrowRDE("Invalid Component Selector");
+
+ frame.compInfo[ciIndex].dcTblNo = td;
+ }
+
+ // Get predictor, see table H.1 from the JPEG spec
+ predictorMode = sos.getByte();
+ // The spec says predictoreMode is in [0..7], but Hasselblad uses '8'.
+ if (predictorMode > 8)
+ ThrowRDE("Invalid predictor mode.");
+
+ // Se + Ah Not used in LJPEG
+ if (sos.getByte() != 0)
+ ThrowRDE("Se/Ah not zero.");
+
+ Pt = sos.getByte(); // Point Transform
+ if (Pt > 15)
+ ThrowRDE("Invalid Point transform.");
+
+ decodeScan();
+}
+
+void AbstractLJpegDecompressor::parseDHT(ByteStream dht) {
+ while (dht.getRemainSize() > 0) {
+ uint32 b = dht.getByte();
+
+ uint32 htClass = b >> 4;
+ if (htClass != 0)
+ ThrowRDE("Unsupported Table class.");
+
+ uint32 htIndex = b & 0xf;
+ if (htIndex >= huff.size())
+ ThrowRDE("Invalid huffman table destination id.");
+
+ if (huff[htIndex] != nullptr)
+ ThrowRDE("Duplicate table definition");
+
+ // copy 16 bytes from input stream to number of codes per length table
+ uint32 nCodes = ht_.setNCodesPerLength(dht.getBuffer(16));
+
+ // spec says 16 different codes is max but Hasselblad violates that -> 17
+ if (nCodes > 17)
+ ThrowRDE("Invalid DHT table.");
+
+ // copy nCodes bytes from input stream to code values table
+ ht_.setCodeValues(dht.getBuffer(nCodes));
+
+ // see if we already have a HuffmanTable with the same codes
+ for (const auto& i : huffmanTableStore)
+ if (*i == ht_)
+ huff[htIndex] = i.get();
+
+ if (!huff[htIndex]) {
+ // setup new ht_ and put it into the store
+ auto dHT = std::make_unique<HuffmanTable>(ht_);
+ dHT->setup(fullDecodeHT, fixDng16Bug);
+ huff[htIndex] = dHT.get();
+ huffmanTableStore.emplace_back(std::move(dHT));
+ }
+ }
+}
+
+JpegMarker AbstractLJpegDecompressor::getNextMarker(bool allowskip) {
+ uchar8 c0;
+ uchar8 c1 = input.getByte();
+ do {
+ c0 = c1;
+ c1 = input.getByte();
+ } while (allowskip && !(c0 == 0xFF && c1 != 0 && c1 != 0xFF));
+
+ if (!(c0 == 0xFF && c1 != 0 && c1 != 0xFF))
+ ThrowRDE("(Noskip) Expected marker not found. Propably corrupt file.");
+
+ return static_cast<JpegMarker>(c1);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/AbstractLJpegDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/AbstractLJpegDecompressor.h
new file mode 100644
index 000000000..74a7941af
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/AbstractLJpegDecompressor.h
@@ -0,0 +1,202 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, ushort16
+#include "common/RawImage.h" // for RawImage
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/Buffer.h" // for Buffer, Buffer::size_type
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for getHostEndianness, Endiannes...
+#include <array> // for array
+#include <memory> // for unique_ptr
+#include <utility> // for move
+#include <vector> // for vector
+
+/*
+ * The following enum and two structs are stolen from the IJG JPEG library
+ * Comments added by tm. See also Copyright in HuffmanTable.h.
+ */
+
+namespace rawspeed {
+
+enum JpegMarker { /* JPEG marker codes */
+ M_STUFF = 0x00,
+ M_SOF0 = 0xc0, /* baseline DCT */
+ M_SOF1 = 0xc1, /* extended sequential DCT */
+ M_SOF2 = 0xc2, /* progressive DCT */
+ M_SOF3 = 0xc3, /* lossless (sequential) */
+
+ M_SOF5 = 0xc5, /* differential sequential DCT */
+ M_SOF6 = 0xc6, /* differential progressive DCT */
+ M_SOF7 = 0xc7, /* differential lossless */
+
+ M_JPG = 0xc8, /* JPEG extensions */
+ M_SOF9 = 0xc9, /* extended sequential DCT */
+ M_SOF10 = 0xca, /* progressive DCT */
+ M_SOF11 = 0xcb, /* lossless (sequential) */
+
+ M_SOF13 = 0xcd, /* differential sequential DCT */
+ M_SOF14 = 0xce, /* differential progressive DCT */
+ M_SOF15 = 0xcf, /* differential lossless */
+
+ M_DHT = 0xc4, /* define Huffman tables */
+
+ M_DAC = 0xcc, /* define arithmetic conditioning table */
+
+ M_RST0 = 0xd0, /* restart */
+ M_RST1 = 0xd1, /* restart */
+ M_RST2 = 0xd2, /* restart */
+ M_RST3 = 0xd3, /* restart */
+ M_RST4 = 0xd4, /* restart */
+ M_RST5 = 0xd5, /* restart */
+ M_RST6 = 0xd6, /* restart */
+ M_RST7 = 0xd7, /* restart */
+
+ M_SOI = 0xd8, /* start of image */
+ M_EOI = 0xd9, /* end of image */
+ M_SOS = 0xda, /* start of scan */
+ M_DQT = 0xdb, /* define quantization tables */
+ M_DNL = 0xdc, /* define number of lines */
+ M_DRI = 0xdd, /* define restart interval */
+ M_DHP = 0xde, /* define hierarchical progression */
+ M_EXP = 0xdf, /* expand reference image(s) */
+
+ M_APP0 = 0xe0, /* application marker, used for JFIF */
+ M_APP1 = 0xe1, /* application marker */
+ M_APP2 = 0xe2, /* application marker */
+ M_APP3 = 0xe3, /* application marker */
+ M_APP4 = 0xe4, /* application marker */
+ M_APP5 = 0xe5, /* application marker */
+ M_APP6 = 0xe6, /* application marker */
+ M_APP7 = 0xe7, /* application marker */
+ M_APP8 = 0xe8, /* application marker */
+ M_APP9 = 0xe9, /* application marker */
+ M_APP10 = 0xea, /* application marker */
+ M_APP11 = 0xeb, /* application marker */
+ M_APP12 = 0xec, /* application marker */
+ M_APP13 = 0xed, /* application marker */
+ M_APP14 = 0xee, /* application marker, used by Adobe */
+ M_APP15 = 0xef, /* application marker */
+
+ M_JPG0 = 0xf0, /* reserved for JPEG extensions */
+ M_JPG13 = 0xfd, /* reserved for JPEG extensions */
+ M_COM = 0xfe, /* comment */
+
+ M_TEM = 0x01, /* temporary use */
+ M_FILL = 0xFF
+
+
+};
+
+/*
+* The following structure stores basic information about one component.
+*/
+struct JpegComponentInfo {
+ /*
+ * These values are fixed over the whole image.
+ * They are read from the SOF marker.
+ */
+ uint32 componentId = -1; /* identifier for this component (0..255) */
+
+ /*
+ * Huffman table selector (0..3). The value may vary
+ * between scans. It is read from the SOS marker.
+ */
+ uint32 dcTblNo = -1;
+ uint32 superH = -1; // Horizontal Supersampling
+ uint32 superV = -1; // Vertical Supersampling
+};
+
+class SOFInfo {
+public:
+ JpegComponentInfo compInfo[4];
+ uint32 w = 0; // Width
+ uint32 h = 0; // Height
+ uint32 cps = 0; // Components
+ uint32 prec = 0; // Precision
+ bool initialized = false;
+};
+
+class AbstractLJpegDecompressor : public AbstractDecompressor {
+ // std::vector of unique HTs, to not recreate HT, but cache them
+ std::vector<std::unique_ptr<HuffmanTable>> huffmanTableStore;
+ HuffmanTable ht_; // temporary table, used
+
+ uint32 Pt = 0;
+ std::array<HuffmanTable*, 4> huff{{}}; // 4 pointers into the store
+
+public:
+ AbstractLJpegDecompressor(ByteStream bs, const RawImage& img);
+
+ virtual ~AbstractLJpegDecompressor() = default;
+
+protected:
+ bool fixDng16Bug = false; // DNG v1.0.x compatibility
+ bool fullDecodeHT = true; // FullDecode Huffman
+
+ void decode();
+ void parseSOF(ByteStream data, SOFInfo* i);
+ void parseSOS(ByteStream data);
+ void parseDHT(ByteStream data);
+ JpegMarker getNextMarker(bool allowskip);
+
+ template <int N_COMP>
+ std::array<HuffmanTable*, N_COMP> getHuffmanTables() const {
+ std::array<HuffmanTable*, N_COMP> ht;
+ for (int i = 0; i < N_COMP; ++i) {
+ const unsigned dcTblNo = frame.compInfo[i].dcTblNo;
+ const unsigned dcTbls = huff.size();
+ if (dcTblNo >= dcTbls) {
+ ThrowRDE("Decoding table %u for comp %i does not exist (tables = %u)",
+ dcTblNo, i, dcTbls);
+ }
+ ht[i] = huff[dcTblNo];
+ }
+
+ return ht;
+ }
+
+ template <int N_COMP>
+ __attribute__((pure)) std::array<ushort16, N_COMP>
+ getInitialPredictors() const {
+ std::array<ushort16, N_COMP> pred;
+ if (frame.prec < (Pt + 1)) {
+ ThrowRDE("Invalid precision (%u) and point transform (%u) combination!",
+ frame.prec, Pt);
+ }
+ pred.fill(1 << (frame.prec - Pt - 1));
+ return pred;
+ }
+
+ virtual void decodeScan() = 0;
+
+ ByteStream input;
+ RawImage mRaw;
+
+ SOFInfo frame;
+ uint32 predictorMode = 0;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/AbstractParallelizedDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/AbstractParallelizedDecompressor.cpp
new file mode 100644
index 000000000..bcf5ff8fe
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/AbstractParallelizedDecompressor.cpp
@@ -0,0 +1,125 @@
+/*
+ RawSpeed - RAW file Decompressor.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h" // for HAVE_PTHREAD
+#include "decompressors/AbstractParallelizedDecompressor.h"
+#include "common/Point.h" // for iPoint2D
+#include "common/Threading.h" // for sliceUp
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include <cassert> // for assert
+#include <memory> // for allocator_traits<>::value_...
+#include <string> // for string
+#include <vector> // for vector
+
+namespace rawspeed {
+
+void AbstractParallelizedDecompressor::decompressOne(uint32 pieces) const {
+ RawDecompressorThread t(this, 1);
+ t.taskNo = 0;
+ t.start = 0;
+ t.end = pieces;
+
+ RawDecompressorThread::start_routine(&t);
+
+ std::string firstErr;
+ if (mRaw->isTooManyErrors(1, &firstErr)) {
+ ThrowRDE("Too many errors encountered. Giving up. First Error:\n%s",
+ firstErr.c_str());
+ }
+};
+
+#ifdef HAVE_PTHREAD
+void AbstractParallelizedDecompressor::startThreading(uint32 pieces) const {
+ assert(pieces > 0);
+ assert(getThreadCount() > 0);
+ const auto buckets = sliceUp(getThreadCount(), pieces);
+
+ if (buckets.size() == 1)
+ return decompressOne(pieces);
+
+ std::vector<RawDecompressorThread> threads(
+ buckets.size(), RawDecompressorThread(this, buckets.size()));
+
+ /* Initialize and set thread detached attribute */
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ uint32 i = 0;
+ bool fail = false;
+ int offset = 0;
+ for (auto& t : threads) {
+ t.taskNo = i;
+
+ t.start = offset;
+ t.end = t.start + buckets[i];
+
+ assert(t.start < pieces);
+ assert(t.end > 0);
+ assert(t.end > t.start);
+ assert(t.end <= pieces);
+
+#ifndef NDEBUG
+ if (i > 0) {
+ assert(t.start > threads[i - 1].start);
+ assert(t.end > threads[i - 1].end);
+ assert(t.start == threads[i - 1].end);
+ }
+#endif
+
+ if (pthread_create(&t.threadid, &attr, RawDecompressorThread::start_routine,
+ &t) != 0) {
+ // If a failure occurs, we need to wait for the already created threads to
+ // finish
+ fail = true;
+ while (threads.size() > i)
+ threads.pop_back();
+ break;
+ }
+
+ offset = t.end;
+ i++;
+ }
+
+ for (auto& t : threads)
+ pthread_join(t.threadid, nullptr);
+
+ pthread_attr_destroy(&attr);
+
+ if (fail)
+ ThrowRDE("Unable to start threads");
+
+ std::string firstErr;
+ if (mRaw->isTooManyErrors(1, &firstErr)) {
+ ThrowRDE("Too many errors encountered. Giving up. First Error:\n%s",
+ firstErr.c_str());
+ }
+}
+#else
+void AbstractParallelizedDecompressor::startThreading(uint32 pieces) const {
+ decompressOne(pieces);
+}
+#endif
+
+void AbstractParallelizedDecompressor::decompress() const {
+ startThreading(mRaw->dim.y);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/AbstractParallelizedDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/AbstractParallelizedDecompressor.h
new file mode 100644
index 000000000..36fbdffd8
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/AbstractParallelizedDecompressor.h
@@ -0,0 +1,87 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h" // for HAVE_PTHREAD
+#include "common/Common.h" // for uint32, BitOrder
+#include "common/RawImage.h" // for RawImage
+#include "decoders/RawDecoderException.h" // for RawDecoderException
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+#include "io/IOException.h" // for IOException
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h> // for pthread_t
+#endif
+
+namespace rawspeed {
+
+class RawDecompressorThread;
+
+class AbstractParallelizedDecompressor : public AbstractDecompressor {
+ friend class RawDecompressorThread;
+ virtual void decompressThreaded(const RawDecompressorThread* t) const = 0;
+
+ void decompressOne(uint32 pieces) const;
+
+public:
+ explicit AbstractParallelizedDecompressor(const RawImage& img) : mRaw(img) {}
+ virtual ~AbstractParallelizedDecompressor() = default;
+
+ virtual void decompress() const;
+
+protected:
+ RawImage mRaw;
+
+ void startThreading(uint32 pieces) const;
+};
+
+class RawDecompressorThread final {
+ const AbstractParallelizedDecompressor* const parent;
+
+public:
+ RawDecompressorThread(const AbstractParallelizedDecompressor* parent_,
+ uint32 tasksTotal_)
+ : parent(parent_), tasksTotal(tasksTotal_) {}
+
+ static void* start_routine(void* arg) noexcept {
+ const auto* this_ = static_cast<const RawDecompressorThread*>(arg);
+ try {
+ this_->parent->decompressThreaded(this_);
+ } catch (RawDecoderException& err) {
+ this_->parent->mRaw->setError(err.what());
+ } catch (IOException& err) {
+ this_->parent->mRaw->setError(err.what());
+ }
+ return nullptr;
+ }
+
+ uint32 taskNo = -1;
+ const uint32 tasksTotal;
+
+ uint32 start = 0;
+ uint32 end = 0;
+
+#ifdef HAVE_PTHREAD
+ pthread_t threadid;
+#endif
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/AbstractSamsungDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/AbstractSamsungDecompressor.h
new file mode 100644
index 000000000..653e1be56
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/AbstractSamsungDecompressor.h
@@ -0,0 +1,36 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+
+namespace rawspeed {
+
+class AbstractSamsungDecompressor : public AbstractDecompressor {
+protected:
+ RawImage mRaw;
+
+public:
+ explicit AbstractSamsungDecompressor(const RawImage& raw) : mRaw(raw) {}
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/CMakeLists.txt b/src/external/rawspeed/src/librawspeed/decompressors/CMakeLists.txt
new file mode 100644
index 000000000..48b12413a
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/CMakeLists.txt
@@ -0,0 +1,51 @@
+FILE(GLOB SOURCES
+ "AbstractDecompressor.h"
+ "AbstractDngDecompressor.cpp"
+ "AbstractDngDecompressor.h"
+ "AbstractLJpegDecompressor.cpp"
+ "AbstractLJpegDecompressor.h"
+ "AbstractParallelizedDecompressor.cpp"
+ "AbstractParallelizedDecompressor.h"
+ "AbstractSamsungDecompressor.h"
+ "Cr2Decompressor.cpp"
+ "Cr2Decompressor.h"
+ "CrwDecompressor.cpp"
+ "CrwDecompressor.h"
+ "DeflateDecompressor.cpp"
+ "DeflateDecompressor.h"
+ "FujiDecompressor.cpp"
+ "FujiDecompressor.h"
+ "HasselbladDecompressor.cpp"
+ "HasselbladDecompressor.h"
+ "HuffmanTable.h"
+ "JpegDecompressor.cpp"
+ "JpegDecompressor.h"
+ "KodakDecompressor.cpp"
+ "KodakDecompressor.h"
+ "LJpegDecompressor.cpp"
+ "LJpegDecompressor.h"
+ "NikonDecompressor.cpp"
+ "NikonDecompressor.h"
+ "OlympusDecompressor.cpp"
+ "OlympusDecompressor.h"
+ "PanasonicDecompressor.cpp"
+ "PanasonicDecompressor.h"
+ "PentaxDecompressor.cpp"
+ "PentaxDecompressor.h"
+ "SamsungV0Decompressor.cpp"
+ "SamsungV0Decompressor.h"
+ "SamsungV1Decompressor.cpp"
+ "SamsungV1Decompressor.h"
+ "SamsungV2Decompressor.cpp"
+ "SamsungV2Decompressor.h"
+ "SonyArw1Decompressor.cpp"
+ "SonyArw1Decompressor.h"
+ "SonyArw2Decompressor.cpp"
+ "SonyArw2Decompressor.h"
+ "UncompressedDecompressor.cpp"
+ "UncompressedDecompressor.h"
+)
+
+target_sources(rawspeed PRIVATE
+ ${SOURCES}
+)
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/Cr2Decompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/Cr2Decompressor.cpp
new file mode 100644
index 000000000..ee58cc398
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/Cr2Decompressor.cpp
@@ -0,0 +1,225 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/Cr2Decompressor.h"
+#include "common/Common.h" // for uint32, unroll_loop, ushort16
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "io/BitPumpJPEG.h" // for BitPumpJPEG
+#include <algorithm> // for move, copy_n
+#include <cassert> // for assert
+#include <numeric> // for accumulate
+
+using std::copy_n;
+
+namespace rawspeed {
+
+Cr2Decompressor::Cr2Decompressor(const ByteStream& bs, const RawImage& img)
+ : AbstractLJpegDecompressor(bs, img) {
+ if (mRaw->getDataType() != TYPE_USHORT16)
+ ThrowRDE("Unexpected data type");
+
+ if (!((mRaw->getCpp() == 1 && mRaw->getBpp() == 2) ||
+ (mRaw->getCpp() == 3 && mRaw->getBpp() == 6)))
+ ThrowRDE("Unexpected cpp: %u", mRaw->getCpp());
+
+ if (!mRaw->dim.x || !mRaw->dim.y || mRaw->dim.x > 8896 ||
+ mRaw->dim.y > 5920) {
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x,
+ mRaw->dim.y);
+ }
+}
+
+void Cr2Decompressor::decodeScan()
+{
+ if (predictorMode != 1)
+ ThrowRDE("Unsupported predictor mode.");
+
+ if (slicesWidths.empty()) {
+ const int slicesWidth = frame.w * frame.cps;
+ if (slicesWidth > mRaw->dim.x)
+ ThrowRDE("Don't know slicing pattern, and failed to guess it.");
+
+ slicesWidths.push_back(slicesWidth);
+ }
+
+ bool isSubSampled = false;
+ for (uint32 i = 0; i < frame.cps; i++)
+ isSubSampled = isSubSampled || frame.compInfo[i].superH != 1 ||
+ frame.compInfo[i].superV != 1;
+
+ if (isSubSampled) {
+ if (mRaw->isCFA)
+ ThrowRDE("Cannot decode subsampled image to CFA data");
+
+ if (mRaw->getCpp() != frame.cps)
+ ThrowRDE("Subsampled component count does not match image.");
+
+ if (frame.cps != 3)
+ ThrowRDE("Unsupported number of subsampled components: %u", frame.cps);
+
+ // see http://lclevy.free.fr/cr2/#sraw for overview table
+ bool isSupported = frame.compInfo[0].superH == 2;
+
+ isSupported = isSupported && (frame.compInfo[0].superV == 1 ||
+ frame.compInfo[0].superV == 2);
+
+ for (uint32 i = 1; i < frame.cps; i++)
+ isSupported = isSupported && frame.compInfo[i].superH == 1 &&
+ frame.compInfo[i].superV == 1;
+
+ if (!isSupported) {
+ ThrowRDE("Unsupported subsampling ([[%u, %u], [%u, %u], [%u, %u]])",
+ frame.compInfo[0].superH, frame.compInfo[0].superV,
+ frame.compInfo[1].superH, frame.compInfo[1].superV,
+ frame.compInfo[2].superH, frame.compInfo[2].superV);
+ }
+
+ if (frame.compInfo[0].superV == 2)
+ decodeN_X_Y<3, 2, 2>(); // Cr2 sRaw1/mRaw
+ else {
+ assert(frame.compInfo[0].superV == 1);
+ decodeN_X_Y<3, 2, 1>(); // Cr2 sRaw2/sRaw
+ }
+ } else {
+ switch (frame.cps) {
+ case 2:
+ decodeN_X_Y<2, 1, 1>();
+ break;
+ case 4:
+ decodeN_X_Y<4, 1, 1>();
+ break;
+ default:
+ ThrowRDE("Unsupported number of components: %u", frame.cps);
+ }
+ }
+}
+
+void Cr2Decompressor::decode(std::vector<int> slicesWidths_)
+{
+ slicesWidths = move(slicesWidths_);
+ AbstractLJpegDecompressor::decode();
+}
+
+// N_COMP == number of components (2, 3 or 4)
+// X_S_F == x/horizontal sampling factor (1 or 2)
+// Y_S_F == y/vertical sampling factor (1 or 2)
+
+template <int N_COMP, int X_S_F, int Y_S_F>
+void Cr2Decompressor::decodeN_X_Y()
+{
+ auto ht = getHuffmanTables<N_COMP>();
+ auto pred = getInitialPredictors<N_COMP>();
+ auto predNext = reinterpret_cast<ushort16*>(mRaw->getDataUncropped(0, 0));
+
+ BitPumpJPEG bitStream(input);
+
+ uint32 pixelPitch = mRaw->pitch / 2; // Pitch in pixel
+ if (frame.cps != 3 && frame.w * frame.cps > 2 * frame.h) {
+ // Fix Canon double height issue where Canon doubled the width and halfed
+ // the height (e.g. with 5Ds), ask Canon. frame.w needs to stay as is here
+ // because the number of pixels after which the predictor gets updated is
+ // still the doubled width.
+ // see: FIX_CANON_HALF_HEIGHT_DOUBLE_WIDTH
+ frame.h *= 2;
+ }
+
+ if (X_S_F == 2 && Y_S_F == 1)
+ {
+ // fix the inconsistent slice width in sRaw mode, ask Canon.
+ for (auto& sliceWidth : slicesWidths)
+ sliceWidth = sliceWidth * 3 / 2;
+ }
+
+ for (const auto& slicesWidth : slicesWidths) {
+ if (slicesWidth > mRaw->dim.x)
+ ThrowRDE("Slice is longer than image's height, which is unsupported.");
+ }
+
+ if (frame.h * std::accumulate(slicesWidths.begin(), slicesWidths.end(), 0) <
+ mRaw->dim.area())
+ ThrowRDE("Incorrrect slice height / slice widths! Less than image size.");
+
+ // To understand the CR2 slice handling and sampling factor behavior, see
+ // https://github.com/lclevy/libcraw2/blob/master/docs/cr2_lossless.pdf?raw=true
+
+ // inner loop decodes one group of pixels at a time
+ // * for <N,1,1>: N = N*1*1 (full raw)
+ // * for <3,2,1>: 6 = 3*2*1
+ // * for <3,2,2>: 12 = 3*2*2
+ // and advances x by N_COMP*X_S_F and y by Y_S_F
+ constexpr int xStepSize = N_COMP * X_S_F;
+ constexpr int yStepSize = Y_S_F;
+
+ unsigned processedPixels = 0;
+ unsigned processedLineSlices = 0;
+ for (unsigned sliceWidth : slicesWidths) {
+ for (unsigned y = 0; y < frame.h; y += yStepSize) {
+ // Fix for Canon 80D mraw format.
+ // In that format, `frame` is 4032x3402, while `mRaw` is 4536x3024.
+ // Consequently, the slices in `frame` wrap around plus there are few
+ // 'extra' sliced lines because sum(slicesW) * sliceH > mRaw->dim.area()
+ // Those would overflow, hence the break.
+ // see FIX_CANON_FRAME_VS_IMAGE_SIZE_MISMATCH
+ unsigned destY = processedLineSlices % mRaw->dim.y;
+ unsigned destX =
+ processedLineSlices / mRaw->dim.y * slicesWidths[0] / mRaw->getCpp();
+ if (destX >= static_cast<unsigned>(mRaw->dim.x))
+ break;
+ auto dest =
+ reinterpret_cast<ushort16*>(mRaw->getDataUncropped(destX, destY));
+
+ for (unsigned x = 0; x < sliceWidth; x += xStepSize) {
+ // check if we processed one full raw row worth of pixels
+ if (processedPixels == frame.w) {
+ // if yes -> update predictor by going back exactly one row,
+ // no matter where we are right now.
+ // makes no sense from an image compression point of view, ask Canon.
+ copy_n(predNext, N_COMP, pred.data());
+ predNext = dest;
+ processedPixels = 0;
+ }
+
+ if (X_S_F == 1) { // will be optimized out
+ unroll_loop<N_COMP>([&](int i) {
+ dest[i] = pred[i] += ht[i]->decodeNext(bitStream);
+ });
+ } else {
+ unroll_loop<Y_S_F>([&](int i) {
+ dest[0 + i*pixelPitch] = pred[0] += ht[0]->decodeNext(bitStream);
+ dest[3 + i*pixelPitch] = pred[0] += ht[0]->decodeNext(bitStream);
+ });
+
+ dest[1] = pred[1] += ht[1]->decodeNext(bitStream);
+ dest[2] = pred[2] += ht[2]->decodeNext(bitStream);
+ }
+
+ dest += xStepSize;
+ processedPixels += X_S_F;
+ }
+
+ processedLineSlices += yStepSize;
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/Cr2Decompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/Cr2Decompressor.h
new file mode 100644
index 000000000..07718ecf4
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/Cr2Decompressor.h
@@ -0,0 +1,47 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "decompressors/AbstractLJpegDecompressor.h" // for AbstractLJpegDe...
+#include "io/Buffer.h" // for Buffer, Buffer:...
+#include "io/ByteStream.h" // for ByteStream
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class RawImage;
+
+// Decompresses Lossless JPEGs, with 2-4 components and optional X/Y subsampling
+
+class Cr2Decompressor final : public AbstractLJpegDecompressor
+{
+ // CR2 slices
+ std::vector<int> slicesWidths;
+
+ void decodeScan() override;
+ template<int N_COMP, int X_S_F, int Y_S_F> void decodeN_X_Y();
+
+public:
+ Cr2Decompressor(const ByteStream& bs, const RawImage& img);
+ void decode(std::vector<int> slicesWidths);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/CrwDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/CrwDecompressor.cpp
new file mode 100644
index 000000000..7eaf8a6d7
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/CrwDecompressor.cpp
@@ -0,0 +1,330 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2015-2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/CrwDecompressor.h"
+#include "common/Common.h" // for uint32, ushort16, uchar8
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decoders/RawDecoderException.h" // for RawDecoderException (ptr o...
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/BitPumpJPEG.h" // for BitPumpJPEG, BitStream<>::...
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include <algorithm> // for min
+#include <array> // for array
+#include <memory> // for make_unique
+
+using std::array;
+
+namespace rawspeed {
+
+CrwDecompressor::CrwDecompressor(const RawImage& img, uint32 dec_table,
+ bool lowbits_, const Buffer* file)
+ : mRaw(img), lowbits(lowbits_), mFile(*file) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ const uint32 width = mRaw->dim.x;
+ const uint32 height = mRaw->dim.y;
+
+ if (width == 0 || height == 0 || width % 4 != 0 || width > 4104 ||
+ height > 3048 || (height * width) % 64 != 0)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ mHuff = initHuffTables(dec_table);
+}
+
+HuffmanTable CrwDecompressor::makeDecoder(const uchar8* ncpl,
+ const uchar8* values) {
+ assert(ncpl);
+
+ HuffmanTable ht;
+ auto count = ht.setNCodesPerLength(Buffer(ncpl, 16));
+ ht.setCodeValues(Buffer(values, count));
+ ht.setup(false, false);
+
+ return ht;
+}
+
+CrwDecompressor::crw_hts CrwDecompressor::initHuffTables(uint32 table) {
+ if (table > 2)
+ ThrowRDE("Wrong table number: %u", table);
+
+ // NCodesPerLength
+ static const uchar8 first_tree_ncpl[3][16] = {
+ {0, 1, 4, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 2, 2, 3, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 6, 3, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ };
+
+ static const uchar8 first_tree_len[3][13] = {
+ {0x4, 0x3, 0x5, 0x6, 0x2, 0x7, 0x1, 0x8, 0x9, 0x0, 0xa, 0xb, 0xf},
+ {0x3, 0x2, 0x4, 0x1, 0x5, 0x0, 0x6, 0x7, 0x9, 0x8, 0xa, 0xb, 0xf},
+ {0x6, 0x5, 0x7, 0x4, 0x8, 0x3, 0x9, 0x2, 0x0, 0xa, 0x1, 0xb, 0xf},
+ };
+
+ static const uchar8 first_tree_index[3][13] = {
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf},
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf},
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf},
+ };
+
+ // NCodesPerLength
+ static const uchar8 second_tree_ncpl[3][16] = {
+ {0, 2, 2, 2, 1, 4, 2, 1, 2, 5, 1, 1, 0, 0, 0, 139},
+ {0, 2, 2, 1, 4, 1, 4, 1, 3, 3, 1, 0, 0, 0, 0, 140},
+ {0, 0, 6, 2, 1, 3, 3, 2, 5, 1, 2, 2, 8, 10, 0, 117},
+ };
+
+ static const uchar8 second_tree_len[3][164] = {
+ {0x3, 0x4, 0x2, 0x5, 0x1, 0x6, 0x7, 0x8, 0x2, 0x3, 0x1, 0x4, 0x9, 0x5,
+ 0x2, 0x0, 0x1, 0x6, 0xa, 0x0, 0x3, 0x7, 0x4, 0x1, 0x2, 0x8, 0x9, 0x3,
+ 0x5, 0x1, 0x4, 0x2, 0x5, 0x1, 0x6, 0x7, 0x8, 0x9, 0x9, 0x6, 0xa, 0x9,
+ 0x6, 0x7, 0x8, 0x7, 0x2, 0x5, 0x8, 0x3, 0x6, 0x9, 0x7, 0x4, 0x1, 0x9,
+ 0x1, 0x8, 0x5, 0x6, 0x7, 0x9, 0x7, 0x3, 0x7, 0x4, 0x6, 0x8, 0x7, 0x8,
+ 0x5, 0x9, 0x9, 0x1, 0xa, 0x8, 0x8, 0x5, 0x9, 0x6, 0x7, 0x8, 0x7, 0x6,
+ 0x5, 0x4, 0x9, 0x8, 0x1, 0x5, 0x6, 0x4, 0x8, 0x1, 0xa, 0x4, 0x2, 0x9,
+ 0x7, 0x6, 0x4, 0x5, 0xa, 0x7, 0x3, 0x9, 0x8, 0x6, 0x2, 0x7, 0x5, 0x8,
+ 0x9, 0x1, 0x4, 0x1, 0x9, 0xa, 0x2, 0x5, 0x6, 0x7, 0x3, 0x8, 0x1, 0x6,
+ 0xa, 0x4, 0x1, 0xa, 0xa, 0x6, 0x3, 0x1, 0x3, 0x5, 0xa, 0x2, 0xa, 0xa,
+ 0x4, 0x4, 0x3, 0x5, 0x5, 0x3, 0x2, 0x4, 0x2, 0xa, 0xa, 0x4, 0x2, 0xa,
+ 0x3, 0x3, 0x2, 0x3, 0xa, 0x2, 0x2, 0x3, 0xf, 0xf},
+ {0x2, 0x3, 0x1, 0x4, 0x5, 0x2, 0x1, 0x6, 0x3, 0x7, 0x8, 0x4, 0x2, 0x9,
+ 0x1, 0x0, 0x3, 0x5, 0x1, 0x2, 0xa, 0x6, 0x0, 0x4, 0x3, 0x1, 0x2, 0x9,
+ 0x7, 0x5, 0x8, 0x1, 0x4, 0x3, 0x2, 0x9, 0x5, 0x1, 0x9, 0x1, 0x2, 0x6,
+ 0x3, 0x6, 0x8, 0xa, 0x7, 0x1, 0x7, 0x1, 0x9, 0x5, 0x5, 0x8, 0x2, 0x9,
+ 0x1, 0x1, 0x4, 0x9, 0x4, 0x8, 0x1, 0xa, 0x7, 0x1, 0x1, 0x9, 0x9, 0x7,
+ 0x3, 0xa, 0x9, 0x6, 0x6, 0x8, 0xa, 0xa, 0x8, 0x9, 0xa, 0x5, 0x4, 0x6,
+ 0x5, 0x1, 0x6, 0x6, 0x6, 0x6, 0x9, 0x5, 0x9, 0x5, 0x5, 0x4, 0x7, 0x7,
+ 0xa, 0x7, 0x8, 0x3, 0x7, 0x8, 0x9, 0x7, 0x7, 0xa, 0x8, 0x2, 0x4, 0xa,
+ 0x4, 0x6, 0x5, 0xa, 0x4, 0x4, 0x6, 0x2, 0x3, 0x8, 0x5, 0x8, 0x4, 0x5,
+ 0x6, 0x9, 0x2, 0x3, 0x3, 0x2, 0x6, 0x7, 0x3, 0xa, 0x4, 0x5, 0x7, 0x8,
+ 0x8, 0xa, 0x7, 0x7, 0x4, 0x4, 0x2, 0x8, 0x5, 0xa, 0xa, 0x8, 0x3, 0x6,
+ 0x9, 0x2, 0x3, 0x2, 0x2, 0x3, 0xa, 0x3, 0xf, 0xf},
+ {0x4, 0x5, 0x3, 0x6, 0x2, 0x7, 0x1, 0x8, 0x9, 0x2, 0x3, 0x4, 0x1, 0x5,
+ 0xa, 0x6, 0x7, 0x0, 0x0, 0x2, 0x1, 0x8, 0x3, 0x9, 0x4, 0x2, 0x1, 0x5,
+ 0x3, 0x8, 0x7, 0x4, 0x5, 0x6, 0x9, 0x9, 0x7, 0x8, 0x9, 0x8, 0x6, 0x8,
+ 0x7, 0x1, 0x9, 0x7, 0x6, 0x2, 0x6, 0x9, 0xa, 0x5, 0x8, 0x7, 0x9, 0x8,
+ 0x4, 0x6, 0x9, 0x7, 0x7, 0x9, 0xa, 0x5, 0x8, 0x6, 0x7, 0x9, 0x9, 0x8,
+ 0x8, 0x2, 0x7, 0x8, 0x5, 0x4, 0x1, 0x6, 0x9, 0x8, 0xa, 0x6, 0x7, 0x5,
+ 0xa, 0x5, 0x5, 0x6, 0x6, 0x4, 0x9, 0x4, 0x3, 0xa, 0x8, 0x3, 0x5, 0x7,
+ 0x4, 0x6, 0x7, 0xa, 0x4, 0xa, 0x9, 0x8, 0x8, 0x7, 0xa, 0xa, 0x3, 0xa,
+ 0x1, 0x7, 0x4, 0x6, 0x5, 0x9, 0x2, 0x6, 0x1, 0x1, 0x3, 0x6, 0xa, 0x2,
+ 0x5, 0x2, 0x3, 0x5, 0x2, 0x4, 0x4, 0xa, 0x4, 0x5, 0x3, 0x2, 0x1, 0x5,
+ 0x3, 0xa, 0x4, 0xa, 0x2, 0x1, 0x4, 0x1, 0x3, 0x3, 0xa, 0x3, 0x2, 0x2,
+ 0x1, 0x3, 0x2, 0x1, 0x1, 0x3, 0x2, 0x1, 0xf, 0xf},
+ };
+
+ static const uchar8 second_tree_index[3][164] = {
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x1,
+ 0x2, 0x0, 0x2, 0x1, 0x0, 0xf, 0x2, 0x1, 0x2, 0x3, 0x3, 0x1, 0x1, 0x3,
+ 0x2, 0x4, 0x3, 0x4, 0x3, 0x5, 0x3, 0x3, 0x3, 0x2, 0x7, 0x2, 0x1, 0x3,
+ 0x5, 0x5, 0x2, 0x2, 0x5, 0x5, 0x5, 0x4, 0x7, 0x5, 0x7, 0x5, 0x6, 0xf,
+ 0x7, 0x7, 0x7, 0x9, 0x9, 0x4, 0xb, 0x5, 0xd, 0x7, 0xb, 0x9, 0x4, 0x4,
+ 0x9, 0x6, 0x9, 0x9, 0xf, 0xb, 0x6, 0xb, 0xb, 0xd, 0xf, 0xd, 0x6, 0x4,
+ 0x4, 0x9, 0x8, 0xf, 0x8, 0xd, 0xf, 0xb, 0x8, 0xb, 0x2, 0x4, 0x7, 0xd,
+ 0x8, 0x6, 0xd, 0xf, 0x3, 0xa, 0x7, 0xa, 0xa, 0x8, 0x6, 0xc, 0x6, 0xc,
+ 0xc, 0xa, 0xf, 0xd, 0xe, 0x5, 0x9, 0x8, 0xa, 0xe, 0x9, 0xe, 0xc, 0xc,
+ 0x7, 0x6, 0xe, 0x4, 0x6, 0xe, 0xb, 0xf, 0xd, 0xa, 0x8, 0xb, 0x9, 0xb,
+ 0x8, 0xa, 0x6, 0xe, 0xc, 0xf, 0xd, 0xc, 0x8, 0xa, 0xd, 0xe, 0xf, 0xc,
+ 0x8, 0xa, 0xa, 0xc, 0xe, 0xc, 0xe, 0xe, 0xf, 0xf},
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x0, 0x1, 0x0, 0x0, 0x1, 0x2, 0x0,
+ 0x2, 0x0, 0x2, 0x1, 0x3, 0x3, 0x0, 0x1, 0xf, 0x2, 0x3, 0x4, 0x4, 0x1,
+ 0x1, 0x2, 0x1, 0x5, 0x3, 0x4, 0x5, 0x2, 0x3, 0x6, 0x3, 0x7, 0x6, 0x3,
+ 0x5, 0x2, 0x3, 0x1, 0x3, 0x8, 0x2, 0x9, 0x7, 0x5, 0x4, 0x2, 0x7, 0x5,
+ 0xa, 0xb, 0x4, 0x6, 0x5, 0x5, 0xd, 0xf, 0x5, 0xe, 0xf, 0xb, 0x4, 0x4,
+ 0x6, 0x6, 0xf, 0x5, 0x4, 0xa, 0x2, 0x4, 0x7, 0x9, 0x3, 0x7, 0x7, 0x8,
+ 0x6, 0xc, 0x7, 0xb, 0x9, 0xd, 0x8, 0x8, 0xc, 0xf, 0x9, 0xb, 0xc, 0xf,
+ 0x8, 0x9, 0xb, 0x7, 0xb, 0xd, 0xd, 0x8, 0xa, 0x7, 0x4, 0x8, 0x8, 0xe,
+ 0xf, 0xa, 0xc, 0x5, 0x9, 0xa, 0xc, 0x9, 0xc, 0x6, 0xb, 0xc, 0xe, 0xe,
+ 0xe, 0xe, 0xa, 0xa, 0xe, 0xc, 0x6, 0x6, 0x9, 0xa, 0xd, 0xd, 0xe, 0xf,
+ 0x8, 0x9, 0xd, 0x7, 0xc, 0x6, 0xe, 0x9, 0xa, 0xc, 0xd, 0xe, 0xf, 0xf,
+ 0xa, 0xb, 0xb, 0xf, 0xd, 0x8, 0xb, 0xd, 0xf, 0xf},
+ {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1,
+ 0x0, 0x1, 0x1, 0xf, 0x0, 0x2, 0x2, 0x1, 0x2, 0x1, 0x2, 0x3, 0x3, 0x2,
+ 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x7, 0x5, 0x5, 0x5, 0x2, 0x5, 0x7,
+ 0x2, 0x4, 0x2, 0x7, 0x2, 0x4, 0x7, 0x9, 0x1, 0x5, 0x9, 0x9, 0xf, 0x4,
+ 0x5, 0x9, 0x8, 0x4, 0xb, 0x4, 0xf, 0x7, 0x6, 0xb, 0x6, 0x6, 0xb, 0xb,
+ 0xd, 0x5, 0xd, 0x8, 0xb, 0x7, 0x5, 0x4, 0xd, 0xf, 0x3, 0xd, 0x8, 0x4,
+ 0x7, 0x9, 0xd, 0xf, 0x8, 0xb, 0xa, 0x9, 0x5, 0x2, 0xa, 0x4, 0xf, 0xf,
+ 0xd, 0x6, 0xa, 0x5, 0x4, 0x8, 0xc, 0xe, 0xc, 0xe, 0x9, 0x6, 0x7, 0x4,
+ 0x6, 0xc, 0xf, 0xc, 0x6, 0xe, 0x7, 0xe, 0x7, 0x9, 0x9, 0xa, 0xd, 0x9,
+ 0x8, 0x6, 0xf, 0xc, 0xb, 0xa, 0x8, 0xb, 0x6, 0xa, 0xb, 0xd, 0x8, 0xe,
+ 0xd, 0xa, 0xc, 0xc, 0xf, 0xb, 0xe, 0xd, 0x8, 0x6, 0xe, 0xc, 0xe, 0x8,
+ 0xf, 0xa, 0xc, 0xa, 0xc, 0xe, 0xa, 0xe, 0xf, 0xf},
+ };
+
+ array<array<HuffmanTable, 2>, 2> mHuff = {{
+ {{makeDecoder(first_tree_ncpl[table], first_tree_len[table]),
+ makeDecoder(first_tree_ncpl[table], first_tree_index[table])}},
+ {{makeDecoder(second_tree_ncpl[table], second_tree_len[table]),
+ makeDecoder(second_tree_ncpl[table], second_tree_index[table])}},
+ }};
+
+ return mHuff;
+}
+
+// FIXME: this function is horrible.
+inline void CrwDecompressor::decodeBlock(std::array<int, 64>* diffBuf,
+ const crw_hts& mHuff,
+ BitPumpJPEG* lPump,
+ BitPumpJPEG* iPump) {
+ assert(diffBuf);
+ assert(lPump);
+
+ // decode the block
+ for (int i = 0; i < 64; i++) {
+ const int len = mHuff[i > 0][0].decodeLength(*lPump);
+ const int index = mHuff[i > 0][1].decodeLength(*iPump);
+ assert(len >= 0 && index >= 0);
+
+ if (len == 0 && index == 0 && i)
+ break;
+
+ if (len == 0xf && index == 0xf)
+ continue;
+
+ i += index;
+
+ if (len == 0)
+ continue;
+
+ int diff = lPump->getBits(len);
+ iPump->skipBits(len);
+
+ if (i >= 64)
+ break;
+
+ diff = HuffmanTable::signExtended(diff, len);
+
+ (*diffBuf)[i] = diff;
+ }
+}
+
+// FIXME: this function is horrible.
+void CrwDecompressor::decompress() const {
+ const uint32 height = mRaw->dim.y;
+ const uint32 width = mRaw->dim.x;
+
+ {
+ assert(width > 0);
+ assert(width % 4 == 0);
+ assert(height > 0);
+
+ uint32 offset = 540;
+ if (lowbits)
+ offset += height * width / 4;
+
+ // Each block encodes 64 pixels
+ assert((height * width) % 64 == 0);
+ const unsigned hBlocks = height * width / 64;
+ assert(hBlocks > 0);
+
+ ByteStream input(mFile, offset);
+ // FIXME: fix this to not require two pumps
+ BitPumpJPEG lPump(input);
+ BitPumpJPEG iPump(input);
+
+ int carry = 0;
+ int base[2];
+
+ uint32 j = 0;
+ ushort16* dest = nullptr;
+ uint32 i = 0;
+
+ for (unsigned block = 0; block < hBlocks; block++) {
+ array<int, 64> diffBuf = {{}};
+ decodeBlock(&diffBuf, mHuff, &lPump, &iPump);
+
+ // predict and output the block
+
+ diffBuf[0] += carry;
+ carry = diffBuf[0];
+
+ for (uint32 k = 0; k < 64; k++) {
+ if (i % width == 0) {
+ // new line. sadly, does not always happen when k == 0.
+ i = 0;
+
+ dest = reinterpret_cast<ushort16*>(mRaw->getData(0, j));
+
+ j++;
+ base[0] = base[1] = 512;
+ }
+
+ assert(dest != nullptr);
+ base[k & 1] += diffBuf[k];
+
+ if (base[k & 1] >> 10)
+ ThrowRDE("Error decompressing");
+
+ *dest = base[k & 1];
+
+ i++;
+ dest++;
+ }
+ }
+ assert(j == height);
+ assert(i == width);
+ }
+
+ // Add the uncompressed 2 low bits to the decoded 8 high bits
+ if (lowbits) {
+ uint32 offset = 26;
+
+ assert(width > 0);
+ assert(width % 4 == 0);
+ assert(height > 0);
+
+ // Each block is 4 pairs of 2 bits, so we have 1 block per 4 pixels
+ const unsigned lBlocks = 1 * height * width / 4;
+ assert(lBlocks > 0);
+
+ ByteStream lowbitInput(mFile, offset, lBlocks);
+
+ for (uint32 j = 0; j < height; j++) {
+ auto* dest = reinterpret_cast<ushort16*>(mRaw->getData(0, j));
+
+ assert(width % 4 == 0);
+ for (uint32 i = 0; i < width; /* NOTE: i += 4 */) {
+ const uchar8 c = lowbitInput.getByte();
+ // LSB-packed: p3 << 6 | p2 << 4 | p1 << 2 | p0 << 0
+
+ // We have read 8 bits, which is 4 pairs of 2 bits. So process 4 pixels.
+ for (uint32 p = 0; p < 4; p++) {
+ ushort16 low = (c >> (2 * p)) & 0b11;
+ ushort16 val = (*dest << 2) | low;
+
+ if (width == 2672 && val < 512)
+ val += 2; // No idea why this is needed
+
+ *dest = val;
+ i++;
+ dest++;
+ }
+ }
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/CrwDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/CrwDecompressor.h
new file mode 100644
index 000000000..5d38b4b90
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/CrwDecompressor.h
@@ -0,0 +1,59 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, uchar8
+#include "common/RawImage.h" // for RawImage
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/BitPumpJPEG.h" // for BitPumpJPEG
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include <array> // for array
+#include <memory> // for unique_ptr
+
+namespace rawspeed {
+
+class CrwDecompressor final : public AbstractDecompressor {
+ using crw_hts = std::array<std::array<HuffmanTable, 2>, 2>;
+
+ RawImage mRaw;
+ crw_hts mHuff;
+ const bool lowbits;
+ const Buffer mFile;
+
+public:
+ CrwDecompressor(const RawImage& img, uint32 dec_table_, bool lowbits_,
+ const Buffer* file);
+
+ void decompress() const;
+
+private:
+ static HuffmanTable makeDecoder(const uchar8* ncpl, const uchar8* values);
+ static crw_hts initHuffTables(uint32 table);
+
+ inline static void decodeBlock(std::array<int, 64>* diffBuf,
+ const crw_hts& mHuff, BitPumpJPEG* lPump,
+ BitPumpJPEG* iPump);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/DeflateDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/DeflateDecompressor.cpp
new file mode 100644
index 000000000..ba4c10695
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/DeflateDecompressor.cpp
@@ -0,0 +1,260 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Vasily Khoruzhick
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h"
+
+#ifdef HAVE_ZLIB
+
+#include "decompressors/DeflateDecompressor.h"
+#include "common/Common.h" // for uint32, ushort16
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "io/Endianness.h" // for getHostEndianness, Endiann...
+#include <cassert> // for assert
+#include <cstdio> // for size_t
+#include <zlib.h>
+
+namespace rawspeed {
+
+// decodeFPDeltaRow(): MIT License, copyright 2014 Javier Celaya
+// <jcelaya@gmail.com>
+static inline void decodeFPDeltaRow(unsigned char* src, unsigned char* dst,
+ size_t tileWidth, size_t realTileWidth,
+ unsigned int bytesps, int factor) {
+ // DecodeDeltaBytes
+ for (size_t col = factor; col < realTileWidth * bytesps; ++col) {
+ src[col] += src[col - factor];
+ }
+ // Reorder bytes into the image
+ // 16 and 32-bit versions depend on local architecture, 24-bit does not
+ if (bytesps == 3) {
+ for (size_t col = 0; col < tileWidth; ++col) {
+ dst[col * 3] = src[col];
+ dst[col * 3 + 1] = src[col + realTileWidth];
+ dst[col * 3 + 2] = src[col + realTileWidth * 2];
+ }
+ } else {
+ if (getHostEndianness() == Endianness::little) {
+ for (size_t col = 0; col < tileWidth; ++col) {
+ for (size_t byte = 0; byte < bytesps; ++byte)
+ dst[col * bytesps + byte] =
+ src[col + realTileWidth * (bytesps - byte - 1)];
+ }
+ } else {
+ for (size_t col = 0; col < tileWidth; ++col) {
+ for (size_t byte = 0; byte < bytesps; ++byte)
+ dst[col * bytesps + byte] = src[col + realTileWidth * byte];
+ }
+ }
+ }
+}
+
+static inline uint32 __attribute__((const)) fp16ToFloat(ushort16 fp16) {
+ // IEEE-754-2008: binary16:
+ // bit 15 - sign
+ // bits 14-10 - exponent (5 bit)
+ // bits 9-0 - fraction (10 bit)
+ //
+ // exp = 0, fract = +-0: zero
+ // exp = 0; fract != 0: subnormal numbers
+ // equation: -1 ^ sign * 2 ^ -14 * 0.fraction
+ // exp = 1..30: normalized value
+ // equation: -1 ^ sign * 2 ^ (exponent - 15) * 1.fraction
+ // exp = 31, fract = +-0: +-infinity
+ // exp = 31, fract != 0: NaN
+
+ uint32 sign = (fp16 >> 15) & 1;
+ uint32 fp16_exponent = (fp16 >> 10) & ((1 << 5) - 1);
+ uint32 fp16_fraction = fp16 & ((1 << 10) - 1);
+
+ // Normalized or zero
+ // binary32 equation: -1 ^ sign * 2 ^ (exponent - 127) * 1.fraction
+ // => exponent32 - 127 = exponent16 - 15, exponent32 = exponent16 + 127 - 15
+ uint32 fp32_exponent = fp16_exponent + 127 - 15;
+ uint32 fp32_fraction = fp16_fraction
+ << (23 - 10); // 23 is binary32 fraction size
+
+ if (fp16_exponent == 31) {
+ // Infinity or NaN
+ fp32_exponent = 255;
+ } else if (fp16_exponent == 0) {
+ if (fp16_fraction == 0) {
+ // +-Zero
+ fp32_exponent = 0;
+ fp32_fraction = 0;
+ } else {
+ // Subnormal numbers
+ // binary32 equation: -1 ^ sign * 2 ^ (exponent - 127) * 1.fraction
+ // binary16 equation: -1 ^ sign * 2 ^ -14 * 0.fraction, we can represent
+ // it as a normalized value in binary32, we have to shift fraction until
+ // we get 1.new_fraction and decrement exponent for each shift
+ fp32_exponent = -14 + 127;
+ while (!(fp32_fraction & (1 << 23))) {
+ fp32_exponent -= 1;
+ fp32_fraction <<= 1;
+ }
+ fp32_fraction &= ((1 << 23) - 1);
+ }
+ }
+ return (sign << 31) | (fp32_exponent << 23) | fp32_fraction;
+}
+
+static inline uint32 __attribute__((const)) fp24ToFloat(uint32 fp24) {
+ // binary24: Not a part of IEEE754-2008, but format is obvious,
+ // see https://en.wikipedia.org/wiki/Minifloat
+ // bit 23 - sign
+ // bits 22-16 - exponent (7 bit)
+ // bits 15-0 - fraction (16 bit)
+ //
+ // exp = 0, fract = +-0: zero
+ // exp = 0; fract != 0: subnormal numbers
+ // equation: -1 ^ sign * 2 ^ -62 * 0.fraction
+ // exp = 1..126: normalized value
+ // equation: -1 ^ sign * 2 ^ (exponent - 63) * 1.fraction
+ // exp = 127, fract = +-0: +-infinity
+ // exp = 127, fract != 0: NaN
+
+ uint32 sign = (fp24 >> 23) & 1;
+ uint32 fp24_exponent = (fp24 >> 16) & ((1 << 7) - 1);
+ uint32 fp24_fraction = fp24 & ((1 << 16) - 1);
+
+ // Normalized or zero
+ // binary32 equation: -1 ^ sign * 2 ^ (exponent - 127) * 1.fraction
+ // => exponent32 - 127 = exponent24 - 64, exponent32 = exponent16 + 127 - 63
+ uint32 fp32_exponent = fp24_exponent + 127 - 63;
+ uint32 fp32_fraction = fp24_fraction
+ << (23 - 16); // 23 is binary 32 fraction size
+
+ if (fp24_exponent == 127) {
+ // Infinity or NaN
+ fp32_exponent = 255;
+ } else if (fp24_exponent == 0) {
+ if (fp24_fraction == 0) {
+ // +-Zero
+ fp32_exponent = 0;
+ fp32_fraction = 0;
+ } else {
+ // Subnormal numbers
+ // binary32 equation: -1 ^ sign * 2 ^ (exponent - 127) * 1.fraction
+ // binary24 equation: -1 ^ sign * 2 ^ -62 * 0.fraction, we can represent
+ // it as a normalized value in binary32, we have to shift fraction until
+ // we get 1.new_fraction and decrement exponent for each shift
+ fp32_exponent = -62 + 127;
+ while (!(fp32_fraction & (1 << 23))) {
+ fp32_exponent -= 1;
+ fp32_fraction <<= 1;
+ }
+ fp32_fraction &= ((1 << 23) - 1);
+ }
+ }
+ return (sign << 31) | (fp32_exponent << 23) | fp32_fraction;
+}
+
+static inline void expandFP16(unsigned char* dst, int width) {
+ auto* dst16 = reinterpret_cast<ushort16*>(dst);
+ auto* dst32 = reinterpret_cast<uint32*>(dst);
+
+ for (int x = width - 1; x >= 0; x--)
+ dst32[x] = fp16ToFloat(dst16[x]);
+}
+
+static inline void expandFP24(unsigned char* dst, int width) {
+ auto* dst32 = reinterpret_cast<uint32*>(dst);
+ dst += (width - 1) * 3;
+ for (int x = width - 1; x >= 0; x--) {
+ dst32[x] = fp24ToFloat((dst[0] << 16) | (dst[1] << 8) | dst[2]);
+ dst -= 3;
+ }
+}
+
+void DeflateDecompressor::decode(std::unique_ptr<unsigned char[]>* uBuffer,
+ int width, int height, uint32 offX,
+ uint32 offY) {
+ uLongf dstLen = sizeof(float) * width * height;
+
+ if (!uBuffer->get())
+ *uBuffer = std::unique_ptr<unsigned char[]>(new unsigned char[dstLen]);
+
+ const auto cSize = input.getRemainSize();
+ const unsigned char* cBuffer = input.getData(cSize);
+
+ int err = uncompress(uBuffer->get(), &dstLen, cBuffer, cSize);
+ if (err != Z_OK) {
+ ThrowRDE("failed to uncompress tile: %d (%s)", err, zError(err));
+ }
+
+ int predFactor = 0;
+ switch (predictor) {
+ case 3:
+ predFactor = 1;
+ break;
+ case 34894:
+ predFactor = 2;
+ break;
+ case 34895:
+ predFactor = 4;
+ break;
+ default:
+ predFactor = 0;
+ break;
+ }
+
+ int bytesps = bps / 8;
+ size_t thisTileLength = offY + height > static_cast<uint32>(mRaw->dim.y)
+ ? mRaw->dim.y - offY
+ : height;
+ size_t thisTileWidth = offX + width > static_cast<uint32>(mRaw->dim.x)
+ ? mRaw->dim.x - offX
+ : width;
+
+ for (size_t row = 0; row < thisTileLength; ++row) {
+ unsigned char* src = uBuffer->get() + row * width * bytesps;
+ unsigned char* dst =
+ static_cast<unsigned char*>(mRaw->getData()) +
+ ((offY + row) * mRaw->pitch + offX * sizeof(float) * mRaw->getCpp());
+
+ if (predFactor)
+ decodeFPDeltaRow(src, dst, thisTileWidth, width, bytesps, predFactor);
+
+ assert(bytesps >= 2 && bytesps <= 4);
+ switch (bytesps) {
+ case 2:
+ expandFP16(dst, thisTileWidth);
+ break;
+ case 3:
+ expandFP24(dst, thisTileWidth);
+ break;
+ case 4:
+ // No need to expand FP32
+ break;
+ default:
+ __builtin_unreachable();
+ }
+ }
+}
+
+} // namespace rawspeed
+
+#else
+
+#pragma message \
+ "ZLIB is not present! Deflate compression will not be supported!"
+
+#endif
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/DeflateDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/DeflateDecompressor.h
new file mode 100644
index 000000000..c5489574b
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/DeflateDecompressor.h
@@ -0,0 +1,59 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h"
+
+#ifdef HAVE_ZLIB
+
+#include "common/Common.h" // for getHostEndianness, uint32, Endianness::big
+#include "common/RawImage.h" // for RawImage
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+#include "io/Buffer.h" // for Buffer, Buffer::size_type
+#include "io/ByteStream.h" // for ByteStream
+#include <memory> // for unique_ptr
+#include <utility> // for move
+
+namespace rawspeed {
+
+class DeflateDecompressor final : public AbstractDecompressor {
+ ByteStream input;
+ RawImage mRaw;
+ int predictor;
+ int bps;
+
+public:
+ DeflateDecompressor(ByteStream bs, const RawImage& img, int predictor_,
+ int bps_)
+ : input(std::move(bs)), mRaw(img), predictor(predictor_), bps(bps_) {}
+
+ void decode(std::unique_ptr<unsigned char[]>* uBuffer, int width, int height,
+ uint32 offX, uint32 offY);
+};
+
+} // namespace rawspeed
+
+#else
+
+#pragma message \
+ "ZLIB is not present! Deflate compression will not be supported!"
+
+#endif
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/FujiDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/FujiDecompressor.cpp
new file mode 100644
index 000000000..44459419a
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/FujiDecompressor.cpp
@@ -0,0 +1,825 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2016 Alexey Danilchenko
+ Copyright (C) 2016 Alex Tutubalin
+ Copyright (C) 2017 Uwe Müssel
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/FujiDecompressor.h"
+#include "common/Common.h" // for roundUpDiv...
+#include "common/RawImage.h" // for RawImage
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/AbstractParallelizedDecompressor.h" // for RawDecom...
+#include "io/Endianness.h" // for Endianness
+#include "metadata/ColorFilterArray.h" // for CFAColor...
+#include <algorithm> // for fill, min
+#include <cstdlib> // for abs
+#include <cstring> // for memcpy
+// IWYU pragma: no_include <bits/std_abs.h>
+
+namespace rawspeed {
+
+FujiDecompressor::FujiDecompressor(const RawImage& img, ByteStream input_)
+ : AbstractParallelizedDecompressor(img), input(std::move(input_)) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ input.setByteOrder(Endianness::big);
+
+ header = FujiHeader(&input);
+ if (!header)
+ ThrowRDE("compressed RAF header check");
+
+ if (mRaw->dim != iPoint2D(header.raw_width, header.raw_height))
+ ThrowRDE("RAF header specifies different dimensions!");
+
+ if (12 == header.raw_bits) {
+ ThrowRDE("Aha, finally, a 12-bit compressed RAF! Please consider providing "
+ "samples on <https://raw.pixls.us/>, thanks!");
+ }
+
+ for (int i = 0; i < 6; i++) {
+ for (int j = 0; j < 6; j++) {
+ const CFAColor c = mRaw->cfa.getColorAt(j, i);
+ switch (c) {
+ case CFA_RED:
+ case CFA_GREEN:
+ case CFA_BLUE:
+ CFA[i][j] = c;
+ break;
+ default:
+ ThrowRDE("Got unexpected color %u", c);
+ }
+ }
+ }
+
+ fuji_compressed_load_raw();
+}
+
+FujiDecompressor::fuji_compressed_params::fuji_compressed_params(
+ const FujiDecompressor& d) {
+ int cur_val;
+ char* qt;
+
+ if ((d.header.block_size % 3 && d.header.raw_type == 16) ||
+ (d.header.block_size & 1 && d.header.raw_type == 0)) {
+ ThrowRDE("fuji_block_checks");
+ }
+
+ q_table.resize(32768);
+
+ if (d.header.raw_type == 16) {
+ line_width = (d.header.block_size * 2) / 3;
+ } else {
+ line_width = d.header.block_size >> 1;
+ }
+
+ q_point[0] = 0;
+ q_point[1] = 0x12;
+ q_point[2] = 0x43;
+ q_point[3] = 0x114;
+ q_point[4] = (1 << d.header.raw_bits) - 1;
+ min_value = 0x40;
+
+ cur_val = -q_point[4];
+
+ for (qt = &q_table[0]; cur_val <= q_point[4]; ++qt, ++cur_val) {
+ if (cur_val <= -q_point[3]) {
+ *qt = -4;
+ } else if (cur_val <= -q_point[2]) {
+ *qt = -3;
+ } else if (cur_val <= -q_point[1]) {
+ *qt = -2;
+ } else if (cur_val < 0) {
+ *qt = -1;
+ } else if (cur_val == 0) {
+ *qt = 0;
+ } else if (cur_val < q_point[1]) {
+ *qt = 1;
+ } else if (cur_val < q_point[2]) {
+ *qt = 2;
+ } else if (cur_val < q_point[3]) {
+ *qt = 3;
+ } else {
+ *qt = 4;
+ }
+ }
+
+ // populting gradients
+ if (q_point[4] == 0x3FFF) {
+ total_values = 0x4000;
+ raw_bits = 14;
+ max_bits = 56;
+ maxDiff = 256;
+ } else if (q_point[4] == 0xFFF) {
+ ThrowRDE("Aha, finally, a 12-bit compressed RAF! Please consider providing "
+ "samples on <https://raw.pixls.us/>, thanks!");
+
+ /* kept for future, once there is a sample.
+ total_values = 4096;
+ raw_bits = 12;
+ max_bits = 48;
+ maxDiff = 64;
+ */
+ } else {
+ ThrowRDE("FUJI q_point");
+ }
+}
+
+void FujiDecompressor::fuji_compressed_block::reset(
+ const fuji_compressed_params* params) {
+ const bool reInit = !linealloc.empty();
+
+ linealloc.resize(_ltotal * (params->line_width + 2), 0);
+
+ if (reInit)
+ std::fill(linealloc.begin(), linealloc.end(), 0);
+
+ linebuf[_R0] = &linealloc[0];
+
+ for (int i = _R1; i <= _B4; i++) {
+ linebuf[i] = linebuf[i - 1] + params->line_width + 2;
+ }
+
+ for (int j = 0; j < 3; j++) {
+ for (int i = 0; i < 41; i++) {
+ grad_even[j][i].value1 = params->maxDiff;
+ grad_even[j][i].value2 = 1;
+ grad_odd[j][i].value1 = params->maxDiff;
+ grad_odd[j][i].value2 = 1;
+ }
+ }
+}
+
+template <typename T>
+void FujiDecompressor::copy_line(fuji_compressed_block* info,
+ const FujiStrip& strip, int cur_line,
+ T&& idx) const {
+ ushort16* lineBufB[3];
+ ushort16* lineBufG[6];
+ ushort16* lineBufR[3];
+
+ for (int i = 0; i < 3; i++) {
+ lineBufR[i] = info->linebuf[_R2 + i] + 1;
+ lineBufB[i] = info->linebuf[_B2 + i] + 1;
+ }
+
+ for (int i = 0; i < 6; i++) {
+ lineBufG[i] = info->linebuf[_G2 + i] + 1;
+ }
+
+ for (int row_count = 0; row_count < FujiStrip::lineHeight(); row_count++) {
+ auto* const raw_block_data = reinterpret_cast<ushort16*>(
+ mRaw->getData(strip.offsetX(), strip.offsetY(cur_line) + row_count));
+
+ for (int pixel_count = 0; pixel_count < strip.width(); pixel_count++) {
+ ushort16* line_buf = nullptr;
+
+ switch (CFA[row_count][pixel_count % 6]) {
+ case CFA_RED: // red
+ line_buf = lineBufR[row_count >> 1];
+ break;
+
+ case CFA_GREEN: // green
+ line_buf = lineBufG[row_count];
+ break;
+
+ case CFA_BLUE: // blue
+ line_buf = lineBufB[row_count >> 1];
+ break;
+
+ default:
+ __builtin_unreachable();
+ }
+
+ raw_block_data[pixel_count] = line_buf[idx(pixel_count)];
+ }
+ }
+}
+
+void FujiDecompressor::copy_line_to_xtrans(fuji_compressed_block* info,
+ const FujiStrip& strip,
+ int cur_line) const {
+ auto index = [](int pixel_count) {
+ return (((pixel_count * 2 / 3) & 0x7FFFFFFE) | ((pixel_count % 3) & 1)) +
+ ((pixel_count % 3) >> 1);
+ };
+
+ copy_line(info, strip, cur_line, index);
+}
+
+void FujiDecompressor::copy_line_to_bayer(fuji_compressed_block* info,
+ const FujiStrip& strip,
+ int cur_line) const {
+ auto index = [](int pixel_count) { return pixel_count >> 1; };
+
+ copy_line(info, strip, cur_line, index);
+}
+
+void FujiDecompressor::fuji_zerobits(BitPumpMSB* pump, int* count) const {
+ uchar8 zero = 0;
+ *count = 0;
+
+ while (zero == 0) {
+ zero = pump->getBits(1);
+
+ if (zero)
+ break;
+
+ ++*count;
+ }
+}
+
+int __attribute__((const))
+FujiDecompressor::bitDiff(int value1, int value2) const {
+ int decBits = 0;
+
+ if (value2 >= value1)
+ return decBits;
+
+ while (decBits <= 12) {
+ ++decBits;
+
+ if ((value2 << decBits) >= value1)
+ return decBits;
+ }
+
+ return decBits;
+}
+
+template <typename T1, typename T2>
+int FujiDecompressor::fuji_decode_sample(T1&& func_0, T2&& func_1,
+ fuji_compressed_block* info,
+ BitPumpMSB* pump, ushort16* line_buf,
+ int* pos, int_pair* grads) const {
+ int interp_val = 0;
+ int errcnt = 0;
+
+ int sample = 0;
+ int code = 0;
+ ushort16* line_buf_cur = line_buf + *pos;
+
+ int grad;
+ int gradient;
+
+ func_0(line_buf_cur, &interp_val, &grad, &gradient);
+
+ fuji_zerobits(pump, &sample);
+
+ if (sample < common_info.max_bits - common_info.raw_bits - 1) {
+ int decBits = bitDiff(grads[gradient].value1, grads[gradient].value2);
+ code = pump->getBits(decBits);
+ code += sample << decBits;
+ } else {
+ code = pump->getBits(common_info.raw_bits);
+ code++;
+ }
+
+ if (code < 0 || code >= common_info.total_values) {
+ errcnt++;
+ }
+
+ if (code & 1) {
+ code = -1 - code / 2;
+ } else {
+ code /= 2;
+ }
+
+ grads[gradient].value1 += std::abs(code);
+
+ if (grads[gradient].value2 == common_info.min_value) {
+ grads[gradient].value1 >>= 1;
+ grads[gradient].value2 >>= 1;
+ }
+
+ grads[gradient].value2++;
+
+ interp_val = func_1(grad, interp_val, code);
+
+ if (interp_val < 0) {
+ interp_val += common_info.total_values;
+ } else if (interp_val > common_info.q_point[4]) {
+ interp_val -= common_info.total_values;
+ }
+
+ if (interp_val >= 0) {
+ line_buf_cur[0] = std::min(interp_val, common_info.q_point[4]);
+ } else {
+ line_buf_cur[0] = 0;
+ }
+
+ *pos += 2;
+
+ return errcnt;
+}
+
+#define fuji_quant_gradient(v1, v2) \
+ (9 * ci.q_table[ci.q_point[4] + (v1)] + ci.q_table[ci.q_point[4] + (v2)])
+
+int FujiDecompressor::fuji_decode_sample_even(fuji_compressed_block* info,
+ BitPumpMSB* pump,
+ ushort16* line_buf, int* pos,
+ int_pair* grads) const {
+ const auto& ci = common_info;
+ return fuji_decode_sample(
+ [&ci](const ushort16* line_buf_cur, int* interp_val, int* grad,
+ int* gradient) {
+ int Rb = line_buf_cur[-2 - ci.line_width];
+ int Rc = line_buf_cur[-3 - ci.line_width];
+ int Rd = line_buf_cur[-1 - ci.line_width];
+ int Rf = line_buf_cur[-4 - 2 * ci.line_width];
+
+ int diffRcRb;
+ int diffRfRb;
+ int diffRdRb;
+
+ *grad = fuji_quant_gradient(Rb - Rf, Rc - Rb);
+ *gradient = std::abs(*grad);
+ diffRcRb = std::abs(Rc - Rb);
+ diffRfRb = std::abs(Rf - Rb);
+ diffRdRb = std::abs(Rd - Rb);
+
+ if (diffRcRb > diffRfRb && diffRcRb > diffRdRb) {
+ *interp_val = Rf + Rd + 2 * Rb;
+ } else if (diffRdRb > diffRcRb && diffRdRb > diffRfRb) {
+ *interp_val = Rf + Rc + 2 * Rb;
+ } else {
+ *interp_val = Rd + Rc + 2 * Rb;
+ }
+ },
+ [](int grad, int interp_val, int code) {
+ if (grad < 0) {
+ interp_val = (interp_val >> 2) - code;
+ } else {
+ interp_val = (interp_val >> 2) + code;
+ }
+
+ return interp_val;
+ },
+ info, pump, line_buf, pos, grads);
+}
+
+int FujiDecompressor::fuji_decode_sample_odd(fuji_compressed_block* info,
+ BitPumpMSB* pump,
+ ushort16* line_buf, int* pos,
+ int_pair* grads) const {
+ const auto& ci = common_info;
+ return fuji_decode_sample(
+ [&ci](const ushort16* line_buf_cur, int* interp_val, int* grad,
+ int* gradient) {
+ int Ra = line_buf_cur[-1];
+ int Rb = line_buf_cur[-2 - ci.line_width];
+ int Rc = line_buf_cur[-3 - ci.line_width];
+ int Rd = line_buf_cur[-1 - ci.line_width];
+ int Rg = line_buf_cur[1];
+
+ *grad = fuji_quant_gradient(Rb - Rc, Rc - Ra);
+ *gradient = std::abs(*grad);
+
+ if ((Rb > Rc && Rb > Rd) || (Rb < Rc && Rb < Rd)) {
+ *interp_val = (Rg + Ra + 2 * Rb) >> 2;
+ } else {
+ *interp_val = (Ra + Rg) >> 1;
+ }
+ },
+ [](int grad, int interp_val, int code) {
+ if (grad < 0) {
+ interp_val -= code;
+ } else {
+ interp_val += code;
+ }
+
+ return interp_val;
+ },
+ info, pump, line_buf, pos, grads);
+}
+
+#undef fuji_quant_gradient
+
+void FujiDecompressor::fuji_decode_interpolation_even(int line_width,
+ ushort16* line_buf,
+ int* pos) const {
+ ushort16* line_buf_cur = line_buf + *pos;
+ int Rb = line_buf_cur[-2 - line_width];
+ int Rc = line_buf_cur[-3 - line_width];
+ int Rd = line_buf_cur[-1 - line_width];
+ int Rf = line_buf_cur[-4 - 2 * line_width];
+ int diffRcRb = std::abs(Rc - Rb);
+ int diffRfRb = std::abs(Rf - Rb);
+ int diffRdRb = std::abs(Rd - Rb);
+
+ if (diffRcRb > diffRfRb && diffRcRb > diffRdRb) {
+ *line_buf_cur = (Rf + Rd + 2 * Rb) >> 2;
+ } else if (diffRdRb > diffRcRb && diffRdRb > diffRfRb) {
+ *line_buf_cur = (Rf + Rc + 2 * Rb) >> 2;
+ } else {
+ *line_buf_cur = (Rd + Rc + 2 * Rb) >> 2;
+ }
+
+ *pos += 2;
+}
+
+void FujiDecompressor::fuji_extend_generic(ushort16* linebuf[_ltotal],
+ int line_width, int start,
+ int end) const {
+ for (int i = start; i <= end; i++) {
+ linebuf[i][0] = linebuf[i - 1][1];
+ linebuf[i][line_width + 1] = linebuf[i - 1][line_width];
+ }
+}
+
+void FujiDecompressor::fuji_extend_red(ushort16* linebuf[_ltotal],
+ int line_width) const {
+ fuji_extend_generic(linebuf, line_width, _R2, _R4);
+}
+
+void FujiDecompressor::fuji_extend_green(ushort16* linebuf[_ltotal],
+ int line_width) const {
+ fuji_extend_generic(linebuf, line_width, _G2, _G7);
+}
+
+void FujiDecompressor::fuji_extend_blue(ushort16* linebuf[_ltotal],
+ int line_width) const {
+ fuji_extend_generic(linebuf, line_width, _B2, _B4);
+}
+
+void FujiDecompressor::xtrans_decode_block(fuji_compressed_block* info,
+ BitPumpMSB* pump,
+ int cur_line) const {
+ struct ColorPos {
+ int even = 0;
+ int odd = 1;
+
+ void reset() {
+ even = 0;
+ odd = 1;
+ }
+ };
+
+ ColorPos r;
+ ColorPos g;
+ ColorPos b;
+
+ int errcnt = 0;
+
+ const int line_width = common_info.line_width;
+
+ // FIXME: GCC5 sucks.
+ // https://github.com/darktable-org/rawspeed/issues/112
+ // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=871250
+ // https://bugs.launchpad.net/linuxmint/+bug/1709234
+ auto pass = [&, line_width](auto&& even_func, _xt_lines c0, _xt_lines c1,
+ int grad, ColorPos& c0_pos, ColorPos& c1_pos) {
+ while (g.even < line_width || g.odd < line_width) {
+ if (g.even < line_width)
+ even_func(c0, c1, grad, c0_pos, c1_pos);
+
+ if (g.even > 8) {
+ errcnt += fuji_decode_sample_odd(info, pump, info->linebuf[c0] + 1,
+ &c0_pos.odd, info->grad_odd[grad]);
+ errcnt += fuji_decode_sample_odd(info, pump, info->linebuf[c1] + 1,
+ &c1_pos.odd, info->grad_odd[grad]);
+ }
+ }
+ };
+
+ pass(
+ [&](_xt_lines c0, _xt_lines c1, int grad, ColorPos& c0_pos,
+ ColorPos& c1_pos) {
+ fuji_decode_interpolation_even(line_width, info->linebuf[c0] + 1,
+ &c0_pos.even);
+ errcnt += fuji_decode_sample_even(info, pump, info->linebuf[c1] + 1,
+ &c1_pos.even, info->grad_even[grad]);
+ },
+ _R2, _G2, 0, r, g);
+
+ fuji_extend_red(info->linebuf, line_width);
+ fuji_extend_green(info->linebuf, line_width);
+
+ g.reset();
+
+ pass(
+ [&](_xt_lines c0, _xt_lines c1, int grad, ColorPos& c0_pos,
+ ColorPos& c1_pos) {
+ errcnt += fuji_decode_sample_even(info, pump, info->linebuf[c0] + 1,
+ &c0_pos.even, info->grad_even[grad]);
+ fuji_decode_interpolation_even(line_width, info->linebuf[c1] + 1,
+ &c1_pos.even);
+ },
+ _G3, _B2, 1, g, b);
+
+ fuji_extend_green(info->linebuf, line_width);
+ fuji_extend_blue(info->linebuf, line_width);
+
+ r.reset();
+ g.reset();
+
+ pass(
+ [&](_xt_lines c0, _xt_lines c1, int grad, ColorPos& c0_pos,
+ ColorPos& c1_pos) {
+ if (c0_pos.even & 3) {
+ errcnt +=
+ fuji_decode_sample_even(info, pump, info->linebuf[c0] + 1,
+ &c0_pos.even, info->grad_even[grad]);
+ } else {
+ fuji_decode_interpolation_even(line_width, info->linebuf[c0] + 1,
+ &c0_pos.even);
+ }
+
+ fuji_decode_interpolation_even(line_width, info->linebuf[c1] + 1,
+ &c1_pos.even);
+ },
+ _R3, _G4, 2, r, g);
+
+ fuji_extend_red(info->linebuf, line_width);
+ fuji_extend_green(info->linebuf, line_width);
+
+ g.reset();
+ b.reset();
+
+ pass(
+ [&](_xt_lines c0, _xt_lines c1, int grad, ColorPos& c0_pos,
+ ColorPos& c1_pos) {
+ errcnt += fuji_decode_sample_even(info, pump, info->linebuf[c0] + 1,
+ &c0_pos.even, info->grad_even[grad]);
+
+ if ((c1_pos.even & 3) == 2) {
+ fuji_decode_interpolation_even(line_width, info->linebuf[c1] + 1,
+ &c1_pos.even);
+ } else {
+ errcnt +=
+ fuji_decode_sample_even(info, pump, info->linebuf[c1] + 1,
+ &c1_pos.even, info->grad_even[grad]);
+ }
+ },
+ _G5, _B3, 0, g, b);
+
+ fuji_extend_green(info->linebuf, line_width);
+ fuji_extend_blue(info->linebuf, line_width);
+
+ r.reset();
+ g.reset();
+
+ pass(
+ [&](_xt_lines c0, _xt_lines c1, int grad, ColorPos& c0_pos,
+ ColorPos& c1_pos) {
+ if ((c0_pos.even & 3) == 2) {
+ fuji_decode_interpolation_even(line_width, info->linebuf[c0] + 1,
+ &c0_pos.even);
+ } else {
+ errcnt +=
+ fuji_decode_sample_even(info, pump, info->linebuf[c0] + 1,
+ &c0_pos.even, info->grad_even[grad]);
+ }
+
+ errcnt += fuji_decode_sample_even(info, pump, info->linebuf[c1] + 1,
+ &c1_pos.even, info->grad_even[grad]);
+ },
+ _R4, _G6, 1, r, g);
+
+ fuji_extend_red(info->linebuf, line_width);
+ fuji_extend_green(info->linebuf, line_width);
+
+ g.reset();
+ b.reset();
+
+ pass(
+ [&](_xt_lines c0, _xt_lines c1, int grad, ColorPos& c0_pos,
+ ColorPos& c1_pos) {
+ fuji_decode_interpolation_even(line_width, info->linebuf[c0] + 1,
+ &c0_pos.even);
+
+ if (c1_pos.even & 3) {
+ errcnt +=
+ fuji_decode_sample_even(info, pump, info->linebuf[c1] + 1,
+ &c1_pos.even, info->grad_even[grad]);
+ } else {
+ fuji_decode_interpolation_even(line_width, info->linebuf[c1] + 1,
+ &c1_pos.even);
+ }
+ },
+ _G7, _B4, 2, g, b);
+
+ fuji_extend_green(info->linebuf, line_width);
+ fuji_extend_blue(info->linebuf, line_width);
+
+ if (errcnt)
+ ThrowRDE("xtrans_decode_block");
+}
+
+void FujiDecompressor::fuji_bayer_decode_block(fuji_compressed_block* info,
+ BitPumpMSB* pump,
+ int cur_line) const {
+ struct ColorPos {
+ int even = 0;
+ int odd = 1;
+
+ void reset() {
+ even = 0;
+ odd = 1;
+ }
+ };
+
+ ColorPos r;
+ ColorPos g;
+ ColorPos b;
+
+ int errcnt = 0;
+
+ const int line_width = common_info.line_width;
+
+ auto pass = [&](_xt_lines c0, _xt_lines c1, int grad, ColorPos& c0_pos,
+ ColorPos& c1_pos) {
+ while (g.even < line_width || g.odd < line_width) {
+ if (g.even < line_width) {
+ errcnt += fuji_decode_sample_even(info, pump, info->linebuf[c0] + 1,
+ &c0_pos.even, info->grad_even[grad]);
+ errcnt += fuji_decode_sample_even(info, pump, info->linebuf[c1] + 1,
+ &c1_pos.even, info->grad_even[grad]);
+ }
+
+ if (g.even > 8) {
+ errcnt += fuji_decode_sample_odd(info, pump, info->linebuf[c0] + 1,
+ &c0_pos.odd, info->grad_odd[grad]);
+ errcnt += fuji_decode_sample_odd(info, pump, info->linebuf[c1] + 1,
+ &c1_pos.odd, info->grad_odd[grad]);
+ }
+ }
+ };
+
+ auto pass_RG = [&](_xt_lines c0, _xt_lines c1, int grad) {
+ pass(c0, c1, grad, r, g);
+
+ fuji_extend_red(info->linebuf, line_width);
+ fuji_extend_green(info->linebuf, line_width);
+ };
+
+ auto pass_GB = [&](_xt_lines c0, _xt_lines c1, int grad) {
+ pass(c0, c1, grad, g, b);
+
+ fuji_extend_green(info->linebuf, line_width);
+ fuji_extend_blue(info->linebuf, line_width);
+ };
+
+ pass_RG(_R2, _G2, 0);
+
+ g.reset();
+
+ pass_GB(_G3, _B2, 1);
+
+ r.reset();
+ g.reset();
+
+ pass_RG(_R3, _G4, 2);
+
+ g.reset();
+ b.reset();
+
+ pass_GB(_G5, _B3, 0);
+
+ r.reset();
+ g.reset();
+
+ pass_RG(_R4, _G6, 1);
+
+ g.reset();
+ b.reset();
+
+ pass_GB(_G7, _B4, 2);
+
+ if (errcnt)
+ ThrowRDE("fuji decode bayer block");
+}
+
+void FujiDecompressor::fuji_decode_strip(
+ fuji_compressed_block* info_block, const FujiStrip& strip) const {
+ BitPumpMSB pump(strip.bs);
+
+ const unsigned line_size = sizeof(ushort16) * (common_info.line_width + 2);
+
+ struct i_pair {
+ int a;
+ int b;
+ };
+
+ const i_pair mtable[6] = {{_R0, _R3}, {_R1, _R4}, {_G0, _G6},
+ {_G1, _G7}, {_B0, _B3}, {_B1, _B4}};
+ const i_pair ztable[3] = {{_R2, 3}, {_G2, 6}, {_B2, 3}};
+
+ for (int cur_line = 0; cur_line < strip.height(); cur_line++) {
+ if (header.raw_type == 16) {
+ xtrans_decode_block(info_block, &pump, cur_line);
+ } else {
+ fuji_bayer_decode_block(info_block, &pump, cur_line);
+ }
+
+ // copy data from line buffers and advance
+ for (auto i : mtable) {
+ memcpy(info_block->linebuf[i.a], info_block->linebuf[i.b], line_size);
+ }
+
+ if (header.raw_type == 16) {
+ copy_line_to_xtrans(info_block, strip, cur_line);
+ } else {
+ copy_line_to_bayer(info_block, strip, cur_line);
+ }
+
+ for (auto i : ztable) {
+ memset(info_block->linebuf[i.a], 0, i.b * line_size);
+ info_block->linebuf[i.a][0] = info_block->linebuf[i.a - 1][1];
+ info_block->linebuf[i.a][common_info.line_width + 1] =
+ info_block->linebuf[i.a - 1][common_info.line_width];
+ }
+ }
+}
+
+void FujiDecompressor::fuji_compressed_load_raw() {
+ common_info = fuji_compressed_params(*this);
+
+ // read block sizes
+ std::vector<uint32> block_sizes;
+ block_sizes.resize(header.blocks_in_row);
+ for (auto& block_size : block_sizes)
+ block_size = input.getU32();
+
+ // some padding?
+ const uint64 raw_offset = sizeof(uint32) * header.blocks_in_row;
+ if (raw_offset & 0xC) {
+ const int padding = 0x10 - (raw_offset & 0xC);
+ input.skipBytes(padding);
+ }
+
+ // calculating raw block offsets
+ strips.reserve(header.blocks_in_row);
+
+ int block = 0;
+ for (const auto& block_size : block_sizes) {
+ strips.emplace_back(header, block, input.getStream(block_size));
+ block++;
+ }
+}
+
+void FujiDecompressor::decompress() const {
+ startThreading(header.blocks_in_row);
+}
+
+void FujiDecompressor::decompressThreaded(
+ const RawDecompressorThread* t) const {
+ fuji_compressed_block block_info;
+
+ for (size_t i = t->start; i < t->end && i < strips.size(); i++) {
+ block_info.reset(&common_info);
+ fuji_decode_strip(&block_info, strips[i]);
+ }
+}
+
+FujiDecompressor::FujiHeader::FujiHeader(ByteStream* bs) {
+ signature = bs->getU16();
+ version = bs->getByte();
+ raw_type = bs->getByte();
+ raw_bits = bs->getByte();
+ raw_height = bs->getU16();
+ raw_rounded_width = bs->getU16();
+ raw_width = bs->getU16();
+ block_size = bs->getU16();
+ blocks_in_row = bs->getByte();
+ total_lines = bs->getU16();
+}
+
+FujiDecompressor::FujiHeader::operator bool() const {
+ // general validation
+ const bool invalid =
+ (signature != 0x4953 || version != 1 || raw_height > 0x3000 ||
+ raw_height < FujiStrip::lineHeight() ||
+ raw_height % FujiStrip::lineHeight() || raw_width > 0x3000 ||
+ raw_width < 0x300 || raw_width % 24 || raw_rounded_width > 0x3000 ||
+ block_size != 0x300 || raw_rounded_width < block_size ||
+ raw_rounded_width % block_size ||
+ raw_rounded_width - raw_width >= block_size || blocks_in_row > 0x10 ||
+ blocks_in_row == 0 || blocks_in_row != raw_rounded_width / block_size ||
+ blocks_in_row != roundUpDivision(raw_width, block_size) ||
+ total_lines > 0x800 || total_lines == 0 ||
+ total_lines != raw_height / FujiStrip::lineHeight() ||
+ (raw_bits != 12 && raw_bits != 14) || (raw_type != 16 && raw_type != 0));
+
+ return !invalid;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/FujiDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/FujiDecompressor.h
new file mode 100644
index 000000000..1955e9036
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/FujiDecompressor.h
@@ -0,0 +1,213 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Uwe Müssel
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for ushort16
+#include "decompressors/AbstractParallelizedDecompressor.h" // for Abstract...
+#include "io/BitPumpMSB.h" // for BitPumpMSB
+#include "io/ByteStream.h" // for ByteStream
+#include "metadata/ColorFilterArray.h" // for CFAColor
+#include <algorithm> // for move
+#include <array> // for array
+#include <cassert> // for assert
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class RawImage;
+
+class FujiDecompressor final : public AbstractParallelizedDecompressor {
+ void decompressThreaded(const RawDecompressorThread* t) const final;
+
+public:
+ struct FujiHeader {
+ FujiHeader() = default;
+
+ explicit FujiHeader(ByteStream* input_);
+ explicit __attribute__((pure)) operator bool() const; // validity check
+
+ ushort16 signature;
+ uchar8 version;
+ uchar8 raw_type;
+ uchar8 raw_bits;
+ ushort16 raw_height;
+ ushort16 raw_rounded_width;
+ ushort16 raw_width;
+ ushort16 block_size;
+ uchar8 blocks_in_row;
+ ushort16 total_lines;
+ };
+
+ FujiHeader header;
+
+ struct FujiStrip {
+ // part of which 'image' this block is
+ const FujiHeader& h;
+
+ // which strip is this, 0 .. h.blocks_in_row-1
+ const int n;
+
+ // the compressed data of this strip
+ const ByteStream bs;
+
+ FujiStrip(const FujiHeader& h_, int block, ByteStream bs_)
+ : h(h_), n(block), bs(std::move(bs_)) {
+ assert(n >= 0 && n < h.blocks_in_row);
+ }
+
+ // each strip's line corresponds to 6 output lines.
+ static int lineHeight() { return 6; }
+
+ // how many vertical lines does this block encode?
+ int height() const { return h.total_lines; }
+
+ // how many horizontal pixels does this block encode?
+ int width() const {
+ // if this is not the last block, we are good.
+ if ((n + 1) != h.blocks_in_row)
+ return h.block_size;
+
+ // ok, this is the last block...
+
+ assert(h.block_size * h.blocks_in_row >= h.raw_width);
+ return h.raw_width - offsetX();
+ }
+
+ // where vertically does this block start?
+ int offsetY(int line = 0) const {
+ assert(line >= 0 && line < height());
+ return lineHeight() * line;
+ }
+
+ // where horizontally does this block start?
+ int offsetX() const { return h.block_size * n; }
+ };
+
+ FujiDecompressor(const RawImage& img, ByteStream input);
+
+ void fuji_compressed_load_raw();
+
+ void decompress() const final;
+
+protected:
+ struct fuji_compressed_params {
+ fuji_compressed_params() = default;
+
+ explicit fuji_compressed_params(const FujiDecompressor& d);
+
+ std::vector<char> q_table; /* quantization table */
+ int q_point[5]; /* quantization points */
+ int max_bits;
+ int min_value;
+ int raw_bits;
+ int total_values;
+ int maxDiff;
+ ushort16 line_width;
+ };
+
+ fuji_compressed_params common_info;
+
+ struct int_pair {
+ int value1;
+ int value2;
+ };
+
+ enum _xt_lines {
+ _R0 = 0,
+ _R1,
+ _R2,
+ _R3,
+ _R4,
+ _G0,
+ _G1,
+ _G2,
+ _G3,
+ _G4,
+ _G5,
+ _G6,
+ _G7,
+ _B0,
+ _B1,
+ _B2,
+ _B3,
+ _B4,
+ _ltotal
+ };
+
+ struct fuji_compressed_block {
+ fuji_compressed_block() = default;
+
+ void reset(const fuji_compressed_params* params);
+
+ int_pair grad_even[3][41]; // tables of gradients
+ int_pair grad_odd[3][41];
+ std::vector<ushort16> linealloc;
+ ushort16* linebuf[_ltotal];
+ };
+
+private:
+ ByteStream input;
+
+ std::array<std::array<CFAColor, 6>, 6> CFA;
+
+ std::vector<FujiStrip> strips;
+
+ void fuji_decode_strip(fuji_compressed_block* info_block,
+ const FujiStrip& strip) const;
+
+ template <typename T>
+ void copy_line(fuji_compressed_block* info, const FujiStrip& strip,
+ int cur_line, T&& idx) const;
+
+ void copy_line_to_xtrans(fuji_compressed_block* info, const FujiStrip& strip,
+ int cur_line) const;
+ void copy_line_to_bayer(fuji_compressed_block* info, const FujiStrip& strip,
+ int cur_line) const;
+
+ void fuji_zerobits(BitPumpMSB* pump, int* count) const;
+ int bitDiff(int value1, int value2) const;
+
+ template <typename T1, typename T2>
+ int fuji_decode_sample(T1&& func_0, T2&& func_1, fuji_compressed_block* info,
+ BitPumpMSB* pump, ushort16* line_buf, int* pos,
+ int_pair* grads) const;
+ int fuji_decode_sample_even(fuji_compressed_block* info, BitPumpMSB* pump,
+ ushort16* line_buf, int* pos,
+ int_pair* grads) const;
+ int fuji_decode_sample_odd(fuji_compressed_block* info, BitPumpMSB* pump,
+ ushort16* line_buf, int* pos,
+ int_pair* grads) const;
+
+ void fuji_decode_interpolation_even(int line_width, ushort16* line_buf,
+ int* pos) const;
+ void fuji_extend_generic(ushort16* linebuf[_ltotal], int line_width,
+ int start, int end) const;
+ void fuji_extend_red(ushort16* linebuf[_ltotal], int line_width) const;
+ void fuji_extend_green(ushort16* linebuf[_ltotal], int line_width) const;
+ void fuji_extend_blue(ushort16* linebuf[_ltotal], int line_width) const;
+ void xtrans_decode_block(fuji_compressed_block* info,
+ BitPumpMSB* pump, int cur_line) const;
+ void fuji_bayer_decode_block(fuji_compressed_block* info,
+ BitPumpMSB* pump, int cur_line) const;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/HasselbladDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/HasselbladDecompressor.cpp
new file mode 100644
index 000000000..11a74cf2e
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/HasselbladDecompressor.cpp
@@ -0,0 +1,106 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/HasselbladDecompressor.h"
+#include "common/Common.h" // for uint32, ushort16
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/BitPumpMSB32.h" // for BitPumpMSB32, BitStream<>::f...
+#include "io/ByteStream.h" // for ByteStream
+#include <array> // for array
+#include <cassert> // for assert
+
+namespace rawspeed {
+
+HasselbladDecompressor::HasselbladDecompressor(const ByteStream& bs,
+ const RawImage& img)
+ : AbstractLJpegDecompressor(bs, img) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ // FIXME: could be wrong. max "active pixels" - "100 MP"
+ if (mRaw->dim.x == 0 || mRaw->dim.y == 0 || mRaw->dim.x % 2 != 0 ||
+ mRaw->dim.x > 11600 || mRaw->dim.y > 8700) {
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x,
+ mRaw->dim.y);
+ }
+}
+
+// Returns len bits as a signed value.
+// Highest bit is a sign bit
+inline int HasselbladDecompressor::getBits(BitPumpMSB32* bs, int len) {
+ int diff = bs->getBits(len);
+ diff = len > 0 ? HuffmanTable::signExtended(diff, len) : diff;
+ if (diff == 65535)
+ return -32768;
+ return diff;
+}
+
+void HasselbladDecompressor::decodeScan() {
+ if (frame.w != static_cast<unsigned>(mRaw->dim.x) ||
+ frame.h != static_cast<unsigned>(mRaw->dim.y)) {
+ ThrowRDE("LJPEG frame does not match EXIF dimensions: (%u; %u) vs (%i; %i)",
+ frame.w, frame.h, mRaw->dim.x, mRaw->dim.y);
+ }
+
+ assert(frame.h > 0);
+ assert(frame.w > 0);
+ assert(frame.w % 2 == 0);
+
+ const auto ht = getHuffmanTables<1>();
+
+ BitPumpMSB32 bitStream(input);
+ // Pixels are packed two at a time, not like LJPEG:
+ // [p1_length_as_huffman][p2_length_as_huffman][p0_diff_with_length][p1_diff_with_length]|NEXT PIXELS
+ for (uint32 y = 0; y < frame.h; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(mRaw->getData(0, y));
+ int p1 = 0x8000 + pixelBaseOffset;
+ int p2 = 0x8000 + pixelBaseOffset;
+ for (uint32 x = 0; x < frame.w; x += 2) {
+ int len1 = ht[0]->decodeLength(bitStream);
+ int len2 = ht[0]->decodeLength(bitStream);
+ p1 += getBits(&bitStream, len1);
+ p2 += getBits(&bitStream, len2);
+ dest[x] = p1;
+ dest[x+1] = p2;
+ }
+ }
+ input.skipBytes(bitStream.getBufferPosition());
+}
+
+void HasselbladDecompressor::decode(int pixelBaseOffset_)
+{
+ pixelBaseOffset = pixelBaseOffset_;
+
+ if (pixelBaseOffset < -65536 || pixelBaseOffset > 65535)
+ ThrowRDE("Either the offset %i or the bounds are wrong.", pixelBaseOffset);
+
+ // We cannot use fully decoding huffman table,
+ // because values are packed two pixels at the time.
+ fullDecodeHT = false;
+
+ AbstractLJpegDecompressor::decode();
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/HasselbladDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/HasselbladDecompressor.h
new file mode 100644
index 000000000..03535d3cb
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/HasselbladDecompressor.h
@@ -0,0 +1,47 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "decompressors/AbstractLJpegDecompressor.h" // for AbstractLJpegDe...
+#include "io/BitPumpMSB32.h" // for BitPumpMSB32
+#include "io/Buffer.h" // for Buffer, Buffer:...
+#include "io/ByteStream.h" // for ByteStream
+
+namespace rawspeed {
+
+class RawImage;
+
+class HasselbladDecompressor final : public AbstractLJpegDecompressor
+{
+ int pixelBaseOffset = 0;
+
+ void decodeScan() override;
+
+public:
+ HasselbladDecompressor(const ByteStream& bs, const RawImage& img);
+
+ void decode(int pixelBaseOffset_);
+
+ static int getBits(BitPumpMSB32* bs, int len);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/HuffmanTable.h b/src/external/rawspeed/src/librawspeed/decompressors/HuffmanTable.h
new file mode 100644
index 000000000..3e758e6a0
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/HuffmanTable.h
@@ -0,0 +1,366 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for ushort16, uchar8, int32
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "io/Buffer.h" // for Buffer
+#include <algorithm> // for copy
+#include <cassert> // for assert
+#include <cstddef> // for size_t
+#include <iterator> // for distance
+#include <numeric> // for accumulate
+#include <vector> // for vector, allocator, operator==
+
+/*
+* The following code is inspired by the IJG JPEG library.
+*
+* Copyright (C) 1991, 1992, Thomas G. Lane.
+* Part of the Independent JPEG Group's software.
+* See the file Copyright for more details.
+*
+* Copyright (c) 1993 Brian C. Smith, The Regents of the University
+* of California
+* All rights reserved.
+*
+* Copyright (c) 1994 Kongji Huang and Brian C. Smith.
+* Cornell University
+* All rights reserved.
+*
+* Permission to use, copy, modify, and distribute this software and its
+* documentation for any purpose, without fee, and without written agreement is
+* hereby granted, provided that the above copyright notice and the following
+* two paragraphs appear in all copies of this software.
+*
+* IN NO EVENT SHALL CORNELL UNIVERSITY BE LIABLE TO ANY PARTY FOR
+* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
+* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF CORNELL
+* UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+* CORNELL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+* ON AN "AS IS" BASIS, AND CORNELL UNIVERSITY HAS NO OBLIGATION TO
+* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+namespace rawspeed {
+
+class HuffmanTable final {
+ // private fields calculated from codesPerBits and codeValues
+ // they are index '1' based, so we can directly lookup the value
+ // for code length l without decrementing
+ std::vector<ushort16> maxCodeOL; // index is length of code
+ std::vector<ushort16> codeOffsetOL; // index is length of code
+
+ // The code can be compiled with two different decode lookup table layouts.
+ // The idea is that different CPU architectures may perform better with
+ // one or the other, depending on the relative performance of their arithmetic
+ // core vs their memory access. For an Intel Core i7, the big table is better.
+#if 1
+ // lookup table containing 3 fields: payload:16|flag:8|len:8
+ // The payload may be the fully decoded diff or the length of the diff.
+ // The len field contains the number of bits, this lookup consumed.
+ // A lookup value of 0 means the code was too big to fit into the table.
+ // The optimal LookupDepth is also likely to depend on the CPU architecture.
+ static constexpr unsigned PayloadShift = 16;
+ static constexpr unsigned FlagMask = 0x100;
+ static constexpr unsigned LenMask = 0xff;
+ static constexpr unsigned LookupDepth = 11;
+ std::vector<int32> decodeLookup;
+#else
+ // lookup table containing 2 fields: payload:4|len:4
+ // the payload is the length of the diff, len is the length of the code
+ static constexpr unsigned LookupDepth = 15;
+ static constexpr unsigned PayloadShift = 4;
+ static constexpr unsigned FlagMask = 0;
+ static constexpr unsigned LenMask = 0x0f;
+ std::vector<uchar8> decodeLookup;
+#endif
+
+ bool fullDecode = true;
+ bool fixDNGBug16 = false;
+
+ inline size_t __attribute__((pure)) maxCodePlusDiffLength() const {
+ return nCodesPerLength.size() - 1 +
+ *(std::max_element(codeValues.cbegin(), codeValues.cend()));
+ }
+
+ // These two fields directly represent the contents of a JPEG DHT field
+
+ // 1. The number of codes there are per bit length, this is index 1 based.
+ // (there are always 0 codes of length 0)
+ std::vector<unsigned int> nCodesPerLength; // index is length of code
+ inline unsigned int __attribute__((pure)) maxCodesCount() const {
+ return std::accumulate(nCodesPerLength.begin(), nCodesPerLength.end(), 0U);
+ }
+
+ // 2. This is the actual huffman encoded data, i.e. the 'alphabet'. Each value
+ // is the number of bits following the code that encode the difference to the
+ // last pixel. Valid values are in the range 0..16.
+ // signExtended() is used to decode the difference bits to a signed int.
+ std::vector<uchar8> codeValues; // index is just sequential number
+
+public:
+ bool operator==(const HuffmanTable& other) const {
+ return nCodesPerLength == other.nCodesPerLength
+ && codeValues == other.codeValues;
+ }
+
+ uint32 setNCodesPerLength(const Buffer& data) {
+ assert(data.getSize() == 16);
+
+ nCodesPerLength.resize(17, 0);
+ std::copy(data.begin(), data.end(), &nCodesPerLength[1]);
+ assert(nCodesPerLength[0] == 0);
+
+ // trim empty entries from the codes per length table on the right
+ while (!nCodesPerLength.empty() && nCodesPerLength.back() == 0)
+ nCodesPerLength.pop_back();
+
+ if (nCodesPerLength.empty())
+ ThrowRDE("Codes-per-length table is empty");
+
+ assert(nCodesPerLength.back() > 0);
+
+ const auto count = maxCodesCount();
+ assert(count > 0);
+
+ if (count > 162)
+ ThrowRDE("Too big code-values table");
+
+ for (auto codeLen = 1U; codeLen < nCodesPerLength.size(); codeLen++) {
+ // we have codeLen bits. make sure that that code count can actually fit
+ const auto nCodes = nCodesPerLength[codeLen];
+ if (nCodes > ((1U << codeLen) - 1U)) {
+ ThrowRDE("Corrupt Huffman. Can not have %u codes in %u-bit len", nCodes,
+ codeLen);
+ }
+ }
+
+ return count;
+ }
+
+ void setCodeValues(const Buffer& data) {
+ // spec says max 16 but Hasselblad ignores that -> allow 17
+ // Canon's old CRW really ignores this ...
+ assert(data.getSize() <= 162);
+ assert(data.getSize() == maxCodesCount());
+
+ codeValues.clear();
+ codeValues.reserve(maxCodesCount());
+ std::copy(data.begin(), data.end(), std::back_inserter(codeValues));
+ assert(codeValues.size() == maxCodesCount());
+
+ for (const auto cValue : codeValues) {
+ if (cValue > 16)
+ ThrowRDE("Corrupt Huffman. Code value %u is bigger than 16", cValue);
+ }
+ }
+
+ void setup(bool fullDecode_, bool fixDNGBug16_) {
+ this->fullDecode = fullDecode_;
+ this->fixDNGBug16 = fixDNGBug16_;
+
+ // store the code lengths in bits, valid values are 0..16
+ std::vector<uchar8> code_len; // index is just sequential number
+ // store the codes themselfs (bit patterns found inside the stream)
+ std::vector<ushort16> codes; // index is just sequential number
+
+ assert(!nCodesPerLength.empty());
+ assert(maxCodesCount() > 0);
+
+ unsigned int maxCodeLength = nCodesPerLength.size() - 1U;
+ assert(codeValues.size() == maxCodesCount());
+
+ assert(maxCodePlusDiffLength() <= 32U);
+
+ // reserve all the memory. avoids lots of small allocs
+ code_len.reserve(maxCodesCount());
+ codes.reserve(maxCodesCount());
+
+ // Figure C.1: make table of Huffman code length for each symbol
+ // Figure C.2: generate the codes themselves
+ uint32 code = 0;
+ for (unsigned int l = 1; l <= maxCodeLength; ++l) {
+ assert(nCodesPerLength[l] <= ((1U << l) - 1U));
+
+ for (unsigned int i = 0; i < nCodesPerLength[l]; ++i) {
+ if (code > 0xffff) {
+ ThrowRDE("Corrupt Huffman: code value overflow on len = %u, %u-th "
+ "code out of %u\n",
+ l, i, nCodesPerLength[l]);
+ }
+
+ code_len.push_back(l);
+ codes.push_back(code);
+ code++;
+ }
+ code <<= 1;
+ }
+
+ assert(code_len.size() == maxCodesCount());
+ assert(codes.size() == maxCodesCount());
+
+ // Figure F.15: generate decoding tables
+ codeOffsetOL.resize(maxCodeLength + 1UL, 0xffff);
+ maxCodeOL.resize(maxCodeLength + 1UL);
+ int code_index = 0;
+ for (unsigned int l = 1U; l <= maxCodeLength; l++) {
+ if (nCodesPerLength[l]) {
+ codeOffsetOL[l] = codes[code_index] - code_index;
+ code_index += nCodesPerLength[l];
+ maxCodeOL[l] = codes[code_index - 1];
+ }
+ }
+
+ // Generate lookup table for fast decoding lookup.
+ // See definition of decodeLookup above
+ decodeLookup.resize(1 << LookupDepth);
+ for (size_t i = 0; i < codes.size(); i++) {
+ uchar8 code_l = code_len[i];
+ if (code_l > static_cast<int>(LookupDepth))
+ break;
+
+ ushort16 ll = codes[i] << (LookupDepth - code_l);
+ ushort16 ul = ll | ((1 << (LookupDepth - code_l)) - 1);
+ ushort16 diff_l = codeValues[i];
+ for (ushort16 c = ll; c <= ul; c++) {
+ if (!(c < decodeLookup.size()))
+ ThrowRDE("Corrupt Huffman");
+
+ if (!FlagMask || !fullDecode || diff_l + code_l > LookupDepth) {
+ // lookup bit depth is too small to fit both the encoded length
+ // and the final difference value.
+ // -> store only the length and do a normal sign extension later
+ decodeLookup[c] = diff_l << PayloadShift | code_l;
+ } else {
+ // diff_l + code_l <= lookupDepth
+ // The table bit depth is large enough to store both.
+ decodeLookup[c] = (code_l + diff_l) | FlagMask;
+
+ if (diff_l) {
+ uint32 diff = (c >> (LookupDepth - code_l - diff_l)) & ((1 << diff_l) - 1);
+ decodeLookup[c] |= static_cast<uint32>(signExtended(diff, diff_l))
+ << PayloadShift;
+ }
+ }
+ }
+ }
+ }
+
+ // WARNING: the caller should check that len != 0 before calling the function
+ inline static int __attribute__((const))
+ signExtended(uint32 diff, uint32 len) {
+ int32 ret = diff;
+#if 0
+#define _X(x) (1<<x)-1
+ constexpr static int offset[16] = {
+ 0, _X(1), _X(2), _X(3), _X(4), _X(5), _X(6), _X(7),
+ _X(8), _X(9), _X(10), _X(11), _X(12), _X(13), _X(14), _X(15)};
+#undef _X
+ if ((diff & (1 << (len - 1))) == 0)
+ ret -= offset[len];
+#else
+ if ((diff & (1 << (len - 1))) == 0)
+ ret -= (1 << len) - 1;
+#endif
+ return ret;
+ }
+
+ template<typename BIT_STREAM> inline int decodeLength(BIT_STREAM& bs) const {
+ assert(!fullDecode);
+ return decode<BIT_STREAM, false>(bs);
+ }
+
+ template<typename BIT_STREAM> inline int decodeNext(BIT_STREAM& bs) const {
+ assert(fullDecode);
+ return decode<BIT_STREAM, true>(bs);
+ }
+
+ // The bool template paraeter is to enable two versions:
+ // one returning only the length of the of diff bits (see Hasselblad),
+ // one to return the fully decoded diff.
+ // All ifs depending on this bool will be optimized out by the compiler
+ template<typename BIT_STREAM, bool FULL_DECODE> inline int decode(BIT_STREAM& bs) const {
+ assert(FULL_DECODE == fullDecode);
+
+ // 32 is the absolute maximum combined length of code + diff
+ // assertion maxCodePlusDiffLength() <= 32U is already checked in setup()
+ bs.fill(32);
+
+ // for processors supporting bmi2 instructions, using maxCodePlusDiffLength()
+ // might be benifitial
+
+ uint32 code = bs.peekBitsNoFill(LookupDepth);
+ assert(code < decodeLookup.size());
+ int val = decodeLookup[code];
+ int len = val & LenMask;
+ assert(len >= 0);
+ assert(len <= 16);
+
+ // if the code is invalid (bitstream corrupted) len will be 0
+ bs.skipBitsNoFill(len);
+ if (FULL_DECODE && val & FlagMask) {
+ // if the flag bit is set, the payload is the already sign extended difference
+ return val >> PayloadShift;
+ }
+
+ if (len) {
+ // if the flag bit is not set but len != 0, the payload is the number of bits to sign extend and return
+ const int l_diff = val >> PayloadShift;
+ assert((FULL_DECODE && (len + l_diff <= 32)) || !FULL_DECODE);
+ return FULL_DECODE ? signExtended(bs.getBitsNoFill(l_diff), l_diff) : l_diff;
+ }
+
+ uint32 code_l = LookupDepth;
+ bs.skipBitsNoFill(code_l);
+ while (code_l < maxCodeOL.size() && code > maxCodeOL[code_l]) {
+ uint32 temp = bs.getBitsNoFill(1);
+ code = (code << 1) | temp;
+ code_l++;
+ }
+
+ if (code_l >= maxCodeOL.size() || code > maxCodeOL[code_l])
+ ThrowRDE("bad Huffman code: %u (len: %u)", code, code_l);
+
+ if (code < codeOffsetOL[code_l])
+ ThrowRDE("likely corrupt Huffman code: %u (len: %u)", code, code_l);
+
+ int diff_l = codeValues[code - codeOffsetOL[code_l]];
+
+ if (!FULL_DECODE)
+ return diff_l;
+
+ if (diff_l == 16) {
+ if (fixDNGBug16)
+ bs.skipBits(16);
+ return -32768;
+ }
+
+ assert(FULL_DECODE);
+ assert((diff_l && (len + code_l + diff_l <= 32)) || !diff_l);
+ return diff_l ? signExtended(bs.getBitsNoFill(diff_l), diff_l) : 0;
+ }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/JpegDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/JpegDecompressor.cpp
new file mode 100644
index 000000000..63d56b50d
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/JpegDecompressor.cpp
@@ -0,0 +1,168 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h"
+
+#ifdef HAVE_JPEG
+
+#include "decompressors/JpegDecompressor.h"
+
+#include "common/Common.h" // for uchar8, uint32, ushort16
+#include "common/Memory.h" // for alignedFree, alignedMalloc...
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "io/ByteStream.h" // for ByteStream
+#include <algorithm> // for min
+#include <cstdio> // for size_t
+#include <jpeglib.h> // for jpeg
+#include <memory> // for unique_ptr
+#include <vector> // for vector
+
+#ifndef HAVE_JPEG_MEM_SRC
+#include "io/IOException.h" // for ThrowIOE
+#endif
+
+using std::vector;
+using std::unique_ptr;
+using std::min;
+
+namespace rawspeed {
+
+#ifdef HAVE_JPEG_MEM_SRC
+
+// FIXME: some libjpeg versions discard const qual for the input data pointer
+// should this be a cmake check?
+#define JPEG_MEMSRC(A, B, C) \
+ jpeg_mem_src(A, const_cast<unsigned char*>(B), C) // NOLINT
+
+#else
+
+#define JPEG_MEMSRC(A, B, C) jpeg_mem_src_int(A, B, C)
+/* Read JPEG image from a memory segment */
+
+static void init_source(j_decompress_ptr cinfo) {}
+static boolean fill_input_buffer(j_decompress_ptr cinfo) {
+ auto* src = (struct jpeg_source_mgr*)cinfo->src;
+ return (boolean) !!src->bytes_in_buffer;
+}
+static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
+ auto* src = (struct jpeg_source_mgr*)cinfo->src;
+
+ if (num_bytes > (int)src->bytes_in_buffer)
+ ThrowIOE("read out of buffer");
+ if (num_bytes > 0) {
+ src->next_input_byte += (size_t)num_bytes;
+ src->bytes_in_buffer -= (size_t)num_bytes;
+ }
+}
+static void term_source(j_decompress_ptr cinfo) {}
+static void jpeg_mem_src_int(j_decompress_ptr cinfo,
+ const unsigned char* buffer, long nbytes) {
+ struct jpeg_source_mgr* src;
+
+ if (cinfo->src == nullptr) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr*)(*cinfo->mem->alloc_small)(
+ (j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(struct jpeg_source_mgr));
+ }
+
+ src = (struct jpeg_source_mgr*)cinfo->src;
+ src->init_source = init_source;
+ src->fill_input_buffer = fill_input_buffer;
+ src->skip_input_data = skip_input_data;
+ src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->term_source = term_source;
+ src->bytes_in_buffer = nbytes;
+ src->next_input_byte = (const JOCTET*)buffer;
+}
+
+#endif
+
+[[noreturn]] METHODDEF(void) my_error_throw(j_common_ptr cinfo) {
+ char buf[JMSG_LENGTH_MAX] = {0};
+ (*cinfo->err->format_message)(cinfo, buf);
+ ThrowRDE("JPEG decoder error: %s", buf);
+}
+
+struct JpegDecompressor::JpegDecompressStruct : jpeg_decompress_struct {
+ struct jpeg_error_mgr jerr;
+ JpegDecompressStruct() {
+ jpeg_create_decompress(this);
+
+ err = jpeg_std_error(&jerr);
+ jerr.error_exit = &my_error_throw;
+ }
+ ~JpegDecompressStruct() { jpeg_destroy_decompress(this); }
+};
+
+void JpegDecompressor::decode(uint32 offX,
+ uint32 offY) { /* Each slice is a JPEG image */
+ struct JpegDecompressStruct dinfo;
+
+ vector<JSAMPROW> buffer(1);
+
+ const auto size = input.getRemainSize();
+
+ JPEG_MEMSRC(&dinfo, input.getData(size), size);
+
+ if (JPEG_HEADER_OK != jpeg_read_header(&dinfo, static_cast<boolean>(true)))
+ ThrowRDE("Unable to read JPEG header");
+
+ jpeg_start_decompress(&dinfo);
+ if (dinfo.output_components != static_cast<int>(mRaw->getCpp()))
+ ThrowRDE("Component count doesn't match");
+ int row_stride = dinfo.output_width * dinfo.output_components;
+
+ unique_ptr<uchar8[], decltype(&alignedFree)> complete_buffer(
+ alignedMallocArray<uchar8, 16>(dinfo.output_height, row_stride),
+ &alignedFree);
+ while (dinfo.output_scanline < dinfo.output_height) {
+ buffer[0] = static_cast<JSAMPROW>(
+ &complete_buffer[static_cast<size_t>(dinfo.output_scanline) *
+ row_stride]);
+ if (0 == jpeg_read_scanlines(&dinfo, &buffer[0], 1))
+ ThrowRDE("JPEG Error while decompressing image.");
+ }
+ jpeg_finish_decompress(&dinfo);
+
+ // Now the image is decoded, and we copy the image data
+ int copy_w = min(mRaw->dim.x - offX, dinfo.output_width);
+ int copy_h = min(mRaw->dim.y - offY, dinfo.output_height);
+ for (int y = 0; y < copy_h; y++) {
+ uchar8* src = &complete_buffer[static_cast<size_t>(row_stride) * y];
+ auto* dst = reinterpret_cast<ushort16*>(mRaw->getData(offX, y + offY));
+ for (int x = 0; x < copy_w; x++) {
+ for (int c = 0; c < dinfo.output_components; c++) {
+ *dst = *src;
+ src++;
+ dst++;
+ }
+ }
+ }
+}
+
+} // namespace rawspeed
+
+#else
+
+#pragma message \
+ "JPEG is not present! Lossy JPEG compression will not be supported!"
+
+#endif
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/JpegDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/JpegDecompressor.h
new file mode 100644
index 000000000..ed1ddfd27
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/JpegDecompressor.h
@@ -0,0 +1,58 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h"
+
+#ifdef HAVE_JPEG
+
+#include "common/Common.h" // for uint32
+#include "common/RawImage.h" // for RawImage
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+#include "io/Buffer.h" // for Buffer, Buffer::size_type
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for getHostEndianness
+#include <utility> // for move
+
+namespace rawspeed {
+
+class JpegDecompressor final : public AbstractDecompressor {
+ struct JpegDecompressStruct;
+ ByteStream input;
+ RawImage mRaw;
+
+public:
+ JpegDecompressor(ByteStream bs, const RawImage& img)
+ : input(std::move(bs)), mRaw(img) {
+ input.setByteOrder(Endianness::big);
+ }
+
+ void decode(uint32 offsetX, uint32 offsetY);
+};
+
+} // namespace rawspeed
+
+#else
+
+#pragma message \
+ "JPEG is not present! Lossy JPEG compression will not be supported!"
+
+#endif
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/KodakDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/KodakDecompressor.cpp
new file mode 100644
index 000000000..b7bf29d95
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/KodakDecompressor.cpp
@@ -0,0 +1,139 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h"
+#include "decompressors/KodakDecompressor.h"
+#include "common/RawImage.h" // for RawImage
+#include "decoders/RawDecoderException.h" // for RawDecoderException (ptr o...
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/ByteStream.h" // for ByteStream
+#include <algorithm> // for min
+#include <array> // for array
+#include <cassert> // for assert
+
+namespace rawspeed {
+
+constexpr int KodakDecompressor::segment_size;
+
+KodakDecompressor::KodakDecompressor(const RawImage& img, ByteStream bs,
+ bool uncorrectedRawValues_)
+ : mRaw(img), input(std::move(bs)),
+ uncorrectedRawValues(uncorrectedRawValues_) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ if (mRaw->dim.x == 0 || mRaw->dim.y == 0 || mRaw->dim.x % 4 != 0 ||
+ mRaw->dim.x > 4516 || mRaw->dim.y > 3012)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x,
+ mRaw->dim.y);
+
+ // Lower estimate: this decompressor requires *at least* half a byte
+ // per output pixel
+ input.check(mRaw->dim.area() / 2ULL);
+}
+
+KodakDecompressor::segment
+KodakDecompressor::decodeSegment(const uint32 bsize) {
+ assert(bsize > 0);
+ assert(bsize % 4 == 0);
+ assert(bsize <= segment_size);
+
+ segment out;
+ static_assert(out.size() == segment_size, "Wrong segment size");
+
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+ // We are to produce only bsize pixels.
+ __sanitizer_annotate_contiguous_container(out.begin(), out.end(), out.end(),
+ out.begin() + bsize);
+#endif
+
+ std::array<uchar8, 2 * segment_size> blen;
+ uint64 bitbuf = 0;
+ uint32 bits = 0;
+
+ for (uint32 i = 0; i < bsize; i += 2) {
+ // One byte per two pixels
+ blen[i] = input.peekByte() & 15;
+ blen[i + 1] = input.getByte() >> 4;
+ }
+ if ((bsize & 7) == 4) {
+ bitbuf = (static_cast<uint64>(input.getByte())) << 8UL;
+ bitbuf += (static_cast<int>(input.getByte()));
+ bits = 16;
+ }
+ for (uint32 i = 0; i < bsize; i++) {
+ uint32 len = blen[i];
+
+ if (bits < len) {
+ for (uint32 j = 0; j < 32; j += 8) {
+ bitbuf += static_cast<long long>(static_cast<int>(input.getByte()))
+ << (bits + (j ^ 8));
+ }
+ bits += 32;
+ }
+
+ uint32 diff = static_cast<uint32>(bitbuf) & (0xffff >> (16 - len));
+ bitbuf >>= len;
+ bits -= len;
+ diff = len != 0 ? HuffmanTable::signExtended(diff, len) : diff;
+
+ out[i] = diff;
+ }
+
+ return out;
+}
+
+void KodakDecompressor::decompress() {
+ uchar8* data = mRaw->getData();
+ uint32 pitch = mRaw->pitch;
+
+ uint32 random = 0;
+ for (auto y = 0; y < mRaw->dim.y; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
+
+ for (auto x = 0; x < mRaw->dim.x; x += segment_size) {
+ const uint32 len = std::min(segment_size, mRaw->dim.x - x);
+
+ const segment buf = decodeSegment(len);
+
+ std::array<uint32, 2> pred;
+ pred.fill(0);
+
+ for (uint32 i = 0; i < len; i++) {
+ pred[i & 1] += buf[i];
+
+ ushort16 value = pred[i & 1];
+ if (value > 1023)
+ ThrowRDE("Value out of bounds %d", value);
+
+ if (uncorrectedRawValues)
+ dest[x + i] = value;
+ else
+ mRaw->setWithLookUp(value, reinterpret_cast<uchar8*>(&dest[x + i]),
+ &random);
+ }
+ }
+ }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/KodakDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/KodakDecompressor.h
new file mode 100644
index 000000000..9b89edc12
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/KodakDecompressor.h
@@ -0,0 +1,50 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for ushort16
+#include "common/RawImage.h" // for RawImage
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+#include "io/ByteStream.h" // for ByteStream
+#include <array> // for array
+
+namespace rawspeed {
+
+class KodakDecompressor final : public AbstractDecompressor {
+ RawImage mRaw;
+ ByteStream input;
+ bool uncorrectedRawValues;
+
+ static constexpr int segment_size = 256; // pixels
+ using segment = std::array<ushort16, segment_size>;
+
+ segment decodeSegment(uint32 bsize);
+
+public:
+ KodakDecompressor(const RawImage& img, ByteStream bs,
+ bool uncorrectedRawValues_);
+
+ void decompress();
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/LJpegDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/LJpegDecompressor.cpp
new file mode 100644
index 000000000..8f85417a6
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/LJpegDecompressor.cpp
@@ -0,0 +1,158 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/LJpegDecompressor.h"
+#include "common/Common.h" // for uint32, unroll_loop, ushort16
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "io/BitPumpJPEG.h" // for BitPumpJPEG
+#include <algorithm> // for min, copy_n
+
+using std::copy_n;
+
+namespace rawspeed {
+
+LJpegDecompressor::LJpegDecompressor(const ByteStream& bs, const RawImage& img)
+ : AbstractLJpegDecompressor(bs, img) {
+ if (mRaw->getDataType() != TYPE_USHORT16)
+ ThrowRDE("Unexpected data type (%u)", mRaw->getDataType());
+
+ if (!((mRaw->getCpp() == 1 && mRaw->getBpp() == 2) ||
+ (mRaw->getCpp() == 3 && mRaw->getBpp() == 6)))
+ ThrowRDE("Unexpected component count (%u)", mRaw->getCpp());
+
+ if (mRaw->dim.x == 0 || mRaw->dim.y == 0)
+ ThrowRDE("Image has zero size");
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+ // Yeah, sure, here it would be just dumb to leave this for production :)
+ if (mRaw->dim.x > 7424 || mRaw->dim.y > 5552) {
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x,
+ mRaw->dim.y);
+ }
+#endif
+}
+
+void LJpegDecompressor::decode(uint32 offsetX, uint32 offsetY, uint32 width,
+ uint32 height, bool fixDng16Bug_) {
+ if (offsetX >= static_cast<unsigned>(mRaw->dim.x))
+ ThrowRDE("X offset outside of image");
+ if (offsetY >= static_cast<unsigned>(mRaw->dim.y))
+ ThrowRDE("Y offset outside of image");
+
+ offX = offsetX;
+ offY = offsetY;
+ w = width;
+ h = height;
+
+ fixDng16Bug = fixDng16Bug_;
+
+ AbstractLJpegDecompressor::decode();
+}
+
+void LJpegDecompressor::decodeScan()
+{
+ if (predictorMode != 1)
+ ThrowRDE("Unsupported predictor mode: %u", predictorMode);
+
+ for (uint32 i = 0; i < frame.cps; i++)
+ if (frame.compInfo[i].superH != 1 || frame.compInfo[i].superV != 1)
+ ThrowRDE("Unsupported subsampling");
+
+ assert(static_cast<unsigned>(mRaw->dim.x) > offX);
+ if ((mRaw->getCpp() * (mRaw->dim.x - offX)) < frame.cps)
+ ThrowRDE("Got less pixels than the components per sample");
+
+ const auto frameWidth = frame.cps * frame.w;
+ if (frameWidth < w || frame.h < h) {
+ ThrowRDE("LJpeg frame (%u, %u) is smaller than expected (%u, %u)",
+ frameWidth, frame.h, w, h);
+ }
+
+ switch (frame.cps) {
+ case 2:
+ decodeN<2>();
+ break;
+ case 3:
+ decodeN<3>();
+ break;
+ case 4:
+ decodeN<4>();
+ break;
+ default:
+ ThrowRDE("Unsupported number of components: %u", frame.cps);
+ }
+}
+
+// N_COMP == number of components (2, 3 or 4)
+
+template <int N_COMP>
+void LJpegDecompressor::decodeN()
+{
+ assert(mRaw->getCpp() > 0);
+ assert(N_COMP > 0);
+ assert(N_COMP >= mRaw->getCpp());
+ assert((N_COMP / mRaw->getCpp()) > 0);
+
+ assert(mRaw->dim.x >= N_COMP);
+ assert((mRaw->getCpp() * (mRaw->dim.x - offX)) >= N_COMP);
+
+ auto ht = getHuffmanTables<N_COMP>();
+ auto pred = getInitialPredictors<N_COMP>();
+ auto predNext = pred.data();
+
+ BitPumpJPEG bitStream(input);
+
+ // A recoded DNG might be split up into tiles of self contained LJpeg blobs.
+ // The tiles at the bottom and the right may extend beyond the dimension of
+ // the raw image buffer. The excessive content has to be ignored.
+
+ // For y, we can simply stop decoding when we reached the border.
+ for (unsigned y = 0; y < std::min(frame.h, std::min(h, mRaw->dim.y - offY));
+ ++y) {
+ auto destY = offY + y;
+ auto dest =
+ reinterpret_cast<ushort16*>(mRaw->getDataUncropped(offX, destY));
+
+ copy_n(predNext, N_COMP, pred.data());
+ // the predictor for the next line is the start of this line
+ predNext = dest;
+
+ unsigned width = std::min(
+ frame.w, (mRaw->getCpp() * std::min(w, mRaw->dim.x - offX)) / N_COMP);
+
+ // For x, we first process all pixels within the image buffer ...
+ for (unsigned x = 0; x < width; ++x) {
+ unroll_loop<N_COMP>([&](int i) {
+ *dest++ = pred[i] += ht[i]->decodeNext(bitStream);
+ });
+ }
+ // ... and discard the rest.
+ for (unsigned x = width; x < frame.w; ++x) {
+ unroll_loop<N_COMP>([&](int i) {
+ ht[i]->decodeNext(bitStream);
+ });
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/LJpegDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/LJpegDecompressor.h
new file mode 100644
index 000000000..8183067b5
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/LJpegDecompressor.h
@@ -0,0 +1,51 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "decompressors/AbstractLJpegDecompressor.h" // for AbstractLJpegDe...
+#include "io/Buffer.h" // for Buffer, Buffer:...
+#include "io/ByteStream.h" // for ByteStream
+
+namespace rawspeed {
+
+class RawImage;
+
+// Decompresses Lossless JPEGs, with 2-4 components
+
+class LJpegDecompressor final : public AbstractLJpegDecompressor
+{
+ void decodeScan() override;
+ template<int N_COMP> void decodeN();
+
+ uint32 offX = 0;
+ uint32 offY = 0;
+ uint32 w = 0;
+ uint32 h = 0;
+
+public:
+ LJpegDecompressor(const ByteStream& bs, const RawImage& img);
+
+ void decode(uint32 offsetX, uint32 offsetY, uint32 width, uint32 height,
+ bool fixDng16Bug);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp
new file mode 100644
index 000000000..d472985af
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.cpp
@@ -0,0 +1,220 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/NikonDecompressor.h"
+#include "common/Common.h" // for uint32, ushort16, clampBits
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData, RawI...
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/BitPumpMSB.h" // for BitPumpMSB, BitStream<>::fil...
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include <cstdio> // for size_t, NULL
+#include <vector> // for vector, allocator
+
+namespace rawspeed {
+
+const uchar8 NikonDecompressor::nikon_tree[][2][16] = {
+ {/* 12-bit lossy */
+ {0, 1, 5, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0},
+ {5, 4, 3, 6, 2, 7, 1, 0, 8, 9, 11, 10, 12}},
+ {/* 12-bit lossy after split */
+ {0, 1, 5, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0},
+ {0x39, 0x5a, 0x38, 0x27, 0x16, 5, 4, 3, 2, 1, 0, 11, 12, 12}},
+ {/* 12-bit lossless */
+ {0, 1, 4, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {5, 4, 6, 3, 7, 2, 8, 1, 9, 0, 10, 11, 12}},
+ {/* 14-bit lossy */
+ {0, 1, 4, 3, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0},
+ {5, 6, 4, 7, 8, 3, 9, 2, 1, 0, 10, 11, 12, 13, 14}},
+ {/* 14-bit lossy after split */
+ {0, 1, 5, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0},
+ {8, 0x5c, 0x4b, 0x3a, 0x29, 7, 6, 5, 4, 3, 2, 1, 0, 13, 14}},
+ {/* 14-bit lossless */
+ {0, 1, 4, 2, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0},
+ {7, 6, 8, 5, 9, 4, 10, 3, 11, 12, 2, 0, 1, 13, 14}},
+
+};
+
+std::vector<ushort16> NikonDecompressor::createCurve(ByteStream* metadata,
+ uint32 bitsPS, uint32 v0,
+ uint32 v1, uint32* split) {
+ // 'curve' will hold a peace wise linearly interpolated function.
+ // there are 'csize' segements, each is 'step' values long.
+ // the very last value is not part of the used table but necessary
+ // to linearly interpolate the last segment, therefor the '+1/-1'
+ // size adjustments of 'curve'.
+ std::vector<ushort16> curve((1 << bitsPS & 0x7fff) + 1);
+ assert(curve.size() > 1);
+
+ for (size_t i = 0; i < curve.size(); i++)
+ curve[i] = i;
+
+ uint32 step = 0;
+ uint32 csize = metadata->getU16();
+ if (csize > 1)
+ step = curve.size() / (csize - 1);
+
+ if (v0 == 68 && v1 == 32 && step > 0) {
+ if ((csize - 1) * step != curve.size() - 1)
+ ThrowRDE("Bad curve segment count (%u)", csize);
+
+ for (size_t i = 0; i < csize; i++)
+ curve[i * step] = metadata->getU16();
+ for (size_t i = 0; i < curve.size() - 1; i++) {
+ const uint32 b_scale = i % step;
+
+ const uint32 a_pos = i - b_scale;
+ const uint32 b_pos = a_pos + step;
+ assert(a_pos < curve.size());
+ assert(b_pos > 0);
+ assert(b_pos < curve.size());
+ assert(a_pos < b_pos);
+
+ const uint32 a_scale = step - b_scale;
+ curve[i] = (a_scale * curve[a_pos] + b_scale * curve[b_pos]) / step;
+ }
+
+ metadata->setPosition(562);
+ *split = metadata->getU16();
+ } else if (v0 != 70) {
+ if (csize == 0 || csize > 0x4001)
+ ThrowRDE("Don't know how to compute curve! csize = %u", csize);
+
+ curve.resize(csize + 1UL);
+ assert(curve.size() > 1);
+
+ for (uint32 i = 0; i < csize; i++) {
+ curve[i] = metadata->getU16();
+ }
+ }
+
+ // and drop the last value
+ curve.resize(curve.size() - 1);
+ assert(!curve.empty());
+
+ return curve;
+}
+
+HuffmanTable NikonDecompressor::createHuffmanTable(uint32 huffSelect) {
+ HuffmanTable ht;
+ uint32 count = ht.setNCodesPerLength(Buffer(nikon_tree[huffSelect][0], 16));
+ ht.setCodeValues(Buffer(nikon_tree[huffSelect][1], count));
+ ht.setup(true, false);
+ return ht;
+}
+
+NikonDecompressor::NikonDecompressor(const RawImage& raw, uint32 bitsPS_)
+ : mRaw(raw), bitsPS(bitsPS_) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ if (mRaw->dim.x == 0 || mRaw->dim.y == 0 || mRaw->dim.x % 2 != 0 ||
+ mRaw->dim.x > 8288 || mRaw->dim.y > 5520)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x,
+ mRaw->dim.y);
+
+ switch (bitsPS) {
+ case 12:
+ case 14:
+ break;
+ default:
+ ThrowRDE("Invalid bpp found: %u", bitsPS);
+ }
+}
+
+void NikonDecompressor::decompress(ByteStream metadata, const ByteStream& data,
+ bool uncorrectedRawValues) {
+ const iPoint2D& size = mRaw->dim;
+
+ uint32 v0 = metadata.getByte();
+ uint32 v1 = metadata.getByte();
+ uint32 huffSelect = 0;
+ uint32 split = 0;
+ int pUp1[2];
+ int pUp2[2];
+
+ writeLog(DEBUG_PRIO_EXTRA, "Nef version v0:%u, v1:%u", v0, v1);
+
+ if (v0 == 73 || v1 == 88)
+ metadata.skipBytes(2110);
+
+ if (v0 == 70)
+ huffSelect = 2;
+ if (bitsPS == 14)
+ huffSelect += 3;
+
+ pUp1[0] = metadata.getU16();
+ pUp1[1] = metadata.getU16();
+ pUp2[0] = metadata.getU16();
+ pUp2[1] = metadata.getU16();
+
+ HuffmanTable ht = createHuffmanTable(huffSelect);
+
+ auto curve = createCurve(&metadata, bitsPS, v0, v1, &split);
+ RawImageCurveGuard curveHandler(&mRaw, curve, uncorrectedRawValues);
+
+ BitPumpMSB bits(data);
+ uchar8* draw = mRaw->getData();
+ uint32 pitch = mRaw->pitch;
+
+ int pLeft1 = 0;
+ int pLeft2 = 0;
+ uint32 random = bits.peekBits(24);
+ //allow gcc to devirtualize the calls below
+ auto* rawdata = reinterpret_cast<RawImageDataU16*>(mRaw.get());
+
+ assert(size.x % 2 == 0);
+ assert(size.x >= 2);
+ for (uint32 y = 0; y < static_cast<unsigned>(size.y); y++) {
+ if (split && y == split) {
+ ht = createHuffmanTable(huffSelect + 1);
+ }
+ auto* dest =
+ reinterpret_cast<ushort16*>(&draw[y * pitch]); // Adjust destination
+ pUp1[y&1] += ht.decodeNext(bits);
+ pUp2[y&1] += ht.decodeNext(bits);
+ pLeft1 = pUp1[y&1];
+ pLeft2 = pUp2[y&1];
+
+ rawdata->setWithLookUp(clampBits(pLeft1, 15),
+ reinterpret_cast<uchar8*>(dest + 0), &random);
+ rawdata->setWithLookUp(clampBits(pLeft2, 15),
+ reinterpret_cast<uchar8*>(dest + 1), &random);
+
+ dest += 2;
+
+ for (uint32 x = 2; x < static_cast<uint32>(size.x); x += 2) {
+ pLeft1 += ht.decodeNext(bits);
+ pLeft2 += ht.decodeNext(bits);
+
+ rawdata->setWithLookUp(clampBits(pLeft1, 15),
+ reinterpret_cast<uchar8*>(dest + 0), &random);
+ rawdata->setWithLookUp(clampBits(pLeft2, 15),
+ reinterpret_cast<uchar8*>(dest + 1), &random);
+
+ dest += 2;
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.h
new file mode 100644
index 000000000..6fde227a5
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/NikonDecompressor.h
@@ -0,0 +1,55 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "common/RawImage.h" // for RawImage
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class iPoint2D;
+
+class RawImage;
+
+class ByteStream;
+
+class HuffmanTable;
+
+class NikonDecompressor final : public AbstractDecompressor {
+ RawImage mRaw;
+ uint32 bitsPS;
+
+public:
+ NikonDecompressor(const RawImage& raw, uint32 bitsPS);
+
+ void decompress(ByteStream metadata, const ByteStream& data,
+ bool uncorrectedRawValues);
+
+private:
+ static const uchar8 nikon_tree[][2][16];
+ static std::vector<ushort16> createCurve(ByteStream* metadata, uint32 bitsPS,
+ uint32 v0, uint32 v1, uint32* split);
+ static HuffmanTable createHuffmanTable(uint32 huffSelect);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/OlympusDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/OlympusDecompressor.cpp
new file mode 100644
index 000000000..670c7d200
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/OlympusDecompressor.cpp
@@ -0,0 +1,220 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014-2015 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/OlympusDecompressor.h"
+#include "common/Common.h" // for uchar8
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/AbstractDecompressor.h" // for RawDecom...
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/BitPumpMSB.h" // for BitPumpMSB
+#include <algorithm> // for move
+#include <algorithm> // for min
+#include <array> // for array
+#include <cmath> // for signbit
+#include <cstdlib> // for abs
+#include <memory> // for unique_ptr
+
+namespace rawspeed {
+
+OlympusDecompressor::OlympusDecompressor(const RawImage& img) : mRaw(img) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ const uint32 w = mRaw->dim.x;
+ const uint32 h = mRaw->dim.y;
+
+ if (w == 0 || h == 0 || w % 2 != 0 || w > 10400 || h > 7792)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", w, h);
+}
+
+/* This is probably the slowest decoder of them all.
+ * I cannot see any way to effectively speed up the prediction
+ * phase, which is by far the slowest part of this algorithm.
+ * Also there is no way to multithread this code, since prediction
+ * is based on the output of all previous pixel (bar the first four)
+ */
+
+void OlympusDecompressor::decompress(ByteStream input) const {
+ assert(mRaw->dim.y > 0);
+ assert(mRaw->dim.x > 0);
+ assert(mRaw->dim.x % 2 == 0);
+
+ int nbits;
+ int sign;
+ int low;
+ int high;
+ int i;
+ std::array<int, 2> left{{}};
+ std::array<int, 2> nw{{}};
+ int pred;
+ int diff;
+
+ uchar8* data = mRaw->getData();
+ int pitch = mRaw->pitch;
+
+ /* Build a table to quickly look up "high" value */
+ std::unique_ptr<char[]> bittable(new char[4096]);
+
+ for (i = 0; i < 4096; i++) {
+ int b = i;
+ for (high = 0; high < 12; high++)
+ if ((b >> (11 - high)) & 1)
+ break;
+ bittable[i] = std::min(12, high);
+ }
+
+ input.skipBytes(7);
+ BitPumpMSB bits(input);
+
+ for (uint32 y = 0; y < static_cast<uint32>(mRaw->dim.y); y++) {
+ std::array<std::array<int, 3>, 2> acarry{{}};
+
+ auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
+ bool y_border = y < 2;
+ bool border = true;
+ for (uint32 x = 0; x < static_cast<uint32>(mRaw->dim.x); x++) {
+ int c = 0;
+
+ bits.fill();
+ i = 2 * (acarry[c][2] < 3);
+ for (nbits = 2 + i; static_cast<ushort16>(acarry[c][0]) >> (nbits + i);
+ nbits++)
+ ;
+
+ int b = bits.peekBitsNoFill(15);
+ sign = (b >> 14) * -1;
+ low = (b >> 12) & 3;
+ high = bittable[b & 4095];
+
+ // Skip bytes used above or read bits
+ if (high == 12) {
+ bits.skipBitsNoFill(15);
+ high = bits.getBits(16 - nbits) >> 1;
+ } else
+ bits.skipBitsNoFill(high + 1 + 3);
+
+ acarry[c][0] = (high << nbits) | bits.getBits(nbits);
+ diff = (acarry[c][0] ^ sign) + acarry[c][1];
+ acarry[c][1] = (diff * 3 + acarry[c][1]) >> 5;
+ acarry[c][2] = acarry[c][0] > 16 ? 0 : acarry[c][2] + 1;
+
+ if (border) {
+ if (y_border && x < 2)
+ pred = 0;
+ else {
+ if (y_border)
+ pred = left[c];
+ else {
+ pred = dest[-pitch + (static_cast<int>(x))];
+ nw[c] = pred;
+ }
+ }
+ dest[x] = pred + ((diff * 4) | low);
+ // Set predictor
+ left[c] = dest[x];
+ } else {
+ // Have local variables for values used several tiles
+ // (having a "ushort16 *dst_up" that caches dest[-pitch+((int)x)] is
+ // actually slower, probably stack spill or aliasing)
+ int up = dest[-pitch + (static_cast<int>(x))];
+ int leftMinusNw = left[c] - nw[c];
+ int upMinusNw = up - nw[c];
+ // Check if sign is different, and they are both not zero
+ if ((std::signbit(leftMinusNw) ^ std::signbit(upMinusNw)) &&
+ (leftMinusNw != 0 && upMinusNw != 0)) {
+ if (std::abs(leftMinusNw) > 32 || std::abs(upMinusNw) > 32)
+ pred = left[c] + upMinusNw;
+ else
+ pred = (left[c] + up) >> 1;
+ } else
+ pred = std::abs(leftMinusNw) > std::abs(upMinusNw) ? left[c] : up;
+
+ dest[x] = pred + ((diff * 4) | low);
+ // Set predictors
+ left[c] = dest[x];
+ nw[c] = up;
+ }
+
+ // ODD PIXELS
+ x += 1;
+ c = 1;
+ bits.fill();
+ i = 2 * (acarry[c][2] < 3);
+ for (nbits = 2 + i; static_cast<ushort16>(acarry[c][0]) >> (nbits + i);
+ nbits++)
+ ;
+ b = bits.peekBitsNoFill(15);
+ sign = (b >> 14) * -1;
+ low = (b >> 12) & 3;
+ high = bittable[b & 4095];
+
+ // Skip bytes used above or read bits
+ if (high == 12) {
+ bits.skipBitsNoFill(15);
+ high = bits.getBits(16 - nbits) >> 1;
+ } else
+ bits.skipBitsNoFill(high + 1 + 3);
+
+ acarry[c][0] = (high << nbits) | bits.getBits(nbits);
+ diff = (acarry[c][0] ^ sign) + acarry[c][1];
+ acarry[c][1] = (diff * 3 + acarry[c][1]) >> 5;
+ acarry[c][2] = acarry[c][0] > 16 ? 0 : acarry[c][2] + 1;
+
+ if (border) {
+ if (y_border && x < 2)
+ pred = 0;
+ else {
+ if (y_border)
+ pred = left[c];
+ else {
+ pred = dest[-pitch + (static_cast<int>(x))];
+ nw[c] = pred;
+ }
+ }
+ dest[x] = left[c] = pred + ((diff * 4) | low);
+ } else {
+ int up = dest[-pitch + (static_cast<int>(x))];
+ int leftMinusNw = left[c] - nw[c];
+ int upMinusNw = up - nw[c];
+
+ // Check if sign is different, and they are both not zero
+ if ((std::signbit(leftMinusNw) ^ std::signbit(upMinusNw)) &&
+ (leftMinusNw != 0 && upMinusNw != 0)) {
+ if (std::abs(leftMinusNw) > 32 || std::abs(upMinusNw) > 32)
+ pred = left[c] + upMinusNw;
+ else
+ pred = (left[c] + up) >> 1;
+ } else
+ pred = std::abs(leftMinusNw) > std::abs(upMinusNw) ? left[c] : up;
+
+ dest[x] = left[c] = pred + ((diff * 4) | low);
+ nw[c] = up;
+ }
+ border = y_border;
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/OlympusDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/OlympusDecompressor.h
new file mode 100644
index 000000000..bb9ebc1b6
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/OlympusDecompressor.h
@@ -0,0 +1,39 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+#include "io/ByteStream.h" // for ByteStream
+
+namespace rawspeed {
+
+class RawImage;
+
+class OlympusDecompressor final : public AbstractDecompressor {
+ RawImage mRaw;
+
+public:
+ explicit OlympusDecompressor(const RawImage& img);
+ void decompress(ByteStream input) const;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/PanasonicDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/PanasonicDecompressor.cpp
new file mode 100644
index 000000000..b45c85612
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/PanasonicDecompressor.cpp
@@ -0,0 +1,167 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/PanasonicDecompressor.h"
+#include "common/Mutex.h" // for MutexLocker
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include <algorithm> // for min, move
+#include <cstring> // for memcpy
+#include <vector> // for vector
+
+namespace rawspeed {
+
+PanasonicDecompressor::PanasonicDecompressor(const RawImage& img,
+ const ByteStream& input_,
+ bool zero_is_not_bad,
+ uint32 load_flags_)
+ : AbstractParallelizedDecompressor(img), zero_is_bad(!zero_is_not_bad),
+ load_flags(load_flags_) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ const uint32 width = mRaw->dim.x;
+ const uint32 height = mRaw->dim.y;
+
+ if (width == 0 || height == 0 || width % 14 != 0 || width > 5488 ||
+ height > 3904)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ if (BufSize < load_flags)
+ ThrowRDE("Bad load_flags: %u, less than BufSize (%u)", load_flags, BufSize);
+
+ // Naive count of bytes that given pixel count requires.
+ const auto rawBytesNormal = 8U * mRaw->dim.area() / 7U;
+ // If load_flags is zero, than that size is the size we need to read.
+ // But if it is not, then we need to round up to multiple of BufSize, because
+ // of splitting&rotation of each BufSize's slice in half at load_flags bytes.
+ const auto bufSize =
+ load_flags == 0 ? rawBytesNormal : roundUp(rawBytesNormal, BufSize);
+ input = input_.peekStream(bufSize);
+}
+
+struct PanasonicDecompressor::PanaBitpump {
+ ByteStream input;
+ std::vector<uchar8> buf;
+ int vbits = 0;
+ uint32 load_flags;
+
+ PanaBitpump(ByteStream input_, int load_flags_)
+ : input(std::move(input_)), load_flags(load_flags_) {
+ // get one more byte, so the return statement of getBits does not have
+ // to special case for accessing the last byte
+ buf.resize(BufSize + 1UL);
+ }
+
+ void skipBytes(int bytes) {
+ int blocks = (bytes / BufSize) * BufSize;
+ input.skipBytes(blocks);
+ for (int i = blocks; i < bytes; i++)
+ (void)getBits(8);
+ }
+
+ uint32 getBits(int nbits) {
+ if (!vbits) {
+ /* On truncated files this routine will just return just for the truncated
+ * part of the file. Since there is no chance of affecting output buffer
+ * size we allow the decoder to decode this
+ */
+ assert(BufSize >= load_flags);
+ auto size = std::min(input.getRemainSize(), BufSize - load_flags);
+ memcpy(buf.data() + load_flags, input.getData(size), size);
+
+ size = std::min(input.getRemainSize(), load_flags);
+ if (size != 0)
+ memcpy(buf.data(), input.getData(size), size);
+ }
+ vbits = (vbits - nbits) & 0x1ffff;
+ int byte = vbits >> 3 ^ 0x3ff0;
+ return (buf[byte] | buf[byte + 1UL] << 8) >> (vbits & 7) & ~(-(1 << nbits));
+ }
+};
+
+void PanasonicDecompressor::decompressThreaded(
+ const RawDecompressorThread* t) const {
+ PanaBitpump bits(input, load_flags);
+
+ /* 9 + 1/7 bits per pixel */
+ bits.skipBytes(8 * mRaw->dim.x * t->start / 7);
+
+ assert(mRaw->dim.x % 14 == 0);
+ const auto blocks = mRaw->dim.x / 14;
+
+ std::vector<uint32> zero_pos;
+ for (uint32 y = t->start; y < t->end; y++) {
+ int sh = 0;
+
+ auto* dest = reinterpret_cast<ushort16*>(mRaw->getData(0, y));
+ for (int block = 0; block < blocks; block++) {
+ std::array<int, 2> pred;
+ pred.fill(0);
+
+ std::array<int, 2> nonz;
+ nonz.fill(0);
+
+ int u = 0;
+
+ for (int x = 0; x < 14; x++) {
+ const int c = x & 1;
+
+ if (u == 2) {
+ sh = 4 >> (3 - bits.getBits(2));
+ u = -1;
+ }
+
+ if (nonz[c]) {
+ int j = bits.getBits(8);
+ if (j) {
+ pred[c] -= 0x80 << sh;
+ if (pred[c] < 0 || sh == 4)
+ pred[c] &= ~(-(1 << sh));
+ pred[c] += j << sh;
+ }
+ } else {
+ nonz[c] = bits.getBits(8);
+ if (nonz[c] || x > 11)
+ pred[c] = nonz[c] << 4 | bits.getBits(4);
+ }
+
+ *dest = pred[c];
+
+ if (zero_is_bad && 0 == pred[c])
+ zero_pos.push_back((y << 16) | (14 * block + x));
+
+ u++;
+ dest++;
+ }
+ }
+ }
+
+ if (zero_is_bad && !zero_pos.empty()) {
+ MutexLocker guard(&mRaw->mBadPixelMutex);
+ mRaw->mBadPixelPositions.insert(mRaw->mBadPixelPositions.end(),
+ zero_pos.begin(), zero_pos.end());
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/PanasonicDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/PanasonicDecompressor.h
new file mode 100644
index 000000000..27480d489
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/PanasonicDecompressor.h
@@ -0,0 +1,53 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "decompressors/AbstractParallelizedDecompressor.h" // for Abstract...
+#include "io/ByteStream.h" // for ByteStream
+
+namespace rawspeed {
+
+class RawImage;
+
+class PanasonicDecompressor final : public AbstractParallelizedDecompressor {
+ static constexpr uint32 BufSize = 0x4000;
+ struct PanaBitpump;
+
+ void decompressThreaded(const RawDecompressorThread* t) const final;
+
+ ByteStream input;
+ bool zero_is_bad;
+
+ // The RW2 raw image buffer is split into sections of BufSize bytes.
+ // If load_flags is 0, then last section is not nessesairly full.
+ // If load_flags is not 0, then each section has two parts:
+ // bytes: [0..load_flags-1][load_flags..BufSize-1]
+ // pixels: [a..b][0..a-1]
+ // I.e. these two parts need to be swapped around.
+ uint32 load_flags;
+
+public:
+ PanasonicDecompressor(const RawImage& img, const ByteStream& input_,
+ bool zero_is_not_bad, uint32 load_flags_);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/PentaxDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/PentaxDecompressor.cpp
new file mode 100644
index 000000000..14aa4740e
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/PentaxDecompressor.cpp
@@ -0,0 +1,176 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/PentaxDecompressor.h"
+#include "common/Common.h" // for uint32, uchar8, ushort16
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/BitPumpMSB.h" // for BitPumpMSB, BitStream<>::f...
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include "tiff/TiffEntry.h" // for TiffEntry, ::TIFF_UNDEFINED
+#include "tiff/TiffIFD.h" // for TiffIFD
+#include "tiff/TiffTag.h" // for TiffTag
+#include <cassert> // for assert
+#include <vector> // for vector, allocator
+
+namespace rawspeed {
+
+// 16 entries of codes per bit length
+// 13 entries of code values
+const uchar8 PentaxDecompressor::pentax_tree[][2][16] = {
+ {{0, 2, 3, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0},
+ {3, 4, 2, 5, 1, 6, 0, 7, 8, 9, 10, 11, 12}},
+};
+
+PentaxDecompressor::PentaxDecompressor(const RawImage& img,
+ ByteStream* metaData)
+ : mRaw(img), ht(SetupHuffmanTable(metaData)) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ if (!mRaw->dim.x || !mRaw->dim.y || mRaw->dim.x % 2 != 0 ||
+ mRaw->dim.x > 7392 || mRaw->dim.y > 4950) {
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x,
+ mRaw->dim.y);
+ }
+}
+
+HuffmanTable PentaxDecompressor::SetupHuffmanTable_Legacy() {
+ HuffmanTable ht;
+
+ /* Initialize with legacy data */
+ auto nCodes = ht.setNCodesPerLength(Buffer(pentax_tree[0][0], 16));
+ assert(nCodes == 13); // see pentax_tree definition
+ ht.setCodeValues(Buffer(pentax_tree[0][1], nCodes));
+
+ return ht;
+}
+
+HuffmanTable PentaxDecompressor::SetupHuffmanTable_Modern(ByteStream stream) {
+ HuffmanTable ht;
+
+ const uint32 depth = stream.getU16() + 12;
+ if (depth > 15)
+ ThrowRDE("Depth of huffman table is too great (%u).", depth);
+
+ stream.skipBytes(12);
+
+ uint32 v0[16];
+ uint32 v1[16];
+ for (uint32 i = 0; i < depth; i++)
+ v0[i] = stream.getU16();
+ for (uint32 i = 0; i < depth; i++) {
+ v1[i] = stream.getByte();
+
+ if (v1[i] == 0 || v1[i] > 12)
+ ThrowRDE("Data corrupt: v1[%i]=%i, expected [1..12]", depth, v1[i]);
+ }
+
+ std::vector<uchar8> nCodesPerLength;
+ nCodesPerLength.resize(17);
+
+ uint32 v2[16];
+ /* Calculate codes and store bitcounts */
+ for (uint32 c = 0; c < depth; c++) {
+ v2[c] = v0[c] >> (12 - v1[c]);
+ nCodesPerLength.at(v1[c])++;
+ }
+
+ assert(nCodesPerLength.size() == 17);
+ assert(nCodesPerLength[0] == 0);
+ auto nCodes = ht.setNCodesPerLength(Buffer(&nCodesPerLength[1], 16));
+ assert(nCodes == depth);
+
+ std::vector<uchar8> codeValues;
+ codeValues.reserve(nCodes);
+
+ /* Find smallest */
+ for (uint32 i = 0; i < depth; i++) {
+ uint32 sm_val = 0xfffffff;
+ uint32 sm_num = 0xff;
+ for (uint32 j = 0; j < depth; j++) {
+ if (v2[j] <= sm_val) {
+ sm_num = j;
+ sm_val = v2[j];
+ }
+ }
+ codeValues.push_back(sm_num);
+ v2[sm_num] = 0xffffffff;
+ }
+
+ assert(codeValues.size() == nCodes);
+ ht.setCodeValues(Buffer(codeValues.data(), nCodes));
+
+ return ht;
+}
+
+HuffmanTable PentaxDecompressor::SetupHuffmanTable(ByteStream* metaData) {
+ HuffmanTable ht;
+
+ if (metaData)
+ ht = SetupHuffmanTable_Modern(*metaData);
+ else
+ ht = SetupHuffmanTable_Legacy();
+
+ ht.setup(true, false);
+
+ return ht;
+}
+
+void PentaxDecompressor::decompress(const ByteStream& data) const {
+ BitPumpMSB bs(data);
+ uchar8* draw = mRaw->getData();
+
+ assert(mRaw->dim.y > 0);
+ assert(mRaw->dim.x > 0);
+ assert(mRaw->dim.x % 2 == 0);
+
+ int pUp1[2] = {0, 0};
+ int pUp2[2] = {0, 0};
+
+ for (int y = 0; y < mRaw->dim.y && mRaw->dim.x >= 2; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(&draw[y * mRaw->pitch]);
+
+ pUp1[y & 1] += ht.decodeNext(bs);
+ pUp2[y & 1] += ht.decodeNext(bs);
+
+ int pLeft1 = dest[0] = pUp1[y & 1];
+ int pLeft2 = dest[1] = pUp2[y & 1];
+
+ for (int x = 2; x < mRaw->dim.x; x += 2) {
+ pLeft1 += ht.decodeNext(bs);
+ pLeft2 += ht.decodeNext(bs);
+
+ dest[x] = pLeft1;
+ dest[x + 1] = pLeft2;
+
+ if (pLeft1 < 0 || pLeft1 > 65535)
+ ThrowRDE("decoded value out of bounds at %d:%d", x, y);
+ if (pLeft2 < 0 || pLeft2 > 65535)
+ ThrowRDE("decoded value out of bounds at %d:%d", x, y);
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/PentaxDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/PentaxDecompressor.h
new file mode 100644
index 000000000..76c5b84b3
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/PentaxDecompressor.h
@@ -0,0 +1,52 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+
+namespace rawspeed {
+
+class ByteStream;
+
+class TiffIFD;
+
+class PentaxDecompressor final : public AbstractDecompressor {
+ RawImage mRaw;
+ const HuffmanTable ht;
+
+public:
+ PentaxDecompressor(const RawImage& img, ByteStream* metaData);
+
+ void decompress(const ByteStream& data) const;
+
+private:
+ static HuffmanTable SetupHuffmanTable_Legacy();
+ static HuffmanTable SetupHuffmanTable_Modern(ByteStream stream);
+ static HuffmanTable SetupHuffmanTable(ByteStream* metaData);
+
+ static const uchar8 pentax_tree[][2][16];
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/SamsungV0Decompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV0Decompressor.cpp
new file mode 100644
index 000000000..da31936bb
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV0Decompressor.cpp
@@ -0,0 +1,225 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2010 Klaus Post
+ Copyright (C) 2014-2015 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/SamsungV0Decompressor.h"
+#include "common/Common.h" // for ushort16, uint32, int32
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "io/BitPumpMSB32.h" // for BitPumpMSB32
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness, Endianness::li...
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffIFD.h" // for TiffIFD
+#include "tiff/TiffTag.h" // for TiffTag, TiffTag::IMAGELENGTH
+#include <algorithm> // for max
+#include <cassert> // for assert
+#include <iterator> // for advance, begin, end, next
+#include <vector> // for vector
+
+namespace rawspeed {
+
+SamsungV0Decompressor::SamsungV0Decompressor(const RawImage& image,
+ const ByteStream& bso,
+ const ByteStream& bsr)
+ : AbstractSamsungDecompressor(image) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ const uint32 width = mRaw->dim.x;
+ const uint32 height = mRaw->dim.y;
+
+ if (width == 0 || height == 0 || width < 16 || width > 5546 || height > 3714)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ computeStripes(bso.peekStream(height, 4), bsr);
+}
+
+// FIXME: this is very close to IiqDecoder::computeSripes()
+void SamsungV0Decompressor::computeStripes(ByteStream bso, ByteStream bsr) {
+ const uint32 height = mRaw->dim.y;
+
+ std::vector<uint32> offsets;
+ offsets.reserve(1 + height);
+ for (uint32 y = 0; y < height; y++)
+ offsets.emplace_back(bso.getU32());
+ offsets.emplace_back(bsr.getSize());
+
+ stripes.reserve(height);
+
+ auto offset_iterator = std::begin(offsets);
+ bsr.skipBytes(*offset_iterator);
+
+ auto next_offset_iterator = std::next(offset_iterator);
+ while (next_offset_iterator < std::end(offsets)) {
+ if (*offset_iterator >= *next_offset_iterator)
+ ThrowRDE("Line offsets are out of sequence or slice is empty.");
+
+ const auto size = *next_offset_iterator - *offset_iterator;
+ assert(size > 0);
+
+ stripes.emplace_back(bsr.getStream(size));
+
+ std::advance(offset_iterator, 1);
+ std::advance(next_offset_iterator, 1);
+ }
+
+ assert(stripes.size() == height);
+}
+
+void SamsungV0Decompressor::decompress() const {
+ for (int y = 0; y < mRaw->dim.y; y++)
+ decompressStrip(y, stripes[y]);
+
+ // Swap red and blue pixels to get the final CFA pattern
+ for (int y = 0; y < mRaw->dim.y - 1; y += 2) {
+ auto* topline = reinterpret_cast<ushort16*>(mRaw->getData(0, y));
+ auto* bottomline = reinterpret_cast<ushort16*>(mRaw->getData(0, y + 1));
+
+ for (int x = 0; x < mRaw->dim.x - 1; x += 2) {
+ ushort16 temp = topline[1];
+ topline[1] = bottomline[0];
+ bottomline[0] = temp;
+
+ topline += 2;
+ bottomline += 2;
+ }
+ }
+}
+
+int32 SamsungV0Decompressor::calcAdj(BitPumpMSB32* bits, int b) {
+ int32 adj = 0;
+ if (b)
+ adj = (static_cast<int32>(bits->getBits(b)) << (32 - b) >> (32 - b));
+ return adj;
+}
+
+void SamsungV0Decompressor::decompressStrip(uint32 y,
+ const ByteStream& bs) const {
+ const uint32 width = mRaw->dim.x;
+ assert(width > 0);
+
+ BitPumpMSB32 bits(bs);
+
+ int len[4];
+ for (int& i : len)
+ i = y < 2 ? 7 : 4;
+
+ auto* img = reinterpret_cast<ushort16*>(mRaw->getData(0, y));
+ const auto* const past_last =
+ reinterpret_cast<ushort16*>(mRaw->getData(width - 1, y) + mRaw->getBpp());
+ ushort16* img_up = reinterpret_cast<ushort16*>(
+ mRaw->getData(0, std::max(0, static_cast<int>(y) - 1)));
+ ushort16* img_up2 = reinterpret_cast<ushort16*>(
+ mRaw->getData(0, std::max(0, static_cast<int>(y) - 2)));
+
+ // Image is arranged in groups of 16 pixels horizontally
+ for (uint32 x = 0; x < width; x += 16) {
+ bits.fill();
+ bool dir = !!bits.getBitsNoFill(1);
+
+ int op[4];
+ for (int& i : op)
+ i = bits.getBitsNoFill(2);
+
+ for (int i = 0; i < 4; i++) {
+ assert(op[i] >= 0 && op[i] <= 3);
+
+ switch (op[i]) {
+ case 3:
+ len[i] = bits.getBits(4);
+ break;
+ case 2:
+ len[i]--;
+ break;
+ case 1:
+ len[i]++;
+ break;
+ default:
+ // FIXME: it can be zero too.
+ break;
+ }
+
+ if (len[i] < 0)
+ ThrowRDE("Bit length less than 0.");
+ if (len[i] > 16)
+ ThrowRDE("Bit Length more than 16.");
+ }
+
+ if (dir) {
+ // Upward prediction
+
+ if (y < 2)
+ ThrowRDE("Upward prediction for the first two rows. Raw corrupt");
+
+ if (x + 16 >= width)
+ ThrowRDE("Upward prediction for the last block of pixels. Raw corrupt");
+
+ // First we decode even pixels
+ for (int c = 0; c < 16; c += 2) {
+ int b = len[c >> 3];
+ int32 adj = calcAdj(&bits, b);
+
+ img[c] = adj + img_up[c];
+ }
+
+ // Now we decode odd pixels
+ // Why on earth upward prediction only looks up 1 line above
+ // is beyond me, it will hurt compression a deal.
+ for (int c = 1; c < 16; c += 2) {
+ int b = len[2 | (c >> 3)];
+ int32 adj = calcAdj(&bits, b);
+
+ img[c] = adj + img_up2[c];
+ }
+ } else {
+ // Left to right prediction
+ // First we decode even pixels
+ int pred_left = x != 0 ? img[-2] : 128;
+ for (int c = 0; c < 16; c += 2) {
+ int b = len[c >> 3];
+ int32 adj = calcAdj(&bits, b);
+
+ if (img + c < past_last)
+ img[c] = adj + pred_left;
+ }
+
+ // Now we decode odd pixels
+ pred_left = x != 0 ? img[-1] : 128;
+ for (int c = 1; c < 16; c += 2) {
+ int b = len[2 | (c >> 3)];
+ int32 adj = calcAdj(&bits, b);
+
+ if (img + c < past_last)
+ img[c] = adj + pred_left;
+ }
+ }
+
+ img += 16;
+ img_up += 16;
+ img_up2 += 16;
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/SamsungV0Decompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV0Decompressor.h
new file mode 100644
index 000000000..da840ee7b
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV0Decompressor.h
@@ -0,0 +1,52 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for int32, uint32
+#include "decompressors/AbstractSamsungDecompressor.h" // for AbstractSamsu...
+#include "io/BitPumpMSB32.h" // for BitPumpMSB32
+#include "io/ByteStream.h" // for ByteStream
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class Buffer;
+class RawImage;
+class TiffIFD;
+
+// Decoder for compressed srw files (NX300 and later)
+class SamsungV0Decompressor final : public AbstractSamsungDecompressor {
+ std::vector<ByteStream> stripes;
+
+ void computeStripes(ByteStream bso, ByteStream bsr);
+
+ void decompressStrip(uint32 y, const ByteStream& bs) const;
+
+ static int32 calcAdj(BitPumpMSB32* bits, int b);
+
+public:
+ SamsungV0Decompressor(const RawImage& image, const ByteStream& bso,
+ const ByteStream& bsr);
+
+ void decompress() const;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/SamsungV1Decompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV1Decompressor.cpp
new file mode 100644
index 000000000..47e4fa285
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV1Decompressor.cpp
@@ -0,0 +1,126 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2010 Klaus Post
+ Copyright (C) 2014-2015 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/SamsungV1Decompressor.h"
+#include "common/Common.h" // for uint32, ushort16, int32
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/BitPumpMSB.h" // for BitPumpMSB
+#include <memory> // for allocator_traits<>::value_...
+#include <vector> // for vector
+
+namespace rawspeed {
+
+struct SamsungV1Decompressor::encTableItem {
+ uchar8 encLen;
+ uchar8 diffLen;
+};
+
+SamsungV1Decompressor::SamsungV1Decompressor(const RawImage& image,
+ const ByteStream* bs_, int bit)
+ : AbstractSamsungDecompressor(image), bs(bs_), bits(bit) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ switch (bit) {
+ case 12:
+ break;
+ default:
+ ThrowRDE("Unexpected bit per pixel (%u)", bit);
+ }
+
+ const uint32 width = mRaw->dim.x;
+ const uint32 height = mRaw->dim.y;
+
+ if (width == 0 || height == 0 || width > 5664 || height > 3714)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+}
+
+int32 SamsungV1Decompressor::samsungDiff(BitPumpMSB* pump,
+ const std::vector<encTableItem>& tbl) {
+ // We read 10 bits to index into our table
+ uint32 c = pump->peekBits(10);
+ // Skip the bits that were used to encode this case
+ pump->getBits(tbl[c].encLen);
+ // Read the number of bits the table tells me
+ int32 len = tbl[c].diffLen;
+ int32 diff = pump->getBits(len);
+
+ // If the first bit is 0 we need to turn this into a negative number
+ diff = len != 0 ? HuffmanTable::signExtended(diff, len) : diff;
+
+ return diff;
+}
+
+void SamsungV1Decompressor::decompress() {
+ const uint32 width = mRaw->dim.x;
+ const uint32 height = mRaw->dim.y;
+
+ // This format has a variable length encoding of how many bits are needed
+ // to encode the difference between pixels, we use a table to process it
+ // that has two values, the first the number of bits that were used to
+ // encode, the second the number of bits that come after with the difference
+ // The table has 14 entries because the difference can have between 0 (no
+ // difference) and 13 bits (differences between 12 bits numbers can need 13)
+ const uchar8 tab[14][2] = {{3, 4}, {3, 7}, {2, 6}, {2, 5}, {4, 3},
+ {6, 0}, {7, 9}, {8, 10}, {9, 11}, {10, 12},
+ {10, 13}, {5, 1}, {4, 8}, {4, 2}};
+ std::vector<encTableItem> tbl(1024);
+ ushort16 vpred[2][2] = {{0, 0}, {0, 0}};
+ ushort16 hpred[2];
+
+ // We generate a 1024 entry table (to be addressed by reading 10 bits) by
+ // consecutively filling in 2^(10-N) positions where N is the variable number
+ // of bits of the encoding. So for example 4 is encoded with 3 bits so the
+ // first 2^(10-3)=128 positions are set with 3,4 so that any time we read 000
+ // we know the next 4 bits are the difference. We read 10 bits because that is
+ // the maximum number of bits used in the variable encoding (for the 12 and
+ // 13 cases)
+ uint32 n = 0;
+ for (auto i : tab) {
+ for (int32 c = 0; c < (1024 >> i[0]); c++) {
+ tbl[n].encLen = i[0];
+ tbl[n].diffLen = i[1];
+ n++;
+ }
+ }
+
+ BitPumpMSB pump(*bs);
+ for (uint32 y = 0; y < height; y++) {
+ auto* img = reinterpret_cast<ushort16*>(mRaw->getData(0, y));
+ for (uint32 x = 0; x < width; x++) {
+ int32 diff = samsungDiff(&pump, tbl);
+ if (x < 2)
+ hpred[x] = vpred[y & 1][x] += diff;
+ else
+ hpred[x & 1] += diff;
+ img[x] = hpred[x & 1];
+ if (img[x] >> bits)
+ ThrowRDE("decoded value out of bounds at %d:%d", x, y);
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/SamsungV1Decompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV1Decompressor.h
new file mode 100644
index 000000000..bc6f95a94
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV1Decompressor.h
@@ -0,0 +1,48 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for int32
+#include "decompressors/AbstractSamsungDecompressor.h" // for AbstractSamsu...
+#include "io/BitPumpMSB.h" // for BitPumpMSB
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class ByteStream;
+class RawImage;
+
+// Decoder for compressed srw files (NX3000 and later)
+class SamsungV1Decompressor final : public AbstractSamsungDecompressor {
+ struct encTableItem;
+ static int32 samsungDiff(BitPumpMSB* pump,
+ const std::vector<encTableItem>& tbl);
+
+ const ByteStream* bs;
+ int bits;
+
+public:
+ SamsungV1Decompressor(const RawImage& image, const ByteStream* bs_, int bit);
+
+ void decompress();
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/SamsungV2Decompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV2Decompressor.cpp
new file mode 100644
index 000000000..49b3a33e3
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV2Decompressor.cpp
@@ -0,0 +1,342 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2010 Klaus Post
+ Copyright (C) 2014-2015 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/SamsungV2Decompressor.h"
+#include "common/Common.h" // for uint32, ushort16, int32
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "io/BitPumpMSB32.h" // for BitPumpMSB32
+#include "io/ByteStream.h" // for ByteStream
+#include <algorithm> // for max
+#include <cassert> // for assert
+#include <type_traits> // for underlying_type, underlyin...
+
+namespace rawspeed {
+
+// Seriously Samsung just use lossless jpeg already, it compresses better too :)
+
+// Thanks to Michael Reichmann (Luminous Landscape) for putting Pedro Côrte-Real
+// in contact and Loring von Palleske (Samsung) for pointing to the open-source
+// code of Samsung's DNG converter at http://opensource.samsung.com/
+
+enum struct SamsungV2Decompressor::OptFlags : uint32 {
+ NONE = 0U, // no flags
+ SKIP = 1U << 0U, // Skip checking if we need differences from previous line
+ MV = 1U << 1U, // Simplify motion vector definition
+ QP = 1U << 2U, // Don't scale the diff values
+
+ // all possible flags
+ ALL = SKIP | MV | QP,
+};
+
+constexpr SamsungV2Decompressor::OptFlags
+operator|(SamsungV2Decompressor::OptFlags lhs,
+ SamsungV2Decompressor::OptFlags rhs) {
+ return static_cast<SamsungV2Decompressor::OptFlags>(
+ static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
+ lhs) |
+ static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
+ rhs));
+}
+
+constexpr bool operator&(SamsungV2Decompressor::OptFlags lhs,
+ SamsungV2Decompressor::OptFlags rhs) {
+ return SamsungV2Decompressor::OptFlags::NONE !=
+ static_cast<SamsungV2Decompressor::OptFlags>(
+ static_cast<
+ std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
+ lhs) &
+ static_cast<
+ std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
+ rhs));
+}
+
+SamsungV2Decompressor::SamsungV2Decompressor(const RawImage& image,
+ const ByteStream& bs, int bit)
+ : AbstractSamsungDecompressor(image), bits(bit) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ switch (bit) {
+ case 12:
+ case 14:
+ break;
+ default:
+ ThrowRDE("Unexpected bit per pixel (%u)", bit);
+ }
+
+ static constexpr const auto headerSize = 16;
+ bs.check(headerSize);
+
+ BitPumpMSB32 startpump(bs);
+
+ // Process the initial metadata bits, we only really use initVal, width and
+ // height (the last two match the TIFF values anyway)
+ startpump.getBits(16); // NLCVersion
+ startpump.getBits(4); // ImgFormat
+ bitDepth = startpump.getBits(4) + 1;
+ startpump.getBits(4); // NumBlkInRCUnit
+ startpump.getBits(4); // CompressionRatio
+ width = startpump.getBits(16);
+ height = startpump.getBits(16);
+ startpump.getBits(16); // TileWidth
+ startpump.getBits(4); // reserved
+
+ // The format includes an optimization code that sets 3 flags to change the
+ // decoding parameters
+ const uint32 optflags = startpump.getBits(4);
+ if (optflags > static_cast<uint32>(OptFlags::ALL))
+ ThrowRDE("Invalid opt flags %x", optflags);
+ _flags = static_cast<OptFlags>(optflags);
+
+ startpump.getBits(8); // OverlapWidth
+ startpump.getBits(8); // reserved
+ startpump.getBits(8); // Inc
+ startpump.getBits(2); // reserved
+ initVal = startpump.getBits(14);
+
+ assert(startpump.getPosition() == headerSize);
+
+ if (width == 0 || height == 0 || width % 16 != 0 || width > 6496 ||
+ height > 4336)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", width, height);
+
+ if (width != static_cast<uint32>(mRaw->dim.x) ||
+ height != static_cast<uint32>(mRaw->dim.y))
+ ThrowRDE("EXIF image dimensions do not match dimensions from raw header");
+
+ data = startpump.getStream(startpump.getRemainSize());
+}
+
+void SamsungV2Decompressor::decompress() {
+ switch (_flags) {
+ case OptFlags::NONE:
+ for (uint32 row = 0; row < height; row++)
+ decompressRow<OptFlags::NONE>(row);
+ break;
+ case OptFlags::ALL:
+ for (uint32 row = 0; row < height; row++)
+ decompressRow<OptFlags::ALL>(row);
+ break;
+
+ case OptFlags::SKIP:
+ for (uint32 row = 0; row < height; row++)
+ decompressRow<OptFlags::SKIP>(row);
+ break;
+ case OptFlags::MV:
+ for (uint32 row = 0; row < height; row++)
+ decompressRow<OptFlags::MV>(row);
+ break;
+ case OptFlags::QP:
+ for (uint32 row = 0; row < height; row++)
+ decompressRow<OptFlags::QP>(row);
+ break;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wswitch"
+ case OptFlags::SKIP | OptFlags::MV:
+ for (uint32 row = 0; row < height; row++)
+ decompressRow<OptFlags::SKIP | OptFlags::MV>(row);
+ break;
+ case OptFlags::SKIP | OptFlags::QP:
+ for (uint32 row = 0; row < height; row++)
+ decompressRow<OptFlags::SKIP | OptFlags::QP>(row);
+ break;
+
+ case OptFlags::MV | OptFlags::QP:
+ for (uint32 row = 0; row < height; row++)
+ decompressRow<OptFlags::MV | OptFlags::QP>(row);
+ break;
+#pragma GCC diagnostic pop
+
+ default:
+ __builtin_unreachable();
+ }
+}
+
+// The format is relatively straightforward. Each line gets encoded as a set
+// of differences from pixels from another line. Pixels are grouped in blocks
+// of 16 (8 green, 8 red or blue). Each block is encoded in three sections.
+// First 1 or 4 bits to specify which reference pixels to use, then a section
+// that specifies for each pixel the number of bits in the difference, then
+// the actual difference bits
+
+template <SamsungV2Decompressor::OptFlags optflags>
+void SamsungV2Decompressor::decompressRow(uint32 row) {
+ // Align pump to 16byte boundary
+ const auto line_offset = data.getPosition();
+ if ((line_offset & 0xf) != 0)
+ data.skipBytes(16 - (line_offset & 0xf));
+
+ BitPumpMSB32 pump(data);
+
+ auto* img = reinterpret_cast<ushort16*>(mRaw->getData(0, row));
+ ushort16* img_up = reinterpret_cast<ushort16*>(
+ mRaw->getData(0, std::max(0, static_cast<int>(row) - 1)));
+ ushort16* img_up2 = reinterpret_cast<ushort16*>(
+ mRaw->getData(0, std::max(0, static_cast<int>(row) - 2)));
+
+ // Initialize the motion and diff modes at the start of the line
+ uint32 motion = 7;
+ // By default we are not scaling values at all
+ int32 scale = 0;
+
+ uint32 diffBitsMode[3][2] = {{0}};
+ for (auto& i : diffBitsMode)
+ i[0] = i[1] = (row == 0 || row == 1) ? 7 : 4;
+
+ assert(width >= 16);
+ assert(width % 16 == 0);
+ for (uint32 col = 0; col < width; col += 16) {
+ if (!(optflags & OptFlags::QP) && !(col & 63)) {
+ static constexpr int32 scalevals[] = {0, -2, 2};
+ uint32 i = pump.getBits(2);
+ scale = i < 3 ? scale + scalevals[i] : pump.getBits(12);
+ }
+
+ // First we figure out which reference pixels mode we're in
+ if (optflags & OptFlags::MV)
+ motion = pump.getBits(1) ? 3 : 7;
+ else if (!pump.getBits(1))
+ motion = pump.getBits(3);
+
+ if ((row == 0 || row == 1) && (motion != 7))
+ ThrowRDE("At start of image and motion isn't 7. File corrupted?");
+
+ if (motion == 7) {
+ // The base case, just set all pixels to the previous ones on the same
+ // line If we're at the left edge we just start at the initial value
+ for (uint32 i = 0; i < 16; i++)
+ img[i] = (col == 0) ? initVal : *(img + i - 2);
+ } else {
+ // The complex case, we now need to actually lookup one or two lines
+ // above
+ if (row < 2)
+ ThrowRDE(
+ "Got a previous line lookup on first two lines. File corrupted?");
+
+ static constexpr int32 motionOffset[7] = {-4, -2, -2, 0, 0, 2, 4};
+ static constexpr int32 motionDoAverage[7] = {0, 0, 1, 0, 1, 0, 0};
+
+ int32 slideOffset = motionOffset[motion];
+ int32 doAverage = motionDoAverage[motion];
+
+ for (uint32 i = 0; i < 16; i++) {
+ ushort16* line;
+ ushort16* refpixel;
+
+ if ((row + i) & 0x1) {
+ // Red or blue pixels use same color two lines up
+ line = img_up2;
+ refpixel = line + i + slideOffset;
+ } else {
+ // Green pixel N uses Green pixel N from row above
+ // (top left or top right)
+ line = img_up;
+ refpixel = line + i + slideOffset + (((i % 2) != 0) ? -1 : 1);
+ }
+
+ if (col == 0 && line > refpixel)
+ ThrowRDE("Bad motion %u at the beginning of the row", motion);
+ if (col + 16 == width && ((refpixel >= line + 16) ||
+ (doAverage && (refpixel + 2 >= line + 16))))
+ ThrowRDE("Bad motion %u at the end of the row", motion);
+
+ // In some cases we use as reference interpolation of this pixel and
+ // the next
+ if (doAverage)
+ img[i] = (*refpixel + *(refpixel + 2) + 1) >> 1;
+ else
+ img[i] = *refpixel;
+ }
+ }
+
+ // Figure out how many difference bits we have to read for each pixel
+ uint32 diffBits[4] = {0};
+ if (optflags & OptFlags::SKIP || !pump.getBits(1)) {
+ uint32 flags[4];
+ for (unsigned int& flag : flags)
+ flag = pump.getBits(2);
+
+ for (uint32 i = 0; i < 4; i++) {
+ // The color is 0-Green 1-Blue 2-Red
+ uint32 colornum = (row % 2 != 0) ? i >> 1 : ((i >> 1) + 2) % 3;
+
+ assert(flags[i] <= 3);
+ switch (flags[i]) {
+ case 0:
+ diffBits[i] = diffBitsMode[colornum][0];
+ break;
+ case 1:
+ diffBits[i] = diffBitsMode[colornum][0] + 1;
+ break;
+ case 2:
+ if (diffBitsMode[colornum][0] == 0)
+ ThrowRDE("Difference bits underflow. File corrupted?");
+ diffBits[i] = diffBitsMode[colornum][0] - 1;
+ break;
+ case 3:
+ diffBits[i] = pump.getBits(4);
+ break;
+ default:
+ __builtin_unreachable();
+ }
+
+ diffBitsMode[colornum][0] = diffBitsMode[colornum][1];
+ diffBitsMode[colornum][1] = diffBits[i];
+
+ if (diffBits[i] > bitDepth + 1)
+ ThrowRDE("Too many difference bits. File corrupted?");
+ }
+ }
+
+ // Actually read the differences and write them to the pixels
+ for (uint32 i = 0; i < 16; i++) {
+ uint32 len = diffBits[i >> 2];
+ int32 diff = pump.getBits(len);
+
+ // If the first bit is 1 we need to turn this into a negative number
+ if (len != 0 && diff >> (len - 1))
+ diff -= (1 << len);
+
+ ushort16* value = nullptr;
+ // Apply the diff to pixels 0 2 4 6 8 10 12 14 1 3 5 7 9 11 13 15
+ if (row % 2)
+ value = &img[((i & 0x7) << 1) + 1 - (i >> 3)];
+ else
+ value = &img[((i & 0x7) << 1) + (i >> 3)];
+
+ diff = diff * (scale * 2 + 1) + scale;
+ *value = clampBits(static_cast<int>(*value) + diff, bits);
+ }
+
+ img += 16;
+ img_up += 16;
+ img_up2 += 16;
+ }
+
+ data.skipBytes(pump.getBufferPosition());
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/SamsungV2Decompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV2Decompressor.h
new file mode 100644
index 000000000..21bd7399a
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/SamsungV2Decompressor.h
@@ -0,0 +1,55 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "decompressors/AbstractSamsungDecompressor.h" // for AbstractSamsu...
+#include "io/ByteStream.h" // for ByteStream
+
+namespace rawspeed {
+
+class RawImage;
+
+// Decoder for third generation compressed SRW files (NX1)
+class SamsungV2Decompressor final : public AbstractSamsungDecompressor {
+public:
+ enum struct OptFlags : uint32;
+
+protected:
+ int bits;
+
+ uint32 bitDepth;
+ uint32 width;
+ uint32 height;
+ OptFlags _flags;
+ uint32 initVal;
+
+ ByteStream data;
+
+ template <OptFlags optflags> void decompressRow(uint32 row);
+
+public:
+ SamsungV2Decompressor(const RawImage& image, const ByteStream& bs, int bit);
+
+ void decompress();
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/SonyArw1Decompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/SonyArw1Decompressor.cpp
new file mode 100644
index 000000000..7328a3594
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/SonyArw1Decompressor.cpp
@@ -0,0 +1,89 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/SonyArw1Decompressor.h"
+#include "common/Common.h" // for uchar8
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "decompressors/AbstractDecompressor.h" // for RawDecom...
+#include "decompressors/HuffmanTable.h" // for HuffmanTable
+#include "io/BitPumpMSB.h" // for BitPumpMSB
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+SonyArw1Decompressor::SonyArw1Decompressor(const RawImage& img) : mRaw(img) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ const uint32 w = mRaw->dim.x;
+ const uint32 h = mRaw->dim.y;
+
+ if (w == 0 || h == 0 || h % 2 != 0 || w > 4600 || h > 3072)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", w, h);
+}
+
+void SonyArw1Decompressor::decompress(const ByteStream& input) const {
+ const uint32 w = mRaw->dim.x;
+ const uint32 h = mRaw->dim.y;
+
+ assert(w > 0);
+ assert(h > 0);
+ assert(h % 2 == 0);
+
+ BitPumpMSB bits(input);
+ uchar8* data = mRaw->getData();
+ auto* dest = reinterpret_cast<ushort16*>(&data[0]);
+ uint32 pitch = mRaw->pitch / sizeof(ushort16);
+ int sum = 0;
+ for (int64 x = w - 1; x >= 0; x--) {
+ for (uint32 y = 0; y < h + 1; y += 2) {
+ bits.fill();
+
+ if (y == h)
+ y = 1;
+
+ uint32 len = 4 - bits.getBitsNoFill(2);
+
+ if (len == 3 && bits.getBitsNoFill(1))
+ len = 0;
+
+ if (len == 4)
+ while (len < 17 && !bits.getBitsNoFill(1))
+ len++;
+
+ int diff = bits.getBits(len);
+ diff = len != 0 ? HuffmanTable::signExtended(diff, len) : diff;
+ sum += diff;
+
+ if (sum < 0 || (sum >> 12) > 0)
+ ThrowRDE("Error decompressing");
+
+ if (y < h)
+ dest[x + y * pitch] = sum;
+ }
+ }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/SonyArw1Decompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/SonyArw1Decompressor.h
new file mode 100644
index 000000000..67a158675
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/SonyArw1Decompressor.h
@@ -0,0 +1,39 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawImage.h" // for RawImage
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+#include "io/ByteStream.h" // for ByteStream
+
+namespace rawspeed {
+
+class RawImage;
+
+class SonyArw1Decompressor final : public AbstractDecompressor {
+ RawImage mRaw;
+
+public:
+ explicit SonyArw1Decompressor(const RawImage& img);
+ void decompress(const ByteStream& input) const;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/SonyArw2Decompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/SonyArw2Decompressor.cpp
new file mode 100644
index 000000000..231b23a72
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/SonyArw2Decompressor.cpp
@@ -0,0 +1,100 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/SonyArw2Decompressor.h"
+#include "common/Common.h" // for uchar8
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage
+#include "decoders/RawDecoderException.h" // for ThrowRDE, ...
+#include "decompressors/AbstractParallelizedDecompressor.h" // for RawDecom...
+#include "io/BitPumpLSB.h" // for BitPumpLSB
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+SonyArw2Decompressor::SonyArw2Decompressor(const RawImage& img,
+ const ByteStream& input_)
+ : AbstractParallelizedDecompressor(img) {
+ if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
+ mRaw->getBpp() != 2)
+ ThrowRDE("Unexpected component count / data type");
+
+ const uint32 w = mRaw->dim.x;
+ const uint32 h = mRaw->dim.y;
+
+ if (w == 0 || h == 0 || w % 32 != 0 || w > 8000 || h > 5320)
+ ThrowRDE("Unexpected image dimensions found: (%u; %u)", w, h);
+
+ // 1 byte per pixel
+ input = input_.peekStream(mRaw->dim.x * mRaw->dim.y);
+}
+
+void SonyArw2Decompressor::decompressThreaded(
+ const RawDecompressorThread* t) const {
+ uchar8* data = mRaw->getData();
+ uint32 pitch = mRaw->pitch;
+ int32 w = mRaw->dim.x;
+
+ assert(mRaw->dim.x > 0);
+ assert(mRaw->dim.x % 32 == 0);
+ assert(mRaw->dim.y > 0);
+
+ BitPumpLSB bits(input);
+ for (uint32 y = t->start; y < t->end; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
+ // Realign
+ bits.setBufferPosition(w * y);
+ uint32 random = bits.peekBits(24);
+
+ // Process 32 pixels (16x2) per loop.
+ for (int32 x = 0; x < w - 30;) {
+ int _max = bits.getBits(11);
+ int _min = bits.getBits(11);
+ int _imax = bits.getBits(4);
+ int _imin = bits.getBits(4);
+
+ int sh = 0;
+ while ((sh < 4) && ((0x80 << sh) <= (_max - _min)))
+ sh++;
+
+ for (int i = 0; i < 16; i++) {
+ int p;
+ if (i == _imax)
+ p = _max;
+ else {
+ if (i == _imin)
+ p = _min;
+ else {
+ p = (bits.getBits(7) << sh) + _min;
+ if (p > 0x7ff)
+ p = 0x7ff;
+ }
+ }
+ mRaw->setWithLookUp(p << 1, reinterpret_cast<uchar8*>(&dest[x + i * 2]),
+ &random);
+ }
+ x += ((x & 1) != 0) ? 31 : 1; // Skip to next 32 pixels
+ }
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/SonyArw2Decompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/SonyArw2Decompressor.h
new file mode 100644
index 000000000..689f30b4b
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/SonyArw2Decompressor.h
@@ -0,0 +1,39 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "decompressors/AbstractParallelizedDecompressor.h" // for Abstract...
+#include "io/ByteStream.h" // for ByteStream
+
+namespace rawspeed {
+
+class RawImage;
+
+class SonyArw2Decompressor final : public AbstractParallelizedDecompressor {
+ void decompressThreaded(const RawDecompressorThread* t) const final;
+
+ ByteStream input;
+
+public:
+ SonyArw2Decompressor(const RawImage& img, const ByteStream& input);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/UncompressedDecompressor.cpp b/src/external/rawspeed/src/librawspeed/decompressors/UncompressedDecompressor.cpp
new file mode 100644
index 000000000..3f843fe92
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/UncompressedDecompressor.cpp
@@ -0,0 +1,380 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "decompressors/UncompressedDecompressor.h"
+#include "common/Common.h" // for uint32, uchar8, ushort16
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include "io/BitPumpLSB.h" // for BitPumpLSB
+#include "io/BitPumpMSB.h" // for BitPumpMSB
+#include "io/BitPumpMSB16.h" // for BitPumpMSB16
+#include "io/BitPumpMSB32.h" // for BitPumpMSB32
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for getHostEndianness, Endiann...
+#include "io/IOException.h" // for ThrowIOE
+#include <algorithm> // for min
+#include <cassert> // for assert
+
+using std::min;
+
+namespace rawspeed {
+
+void UncompressedDecompressor::sanityCheck(const uint32* h, int bpl) {
+ assert(h != nullptr);
+ assert(*h > 0);
+ assert(bpl > 0);
+ assert(input.getSize() > 0);
+
+ // How many multiples of bpl are there in the input buffer?
+ // The remainder is ignored/discarded.
+ const auto fullRows = input.getRemainSize() / bpl;
+
+ // If more than the output height, we are all good.
+ if (fullRows >= *h)
+ return; // all good!
+
+ if (fullRows == 0)
+ ThrowIOE("Not enough data to decode a single line. Image file truncated.");
+
+ ThrowIOE("Image truncated, only %u of %u lines found", fullRows, *h);
+
+ // FIXME: need to come up with some common variable to allow proceeding here
+ // *h = min_h;
+}
+
+void UncompressedDecompressor::sanityCheck(uint32 w, const uint32* h, int bpp) {
+ assert(w > 0);
+ assert(bpp > 0);
+
+ // bytes per line
+ const auto bpl = bpp * w;
+ assert(bpl > 0);
+
+ sanityCheck(h, bpl);
+}
+
+int UncompressedDecompressor::bytesPerLine(int w, bool skips) {
+ assert(w > 0);
+
+ if ((12 * w) % 8 != 0)
+ ThrowIOE("Bad image width");
+
+ // Calulate expected bytes per line.
+ auto perline = (12 * w) / 8;
+
+ if (!skips)
+ return perline;
+
+ // Add skips every 10 pixels
+ perline += ((w + 2) / 10);
+
+ return perline;
+}
+
+void UncompressedDecompressor::readUncompressedRaw(const iPoint2D& size,
+ const iPoint2D& offset,
+ int inputPitch,
+ int bitPerPixel,
+ BitOrder order) {
+ assert(inputPitch > 0);
+ assert(bitPerPixel > 0);
+
+ uchar8* data = mRaw->getData();
+ uint32 outPitch = mRaw->pitch;
+ uint32 w = size.x;
+ uint32 h = size.y;
+ uint32 cpp = mRaw->getCpp();
+ uint64 ox = offset.x;
+ uint64 oy = offset.y;
+
+ sanityCheck(&h, inputPitch);
+
+ if (bitPerPixel > 16 && mRaw->getDataType() == TYPE_USHORT16)
+ ThrowRDE("Unsupported bit depth");
+
+ const int outPixelBits = w * cpp * bitPerPixel;
+ assert(outPixelBits > 0);
+
+ if (outPixelBits % 8 != 0) {
+ ThrowRDE("Bad combination of cpp (%u), bps (%u) and width (%u), the "
+ "pitch is %u bits, which is not a multiple of 8 (1 byte)",
+ cpp, bitPerPixel, w, outPixelBits);
+ }
+
+ const int outPixelBytes = outPixelBits / 8;
+
+ uint32 skipBits = inputPitch - outPixelBytes; // Skip per line
+ if (oy > static_cast<uint64>(mRaw->dim.y))
+ ThrowRDE("Invalid y offset");
+ if (ox + size.x > static_cast<uint64>(mRaw->dim.x))
+ ThrowRDE("Invalid x offset");
+
+ uint64 y = oy;
+ h = min(h + oy, static_cast<uint64>(mRaw->dim.y));
+
+ if (mRaw->getDataType() == TYPE_FLOAT32) {
+ if (bitPerPixel != 32)
+ ThrowRDE("Only 32 bit float point supported");
+ copyPixels(&data[offset.x * sizeof(float) * cpp + y * outPitch], outPitch,
+ input.getData(inputPitch * (h - y)), inputPitch,
+ w * mRaw->getBpp(), h - y);
+ return;
+ }
+
+ if (BitOrder_MSB == order) {
+ BitPumpMSB bits(input);
+ w *= cpp;
+ for (; y < h; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(
+ &data[offset.x * sizeof(ushort16) * cpp + y * outPitch]);
+ for (uint32 x = 0; x < w; x++) {
+ uint32 b = bits.getBits(bitPerPixel);
+ dest[x] = b;
+ }
+ bits.skipBits(skipBits);
+ }
+ } else if (BitOrder_MSB16 == order) {
+ BitPumpMSB16 bits(input);
+ w *= cpp;
+ for (; y < h; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(
+ &data[offset.x * sizeof(ushort16) * cpp + y * outPitch]);
+ for (uint32 x = 0; x < w; x++) {
+ uint32 b = bits.getBits(bitPerPixel);
+ dest[x] = b;
+ }
+ bits.skipBits(skipBits);
+ }
+ } else if (BitOrder_MSB32 == order) {
+ BitPumpMSB32 bits(input);
+ w *= cpp;
+ for (; y < h; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(
+ &data[offset.x * sizeof(ushort16) * cpp + y * outPitch]);
+ for (uint32 x = 0; x < w; x++) {
+ uint32 b = bits.getBits(bitPerPixel);
+ dest[x] = b;
+ }
+ bits.skipBits(skipBits);
+ }
+ } else {
+ if (bitPerPixel == 16 && getHostEndianness() == Endianness::little) {
+ copyPixels(&data[offset.x * sizeof(ushort16) * cpp + y * outPitch],
+ outPitch, input.getData(inputPitch * (h - y)), inputPitch,
+ w * mRaw->getBpp(), h - y);
+ return;
+ }
+ if (bitPerPixel == 12 && static_cast<int>(w) == inputPitch * 8 / 12 &&
+ getHostEndianness() == Endianness::little) {
+ decode12BitRaw<Endianness::little>(w, h);
+ return;
+ }
+ BitPumpLSB bits(input);
+ w *= cpp;
+ for (; y < h; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(
+ &data[offset.x * sizeof(ushort16) + y * outPitch]);
+ for (uint32 x = 0; x < w; x++) {
+ uint32 b = bits.getBits(bitPerPixel);
+ dest[x] = b;
+ }
+ bits.skipBits(skipBits);
+ }
+ }
+}
+
+template <bool uncorrectedRawValues>
+void UncompressedDecompressor::decode8BitRaw(uint32 w, uint32 h) {
+ sanityCheck(w, &h, 1);
+
+ uchar8* data = mRaw->getData();
+ uint32 pitch = mRaw->pitch;
+ const uchar8* in = input.getData(w * h);
+ uint32 random = 0;
+ for (uint32 y = 0; y < h; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
+ for (uint32 x = 0; x < w; x++) {
+ if (uncorrectedRawValues)
+ dest[x] = *in;
+ else
+ mRaw->setWithLookUp(*in, reinterpret_cast<uchar8*>(&dest[x]), &random);
+ in++;
+ }
+ }
+}
+
+template void UncompressedDecompressor::decode8BitRaw<false>(uint32 w, uint32 h);
+template void UncompressedDecompressor::decode8BitRaw<true>(uint32 w, uint32 h);
+
+template <Endianness e, bool interlaced, bool skips>
+void UncompressedDecompressor::decode12BitRaw(uint32 w, uint32 h) {
+ static constexpr const auto bits = 12;
+
+ static_assert(e == Endianness::little || e == Endianness::big,
+ "unknown endiannes");
+
+ static constexpr const auto shift = 16 - bits;
+ static constexpr const auto pack = 8 - shift;
+ static constexpr const auto mask = (1 << pack) - 1;
+
+ static_assert(bits == 12 && pack == 4, "wrong pack");
+
+ static_assert(bits == 12 && mask == 0x0f, "wrong mask");
+
+ uint32 perline = bytesPerLine(w, skips);
+
+ sanityCheck(&h, perline);
+
+ uchar8* data = mRaw->getData();
+ uint32 pitch = mRaw->pitch;
+
+ // FIXME: maybe check size of interlaced data?
+ const uchar8* in = input.peekData(perline * h);
+ uint32 half = (h + 1) >> 1;
+ for (uint32 row = 0; row < h; row++) {
+ uint32 y = !interlaced ? row : row % half * 2 + row / half;
+ auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
+
+ if (interlaced && y == 1) {
+ // The second field starts at a 2048 byte aligment
+ const uint32 offset = ((half * w * 3 / 2 >> 11) + 1) << 11;
+ input.skipBytes(offset);
+ in = input.peekData(perline * (h - row));
+ }
+
+ for (uint32 x = 0; x < w; x += 2, in += 3) {
+ uint32 g1 = in[0];
+ uint32 g2 = in[1];
+
+ auto process = [dest](uint32 i, bool invert, uint32 p1, uint32 p2) {
+ if (!(invert ^ (e == Endianness::little)))
+ dest[i] = (p1 << pack) | (p2 >> pack);
+ else
+ dest[i] = ((p2 & mask) << 8) | p1;
+ };
+
+ process(x, false, g1, g2);
+
+ g1 = in[2];
+
+ process(x + 1, true, g1, g2);
+
+ if (skips && ((x % 10) == 8))
+ in++;
+ }
+ }
+ input.skipBytes(input.getRemainSize());
+}
+
+template void
+UncompressedDecompressor::decode12BitRaw<Endianness::little, false, false>(
+ uint32 w, uint32 h);
+template void
+UncompressedDecompressor::decode12BitRaw<Endianness::big, false, false>(
+ uint32 w, uint32 h);
+template void
+UncompressedDecompressor::decode12BitRaw<Endianness::big, true, false>(
+ uint32 w, uint32 h);
+template void
+UncompressedDecompressor::decode12BitRaw<Endianness::little, false, true>(
+ uint32 w, uint32 h);
+template void
+UncompressedDecompressor::decode12BitRaw<Endianness::big, false, true>(
+ uint32 w, uint32 h);
+
+template <Endianness e>
+void UncompressedDecompressor::decode12BitRawUnpackedLeftAligned(uint32 w,
+ uint32 h) {
+ static_assert(e == Endianness::big, "unknown endiannes");
+
+ sanityCheck(w, &h, 2);
+
+ uchar8* data = mRaw->getData();
+ uint32 pitch = mRaw->pitch;
+ const uchar8* in = input.getData(w * h * 2);
+
+ for (uint32 y = 0; y < h; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
+ for (uint32 x = 0; x < w; x += 1, in += 2) {
+ uint32 g1 = in[0];
+ uint32 g2 = in[1];
+
+ if (e == Endianness::big)
+ dest[x] = (((g1 << 8) | (g2 & 0xf0)) >> 4);
+ }
+ }
+}
+
+template void
+UncompressedDecompressor::decode12BitRawUnpackedLeftAligned<Endianness::big>(
+ uint32 w, uint32 h);
+
+template <int bits, Endianness e>
+void UncompressedDecompressor::decodeRawUnpacked(uint32 w, uint32 h) {
+ static_assert(bits == 12 || bits == 14 || bits == 16, "unhandled bitdepth");
+ static_assert(e == Endianness::little || e == Endianness::big,
+ "unknown endiannes");
+
+ static constexpr const auto shift = 16 - bits;
+ static constexpr const auto mask = (1 << (8 - shift)) - 1;
+
+ static_assert((bits == 12 && mask == 0x0f) || bits != 12, "wrong mask");
+ static_assert((bits == 14 && mask == 0x3f) || bits != 14, "wrong mask");
+ static_assert((bits == 16 && mask == 0xff) || bits != 16, "wrong mask");
+
+ sanityCheck(w, &h, 2);
+
+ uchar8* data = mRaw->getData();
+ uint32 pitch = mRaw->pitch;
+ const uchar8* in = input.getData(w * h * 2);
+
+ for (uint32 y = 0; y < h; y++) {
+ auto* dest = reinterpret_cast<ushort16*>(&data[y * pitch]);
+ for (uint32 x = 0; x < w; x += 1, in += 2) {
+ uint32 g1 = in[0];
+ uint32 g2 = in[1];
+
+ if (e == Endianness::little)
+ dest[x] = ((g2 << 8) | g1) >> shift;
+ else
+ dest[x] = ((g1 & mask) << 8) | g2;
+ }
+ }
+}
+
+template void
+UncompressedDecompressor::decodeRawUnpacked<12, Endianness::little>(uint32 w,
+ uint32 h);
+template void
+UncompressedDecompressor::decodeRawUnpacked<12, Endianness::big>(uint32 w,
+ uint32 h);
+template void
+UncompressedDecompressor::decodeRawUnpacked<14, Endianness::big>(uint32 w,
+ uint32 h);
+template void
+UncompressedDecompressor::decodeRawUnpacked<16, Endianness::little>(uint32 w,
+ uint32 h);
+template void
+UncompressedDecompressor::decodeRawUnpacked<16, Endianness::big>(uint32 w,
+ uint32 h);
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/decompressors/UncompressedDecompressor.h b/src/external/rawspeed/src/librawspeed/decompressors/UncompressedDecompressor.h
new file mode 100644
index 000000000..6e625137c
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/decompressors/UncompressedDecompressor.h
@@ -0,0 +1,134 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2016-2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, BitOrder
+#include "common/RawImage.h" // for RawImage
+#include "decompressors/AbstractDecompressor.h" // for AbstractDecompressor
+#include "io/Buffer.h" // for Buffer, Buffer::size_type
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for Endianness
+#include <algorithm> // for move
+
+namespace rawspeed {
+
+class iPoint2D;
+
+class UncompressedDecompressor final : public AbstractDecompressor {
+ ByteStream input;
+ RawImage mRaw;
+
+ // check buffer size, throw, or compute minimal height that can be decoded
+ void sanityCheck(const uint32* h, int bpl);
+
+ // check buffer size, throw, or compute minimal height that can be decoded
+ void sanityCheck(uint32 w, const uint32* h, int bpp);
+
+ // for special packed formats
+ int bytesPerLine(int w, bool skips);
+
+public:
+ UncompressedDecompressor(ByteStream input_, const RawImage& img)
+ : input(std::move(input_)), mRaw(img) {}
+
+ UncompressedDecompressor(const Buffer& data, Buffer::size_type offset,
+ Buffer::size_type size, const RawImage& img)
+ : UncompressedDecompressor(ByteStream(data, offset, size), img) {}
+
+ UncompressedDecompressor(const Buffer& data, Buffer::size_type offset,
+ const RawImage& img)
+ : UncompressedDecompressor(ByteStream(data, offset), img) {}
+
+ UncompressedDecompressor(const Buffer& data, const RawImage& img)
+ : UncompressedDecompressor(data, 0, img) {}
+
+ /* Helper function for decoders, that will unpack uncompressed image data */
+ /* input: Input image, positioned at first pixel */
+ /* size: Size of the image to decode in pixels */
+ /* offset: offset to write the data into the final image */
+ /* inputPitch: Number of bytes between each line in the input image */
+ /* bitPerPixel: Number of bits to read for each input pixel. */
+ /* order: Order of the bits - see Common.h for possibilities. */
+ void readUncompressedRaw(const iPoint2D& size, const iPoint2D& offset,
+ int inputPitch, int bitPerPixel, BitOrder order);
+
+ /* Faster versions for unpacking 8 bit data */
+ template <bool uncorrectedRawValues> void decode8BitRaw(uint32 w, uint32 h);
+
+ /* Faster version for unpacking 12 bit data */
+ /* interlaced - is data with interlaced lines ? */
+ /* skips - is there control byte every 10 pixels ? */
+ template <Endianness e, bool interlaced = false, bool skips = false>
+ void decode12BitRaw(uint32 w, uint32 h);
+
+ /* Faster version for reading unpacked 12 bit data that is left aligned
+ * (needs >> 4 shift) */
+ template <Endianness e>
+ void decode12BitRawUnpackedLeftAligned(uint32 w, uint32 h);
+
+ /* Faster version for reading unpacked data */
+ template <int bits, Endianness e> void decodeRawUnpacked(uint32 w, uint32 h);
+};
+
+extern template void UncompressedDecompressor::decode8BitRaw<false>(uint32 w,
+ uint32 h);
+extern template void UncompressedDecompressor::decode8BitRaw<true>(uint32 w,
+ uint32 h);
+
+extern template void
+UncompressedDecompressor::decode12BitRaw<Endianness::little, false, false>(
+ uint32 w, uint32 h);
+extern template void
+UncompressedDecompressor::decode12BitRaw<Endianness::big, false, false>(
+ uint32 w, uint32 h);
+extern template void
+UncompressedDecompressor::decode12BitRaw<Endianness::big, true, false>(
+ uint32 w, uint32 h);
+extern template void
+UncompressedDecompressor::decode12BitRaw<Endianness::little, false, true>(
+ uint32 w, uint32 h);
+extern template void
+UncompressedDecompressor::decode12BitRaw<Endianness::big, false, true>(
+ uint32 w, uint32 h);
+
+extern template void
+UncompressedDecompressor::decode12BitRawUnpackedLeftAligned<Endianness::big>(
+ uint32 w, uint32 h);
+
+extern template void
+UncompressedDecompressor::decodeRawUnpacked<12, Endianness::little>(uint32 w,
+ uint32 h);
+extern template void
+UncompressedDecompressor::decodeRawUnpacked<12, Endianness::big>(uint32 w,
+ uint32 h);
+extern template void
+UncompressedDecompressor::decodeRawUnpacked<14, Endianness::big>(uint32 w,
+ uint32 h);
+extern template void
+UncompressedDecompressor::decodeRawUnpacked<16, Endianness::little>(uint32 w,
+ uint32 h);
+extern template void
+UncompressedDecompressor::decodeRawUnpacked<16, Endianness::big>(uint32 w,
+ uint32 h);
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/interpolators/CMakeLists.txt b/src/external/rawspeed/src/librawspeed/interpolators/CMakeLists.txt
new file mode 100644
index 000000000..3f7629277
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/interpolators/CMakeLists.txt
@@ -0,0 +1,8 @@
+FILE(GLOB SOURCES
+ "Cr2sRawInterpolator.cpp"
+ "Cr2sRawInterpolator.h"
+)
+
+target_sources(rawspeed PRIVATE
+ ${SOURCES}
+)
diff --git a/src/external/rawspeed/src/librawspeed/interpolators/Cr2sRawInterpolator.cpp b/src/external/rawspeed/src/librawspeed/interpolators/Cr2sRawInterpolator.cpp
new file mode 100644
index 000000000..59a2ba27a
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/interpolators/Cr2sRawInterpolator.cpp
@@ -0,0 +1,522 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2015-2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "interpolators/Cr2sRawInterpolator.h"
+#include "common/Common.h" // for ushort16, clampBits
+#include "common/Point.h" // for iPoint2D
+#include "common/RawImage.h" // for RawImage, RawImageData
+#include "decoders/RawDecoderException.h" // for RawDecoderException (ptr o...
+#include <array> // for array
+#include <cassert> // for assert
+#include <type_traits> // for is_pod
+
+using std::is_pod;
+using std::array;
+
+namespace rawspeed {
+
+struct Cr2sRawInterpolator::YCbCr final {
+ int Y;
+ int Cb;
+ int Cr;
+
+ inline static void LoadY(YCbCr* dst, const YCbCr& src) {
+ assert(dst);
+
+ dst->Y = src.Y;
+ }
+
+ inline static void LoadY(YCbCr* p, const ushort16* data) {
+ assert(p);
+ assert(data);
+
+ p->Y = data[0];
+ }
+
+ inline static void LoadCbCr(YCbCr* p, const ushort16* data) {
+ assert(p);
+ assert(data);
+
+ p->Cb = data[1];
+ p->Cr = data[2];
+ }
+
+ inline static void Load(YCbCr* p, const ushort16* data) {
+ assert(p);
+ assert(data);
+
+ LoadY(p, data);
+ LoadCbCr(p, data);
+ }
+
+ YCbCr() = default;
+
+ explicit YCbCr(ushort16* data) {
+ static_assert(is_pod<YCbCr>::value, "not a POD");
+
+ assert(data);
+
+ Load(this, data);
+ }
+
+ inline void signExtend() {
+ Cb -= 16384;
+ Cr -= 16384;
+ }
+
+ inline void applyHue(int hue_) {
+ Cb += hue_;
+ Cr += hue_;
+ }
+
+ inline void process(int hue_) {
+ signExtend();
+ applyHue(hue_);
+ }
+
+ inline void interpolate(const YCbCr& p0, const YCbCr& p2) {
+ // Y is already good, need to interpolate Cb and Cr
+ // FIXME: dcraw does +1 before >> 1
+ Cb = (p0.Cb + p2.Cb) >> 1;
+ Cr = (p0.Cr + p2.Cr) >> 1;
+ }
+
+ inline void interpolate(const YCbCr& p0, const YCbCr& p1, const YCbCr& p2,
+ const YCbCr& p3) {
+ // Y is already good, need to interpolate Cb and Cr
+ // FIXME: dcraw does +1 before >> 1
+ Cb = (p0.Cb + p1.Cb + p2.Cb + p3.Cb) >> 2;
+ Cr = (p0.Cr + p1.Cr + p2.Cr + p3.Cr) >> 2;
+ }
+};
+
+// NOTE: Thread safe.
+template <int version>
+inline void Cr2sRawInterpolator::interpolate_422_row(ushort16* data, int w) {
+ assert(data);
+ assert(w >= 2);
+ assert(w % 2 == 0);
+
+ // the format is:
+ // p0 p1 p2 p3
+ // [ Y1 Cb Cr ] [ Y2 ... ... ] [ Y1 Cb Cr ] [ Y2 ... ... ] ...
+ // i.e. even pixels are full, odd pixels need interpolation:
+ // p0 p1 p2 p3
+ // [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
+ // for last (odd) pixel of the line, just keep Cb/Cr from previous pixel
+ // see http://lclevy.free.fr/cr2/#sraw
+
+ int x;
+ for (x = 0; x < w - 2; x += 2) {
+ assert(x + 4 <= w);
+ assert(x % 2 == 0);
+
+ // load, process and output first pixel, which is full
+ YCbCr p0(data);
+ p0.process(hue);
+ YUV_TO_RGB<version>(p0, data);
+ data += 3;
+
+ // load Y from second pixel, Cb/Cr need to be interpolated
+ YCbCr p;
+ YCbCr::LoadY(&p, data);
+
+ // load third pixel, which is full, process
+ YCbCr p1(data + 3);
+ p1.process(hue);
+
+ // and finally, interpolate and output the middle pixel
+ p.interpolate(p0, p1);
+ YUV_TO_RGB<version>(p, data);
+ data += 3;
+ }
+
+ assert(x + 2 == w);
+ assert(x % 2 == 0);
+
+ // Last two pixels, the format is:
+ // p0 p1
+ // .. [ Y1 Cb Cr ] [ Y2 ... ... ]
+
+ // load, process and output first pixel, which is full
+ YCbCr p(data);
+ p.process(hue);
+ YUV_TO_RGB<version>(p, data);
+ data += 3;
+
+ // load Y from second pixel, keep Cb/Cr from previous pixel, and output
+ YCbCr::LoadY(&p, data);
+ YUV_TO_RGB<version>(p, data);
+ data += 3;
+}
+
+template <int version>
+inline void Cr2sRawInterpolator::interpolate_422(int w, int h) {
+ assert(w > 0);
+ assert(h > 0);
+
+ for (int y = 0; y < h; y++) {
+ auto data = reinterpret_cast<ushort16*>(mRaw->getData(0, y));
+
+ interpolate_422_row<version>(data, w);
+ }
+}
+
+// NOTE: Not thread safe, since it writes inplace.
+template <int version>
+inline void
+Cr2sRawInterpolator::interpolate_420_row(std::array<ushort16*, 3> line, int w) {
+ assert(line[0]);
+ assert(line[1]);
+ assert(line[2]);
+
+ // the format is:
+ // p0 p1 p2 p3
+ // row 0: [ Y1 Cb Cr ] [ Y2 ... ... ] [ Y1 Cb Cr ] [ Y2 ... ... ] ...
+ // row 1: [ Y3 ... ... ] [ Y4 ... ... ] [ Y3 ... ... ] [ Y4 ... ... ] ...
+ // row 2: [ Y1 Cb Cr ] [ Y2 ... ... ] [ Y1 Cb Cr ] [ Y2 ... ... ] ...
+ // row 3: [ Y3 ... ... ] [ Y4 ... ... ] [ Y3 ... ... ] [ Y4 ... ... ] ...
+ // .. . . .. . . .. . . .. . .
+ // i.e. on even rows, even pixels are full, rest of pixels need interpolation
+ // first, on even rows, odd pixels are interpolated using 422 algo (marked *)
+ // p0 p1 p2 p3
+ // row 0: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
+ // row 1: [ Y3 ... ... ] [ Y4 ... ... ] [ Y3 ... ... ] [ Y4 ... ... ] ...
+ // row 2: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
+ // row 3: [ Y3 ... ... ] [ Y4 ... ... ] [ Y3 ... ... ] [ Y4 ... ... ] ...
+ // .. . . .. . . .. . .
+ // then, on odd rows, even pixels are interpolated (marked with #)
+ // p0 p1 p2 p3
+ // row 0: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
+ // row 1: [ Y3 Cb# Cr# ] [ Y4 ... ... ] [ Y3 Cb# Cr# ] [ Y4 ... ... ] ...
+ // row 2: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
+ // row 3: [ Y3 Cb# Cr# ] [ Y4 ... ... ] [ Y3 Cb# Cr# ] [ Y4 ... ... ] ...
+ // .. . . .. . . .. . .
+ // and finally, on odd rows, odd pixels are interpolated from * (marked $)
+ // p0 p1 p2 p3
+ // row 0: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
+ // row 1: [ Y3 Cb# Cr# ] [ Y4 Cb$ Cr$ ] [ Y3 Cb# Cr# ] [ Y4 Cb$ Cr$ ] ...
+ // row 2: [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] [ Y1 Cb Cr ] [ Y2 Cb* Cr* ] ...
+ // row 3: [ Y3 Cb# Cr# ] [ Y4 Cb$ Cr$ ] [ Y3 Cb# Cr# ] [ Y4 Cb$ Cr$ ] ...
+ // .. . . .. . . .. . .
+ // see http://lclevy.free.fr/cr2/#sraw
+
+ int x;
+ for (x = 0; x < w - 2; x += 2) {
+ assert(x + 4 <= w);
+ assert(x % 2 == 0);
+
+ // load, process and output first pixel of first row, which is full
+ YCbCr p0(line[0]);
+ p0.process(hue);
+ YUV_TO_RGB<version>(p0, line[0]);
+ line[0] += 3;
+
+ // load Y from second pixel of first row
+ YCbCr ph;
+ YCbCr::LoadY(&ph, line[0]);
+
+ // load Cb/Cr from third pixel of first row
+ YCbCr p1;
+ YCbCr::LoadCbCr(&p1, line[0] + 3);
+ p1.process(hue);
+
+ // and finally, interpolate and output the middle pixel of first row
+ ph.interpolate(p0, p1);
+ YUV_TO_RGB<version>(ph, line[0]);
+ line[0] += 3;
+
+ // load Y from first pixel of second row
+ YCbCr pv;
+ YCbCr::LoadY(&pv, line[1]);
+
+ // load Cb/Cr from first pixel of third row
+ YCbCr p2;
+ YCbCr::LoadCbCr(&p2, line[2]);
+ p2.process(hue);
+
+ // and finally, interpolate and output the first pixel of second row
+ pv.interpolate(p0, p2);
+ YUV_TO_RGB<version>(pv, line[1]);
+ line[1] += 3;
+ line[2] += 6;
+
+ // load Y from second pixel of second row
+ YCbCr p;
+ YCbCr::LoadY(&p, line[1]);
+
+ // load Cb/Cr from third pixel of third row
+ YCbCr p3;
+ YCbCr::LoadCbCr(&p3, line[2]);
+ p3.process(hue);
+
+ // and finally, interpolate and output the second pixel of second row
+ // NOTE: we interpolate 4 full pixels here, located on diagonals
+ // dcraw interpolates from already interpolated pixels
+ p.interpolate(p0, p1, p2, p3);
+ YUV_TO_RGB<version>(p, line[1]);
+ line[1] += 3;
+ }
+
+ assert(x + 2 == w);
+ assert(x % 2 == 0);
+
+ // Last two pixels of the lines, the format is:
+ // p0 p1
+ // row 0: ... [ Y1 Cb Cr ] [ Y2 ... ... ]
+ // row 1: ... [ Y3 ... ... ] [ Y4 ... ... ]
+ // row 2: ... [ Y1 Cb Cr ] [ Y2 ... ... ]
+ // row 3: ... [ Y3 ... ... ] [ Y4 ... ... ]
+ // .. . . .. . .
+
+ // load, process and output first pixel of first row, which is full
+ YCbCr p0(line[0]);
+ p0.process(hue);
+ YUV_TO_RGB<version>(p0, line[0]);
+ line[0] += 3;
+
+ // keep Cb/Cr from first pixel of first row
+ // load Y from second pixel of first row, output
+ YCbCr::LoadY(&p0, line[0]);
+ YUV_TO_RGB<version>(p0, line[0]);
+ line[0] += 3;
+
+ // load Y from first pixel of second row
+ YCbCr pv;
+ YCbCr::LoadY(&pv, line[1]);
+
+ // load Cb/Cr from first pixel of third row
+ YCbCr p2;
+ YCbCr::LoadCbCr(&p2, line[2]);
+ p2.process(hue);
+
+ // and finally, interpolate and output the first pixel of second row
+ pv.interpolate(p0, p2);
+ YUV_TO_RGB<version>(pv, line[1]);
+ line[1] += 3;
+
+ // keep Cb/Cr from first pixel of second row
+ // load Y from second pixel of second row, output
+ YCbCr::LoadY(&pv, line[1]);
+ YUV_TO_RGB<version>(pv, line[1]);
+ line[1] += 3;
+}
+
+// NOTE: Not thread safe, since it writes inplace.
+template <int version>
+inline void Cr2sRawInterpolator::interpolate_420(int w, int h) {
+ assert(w >= 2);
+ assert(w % 2 == 0);
+
+ assert(h >= 2);
+ assert(h % 2 == 0);
+
+ array<ushort16*, 3> line;
+
+ int y;
+ for (y = 0; y < h - 2; y += 2) {
+ assert(y + 4 <= h);
+ assert(y % 2 == 0);
+
+ line[0] = reinterpret_cast<ushort16*>(mRaw->getData(0, y));
+ line[1] = reinterpret_cast<ushort16*>(mRaw->getData(0, y + 1));
+ line[2] = reinterpret_cast<ushort16*>(mRaw->getData(0, y + 2));
+
+ interpolate_420_row<version>(line, w);
+ }
+
+ assert(y + 2 == h);
+ assert(y % 2 == 0);
+
+ line[0] = reinterpret_cast<ushort16*>(mRaw->getData(0, y));
+ line[1] = reinterpret_cast<ushort16*>(mRaw->getData(0, y + 1));
+ line[2] = nullptr;
+
+ assert(line[0]);
+ assert(line[1]);
+ assert(line[2] == nullptr);
+
+ // Last two lines, the format is:
+ // p0 p1 p2 p3
+ // .. . . .. . . .. . . .. . .
+ // row 0: [ Y1 Cb Cr ] [ Y2 ... ... ] [ Y1 Cb Cr ] [ Y2 ... ... ] ...
+ // row 1: [ Y3 ... ... ] [ Y4 ... ... ] [ Y3 ... ... ] [ Y4 ... ... ] ...
+
+ int x;
+ for (x = 0; x < w - 2; x += 2) {
+ assert(x + 4 <= w);
+ assert(x % 2 == 0);
+
+ // load, process and output first pixel of first row, which is full
+ YCbCr p0(line[0]);
+ p0.process(hue);
+ YUV_TO_RGB<version>(p0, line[0]);
+ line[0] += 3;
+
+ // load Y from second pixel of first row
+ YCbCr ph;
+ YCbCr::LoadY(&ph, line[0]);
+
+ // load Cb/Cr from third pixel of first row
+ YCbCr p1;
+ YCbCr::LoadCbCr(&p1, line[0] + 3);
+ p1.process(hue);
+
+ // and finally, interpolate and output the middle pixel of first row
+ ph.interpolate(p0, p1);
+ YUV_TO_RGB<version>(ph, line[0]);
+ line[0] += 3;
+
+ // keep Cb/Cr from first pixel of first row
+ // load Y from first pixel of second row; and output
+ YCbCr::LoadY(&p0, line[1]);
+ YUV_TO_RGB<version>(p0, line[1]);
+ line[1] += 3;
+
+ // keep Cb/Cr from second pixel of first row
+ // load Y from second pixel of second row; and output
+ YCbCr::LoadY(&ph, line[1]);
+ YUV_TO_RGB<version>(ph, line[1]);
+ line[1] += 3;
+ }
+
+ assert(line[0]);
+ assert(line[1]);
+ assert(line[2] == nullptr);
+
+ assert(y + 2 == h);
+ assert(y % 2 == 0);
+
+ assert(x + 2 == w);
+ assert(x % 2 == 0);
+
+ // Last two pixels of last two lines, the format is:
+ // p0 p1
+ // .. . . .. . .
+ // row 0: ... [ Y1 Cb Cr ] [ Y2 ... ... ]
+ // row 1: ... [ Y3 ... ... ] [ Y4 ... ... ]
+
+ // load, process and output first pixel of first row, which is full
+ YCbCr p(line[0]);
+ p.process(hue);
+ YUV_TO_RGB<version>(p, line[0]);
+ line[0] += 3;
+
+ // rest keeps Cb/Cr from this original pixel, because rest only have Y
+
+ // load Y from second pixel of first row, and output
+ YCbCr::LoadY(&p, line[0]);
+ YUV_TO_RGB<version>(p, line[0]);
+ line[0] += 3;
+
+ // load Y from first pixel of second row, and output
+ YCbCr::LoadY(&p, line[1]);
+ YUV_TO_RGB<version>(p, line[1]);
+ line[1] += 3;
+
+ // load Y from second pixel of second row, and output
+ YCbCr::LoadY(&p, line[1]);
+ YUV_TO_RGB<version>(p, line[1]);
+ line[1] += 3;
+}
+
+inline void Cr2sRawInterpolator::STORE_RGB(ushort16* X, int r, int g, int b) {
+ assert(X);
+
+ X[0] = clampBits(r >> 8, 16);
+ X[1] = clampBits(g >> 8, 16);
+ X[2] = clampBits(b >> 8, 16);
+}
+
+template </* int version */>
+/* Algorithm found in EOS 40D */
+inline void Cr2sRawInterpolator::YUV_TO_RGB<0>(const YCbCr& p, ushort16* X) {
+ assert(X);
+
+ int r = sraw_coeffs[0] * (p.Y + p.Cr - 512);
+ int g = sraw_coeffs[1] * (p.Y + ((-778 * p.Cb - (p.Cr * 2048)) >> 12) - 512);
+ int b = sraw_coeffs[2] * (p.Y + (p.Cb - 512));
+ STORE_RGB(X, r, g, b);
+}
+
+template </* int version */>
+inline void Cr2sRawInterpolator::YUV_TO_RGB<1>(const YCbCr& p, ushort16* X) {
+ assert(X);
+
+ int r = sraw_coeffs[0] * (p.Y + ((50 * p.Cb + 22929 * p.Cr) >> 12));
+ int g = sraw_coeffs[1] * (p.Y + ((-5640 * p.Cb - 11751 * p.Cr) >> 12));
+ int b = sraw_coeffs[2] * (p.Y + ((29040 * p.Cb - 101 * p.Cr) >> 12));
+ STORE_RGB(X, r, g, b);
+}
+
+template </* int version */>
+/* Algorithm found in EOS 5d Mk III */
+inline void Cr2sRawInterpolator::YUV_TO_RGB<2>(const YCbCr& p, ushort16* X) {
+ assert(X);
+
+ int r = sraw_coeffs[0] * (p.Y + p.Cr);
+ int g = sraw_coeffs[1] * (p.Y + ((-778 * p.Cb - (p.Cr * 2048)) >> 12));
+ int b = sraw_coeffs[2] * (p.Y + p.Cb);
+ STORE_RGB(X, r, g, b);
+}
+
+// Interpolate and convert sRaw data.
+void Cr2sRawInterpolator::interpolate(int version) {
+ assert(version >= 0 && version <= 2);
+
+ const auto& subSampling = mRaw->metadata.subsampling;
+ if (subSampling.y == 1 && subSampling.x == 2) {
+ int width = mRaw->dim.x;
+ int height = mRaw->dim.y;
+
+ switch (version) {
+ case 0:
+ interpolate_422<0>(width, height);
+ break;
+ case 1:
+ interpolate_422<1>(width, height);
+ break;
+ case 2:
+ interpolate_422<2>(width, height);
+ break;
+ default:
+ __builtin_unreachable();
+ }
+ } else if (subSampling.y == 2 && subSampling.x == 2) {
+ int width = mRaw->dim.x;
+ int height = mRaw->dim.y;
+
+ switch (version) {
+ // no known sraws with "version 0"
+ case 1:
+ interpolate_420<1>(width, height);
+ break;
+ case 2:
+ interpolate_420<2>(width, height);
+ break;
+ default:
+ __builtin_unreachable();
+ }
+ } else
+ ThrowRDE("Unknown subsampling: (%i; %i)", subSampling.x, subSampling.y);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/interpolators/Cr2sRawInterpolator.h b/src/external/rawspeed/src/librawspeed/interpolators/Cr2sRawInterpolator.h
new file mode 100644
index 000000000..279e871a2
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/interpolators/Cr2sRawInterpolator.h
@@ -0,0 +1,57 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for ushort16
+#include <array> // for array
+
+namespace rawspeed {
+
+class RawImage;
+
+class Cr2sRawInterpolator final {
+ const RawImage& mRaw;
+ std::array<int, 3> sraw_coeffs;
+ int hue;
+
+ struct YCbCr;
+
+public:
+ Cr2sRawInterpolator(const RawImage& mRaw_, std::array<int, 3> sraw_coeffs_,
+ int hue_)
+ : mRaw(mRaw_), sraw_coeffs(sraw_coeffs_), hue(hue_) {}
+
+ void interpolate(int version);
+
+protected:
+ template <int version> inline void YUV_TO_RGB(const YCbCr& p, ushort16* X);
+
+ inline void STORE_RGB(ushort16* X, int r, int g, int b);
+
+ template <int version> inline void interpolate_422_row(ushort16* data, int w);
+ template <int version> inline void interpolate_422(int w, int h);
+
+ template <int version>
+ inline void interpolate_420_row(std::array<ushort16*, 3> line, int w);
+ template <int version> inline void interpolate_420(int w, int h);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/BitPumpJPEG.h b/src/external/rawspeed/src/librawspeed/io/BitPumpJPEG.h
new file mode 100644
index 000000000..d9e562d0a
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/BitPumpJPEG.h
@@ -0,0 +1,84 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uchar8, uint32
+#include "io/BitStream.h" // for BitStreamCacheRightInLeftOut, BitStream
+#include "io/Buffer.h" // for Buffer::size_type
+#include "io/Endianness.h" // for getBE
+
+namespace rawspeed {
+
+struct JPEGBitPumpTag;
+
+// The JPEG data is ordered in MSB bit order,
+// i.e. we push into the cache from the right and read it from the left
+using BitPumpJPEG = BitStream<JPEGBitPumpTag, BitStreamCacheRightInLeftOut>;
+
+template <>
+inline BitPumpJPEG::size_type BitPumpJPEG::fillCache(const uchar8* input)
+{
+ static_assert(BitStreamCacheBase::MaxGetBits >= 32, "check implementation");
+
+ // short-cut path for the most common case (no FF marker in the next 4 bytes)
+ // this is slightly faster than the else-case alone.
+ // TODO: investigate applicability of vector intrinsics to speed up if-cascade
+ if (input[0] != 0xFF &&
+ input[1] != 0xFF &&
+ input[2] != 0xFF &&
+ input[3] != 0xFF ) {
+ cache.push(getBE<uint32>(input), 32);
+ return 4;
+ }
+
+ size_type p = 0;
+ for (size_type i = 0; i < 4; ++i) {
+ // Pre-execute most common case, where next byte is 'normal'/non-FF
+ const int c0 = input[p++];
+ cache.push(c0, 8);
+ if (c0 == 0xFF) {
+ // Found FF -> pre-execute case of FF/00, which represents an FF data byte -> ignore the 00
+ const int c1 = input[p++];
+ if (c1 != 0) {
+ // Found FF/xx with xx != 00. This is the end of stream marker.
+ // Fill the cache with zeros and keep on doing that from now on.
+
+ // Normally we would rewind the pos to the FF byte, but in order to
+ // prevent potential endless loop on corrupt lossless jpeg, let's not.
+
+ cache.cache &= ~0xFF;
+ cache.cache <<= 64 - cache.fillLevel;
+ cache.fillLevel = 64;
+ break;
+ }
+ }
+ }
+ return p;
+}
+
+template <> inline BitPumpJPEG::size_type BitPumpJPEG::getBufferPosition() const
+{
+ // the current number of bytes we consumed -> at the end of the stream pos, it
+ // points to the JPEG marker FF
+ return pos;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/BitPumpLSB.h b/src/external/rawspeed/src/librawspeed/io/BitPumpLSB.h
new file mode 100644
index 000000000..c7665b8a7
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/BitPumpLSB.h
@@ -0,0 +1,51 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, uchar8
+#include "io/BitStream.h" // for BitStream, BitStreamCacheLeftInRightOut
+#include "io/Buffer.h" // for Buffer::size_type
+#include "io/Endianness.h" // for getLE
+
+namespace rawspeed {
+
+struct PlainBitPumpTag;
+
+// The PlainPump is ordered in LSB bit order,
+// i.e. we push into the cache from the left and read it from the right
+
+using BitPumpLSB = BitStream<PlainBitPumpTag, BitStreamCacheLeftInRightOut>;
+
+template <>
+inline BitPumpLSB::size_type BitPumpLSB::fillCache(const uchar8* input) {
+ static_assert(BitStreamCacheBase::MaxGetBits >= 32, "check implementation");
+
+ cache.push(getLE<uint32>(input), 32);
+ return 4;
+}
+
+template <> inline void BitPumpLSB::setBufferPosition(size_type newPos) {
+ pos = newPos;
+ cache.fillLevel = 0;
+ cache.cache = 0;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/BitPumpMSB.h b/src/external/rawspeed/src/librawspeed/io/BitPumpMSB.h
new file mode 100644
index 000000000..9006404ad
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/BitPumpMSB.h
@@ -0,0 +1,45 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, uchar8
+#include "io/BitStream.h" // for BitStream, BitStreamCacheRightInLeftOut
+#include "io/Endianness.h" // for getBE
+
+namespace rawspeed {
+
+struct MSBBitPumpTag;
+
+// The MSB data is ordered in MSB bit order,
+// i.e. we push into the cache from the right and read it from the left
+
+using BitPumpMSB = BitStream<MSBBitPumpTag, BitStreamCacheRightInLeftOut>;
+
+template <>
+inline BitPumpMSB::size_type BitPumpMSB::fillCache(const uchar8* input)
+{
+ static_assert(BitStreamCacheBase::MaxGetBits >= 32, "check implementation");
+
+ cache.push(getBE<uint32>(input), 32);
+ return 4;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/BitPumpMSB16.h b/src/external/rawspeed/src/librawspeed/io/BitPumpMSB16.h
new file mode 100644
index 000000000..a44a2f584
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/BitPumpMSB16.h
@@ -0,0 +1,47 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for ushort16, uchar8
+#include "io/BitStream.h" // for BitStream, BitStreamCacheRightInLeftOut
+#include "io/Buffer.h" // for Buffer::size_type
+#include "io/Endianness.h" // for getLE
+
+namespace rawspeed {
+
+struct MSB16BitPumpTag;
+
+// The MSB data is ordered in MSB bit order,
+// i.e. we push into the cache from the right and read it from the left
+
+using BitPumpMSB16 = BitStream<MSB16BitPumpTag, BitStreamCacheRightInLeftOut>;
+
+template <>
+inline BitPumpMSB16::size_type BitPumpMSB16::fillCache(const uchar8* input)
+{
+ static_assert(BitStreamCacheBase::MaxGetBits >= 32, "check implementation");
+
+ for (size_type i = 0; i < 4; i += sizeof(ushort16))
+ cache.push(getLE<ushort16>(input + i), 16);
+ return 4;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/BitPumpMSB32.h b/src/external/rawspeed/src/librawspeed/io/BitPumpMSB32.h
new file mode 100644
index 000000000..ed77c9200
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/BitPumpMSB32.h
@@ -0,0 +1,45 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, uchar8
+#include "io/BitStream.h" // for BitStream, BitStreamCacheRightInLeftOut
+#include "io/Endianness.h" // for getLE
+
+namespace rawspeed {
+
+struct MSB32BitPumpTag;
+
+// The MSB data is ordered in MSB bit order,
+// i.e. we push into the cache from the right and read it from the left
+
+using BitPumpMSB32 = BitStream<MSB32BitPumpTag, BitStreamCacheRightInLeftOut>;
+
+template <>
+inline BitPumpMSB32::size_type BitPumpMSB32::fillCache(const uchar8* input)
+{
+ static_assert(BitStreamCacheBase::MaxGetBits >= 32, "check implementation");
+
+ cache.push(getLE<uint32>(input), 32);
+ return 4;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/BitStream.h b/src/external/rawspeed/src/librawspeed/io/BitStream.h
new file mode 100644
index 000000000..be6146732
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/BitStream.h
@@ -0,0 +1,203 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, uchar8, uint64
+#include "io/Buffer.h" // for Buffer::size_type, BUFFER_PADDING
+#include "io/ByteStream.h" // for ByteStream
+#include "io/IOException.h" // for IOException (ptr only), ThrowIOE
+#include <cassert> // for assert
+#include <cstring> // for memcpy
+
+namespace rawspeed {
+
+// simple 64-bit wide cache implementation that acts like a FiFo.
+// There are two variants:
+// * L->R: new bits are pushed in on the left and pulled out on the right
+// * L<-R: new bits are pushed in on the right and pulled out on the left
+// Each BitStream specialization uses one of the two.
+
+struct BitStreamCacheBase
+{
+ uint64 cache = 0; // the acutal bits stored in the cache
+ unsigned int fillLevel = 0; // bits left in cache
+ static constexpr unsigned Size = sizeof(cache)*8;
+
+ // how many bits could be requested to be filled
+ static constexpr unsigned MaxGetBits = Size/2;
+
+ // maximal number of bytes the implementation may read.
+ // NOTE: this is not the same as MaxGetBits/8 !!!
+ static constexpr unsigned MaxProcessBytes = 8;
+};
+
+struct BitStreamCacheLeftInRightOut : BitStreamCacheBase
+{
+ inline void push(uint64 bits, uint32 count) noexcept {
+ assert(count + fillLevel <= Size);
+ cache |= bits << fillLevel;
+ fillLevel += count;
+ }
+
+ inline uint32 peek(uint32 count) const noexcept {
+ return cache & ((1 << count) - 1);
+ }
+
+ inline void skip(uint32 count) noexcept {
+ cache >>= count;
+ fillLevel -= count;
+ }
+};
+
+struct BitStreamCacheRightInLeftOut : BitStreamCacheBase
+{
+ inline void push(uint64 bits, uint32 count) noexcept {
+ assert(count + fillLevel <= Size);
+ cache = cache << count | bits;
+ fillLevel += count;
+ }
+
+ inline uint32 peek(uint32 count) const noexcept {
+ return (cache >> (fillLevel - count)) & ((1 << count) - 1);
+ }
+
+ inline void skip(uint32 count) noexcept {
+ fillLevel -= count;
+ }
+};
+
+template <typename Tag, typename Cache>
+class BitStream final : public ByteStream {
+ Cache cache;
+
+ // this method hase to be implemented in the concrete BitStream template
+ // specializations. It will return the number of bytes processed. It needs
+ // to process up to BitStreamCacheBase::MaxProcessBytes bytes of input.
+ size_type fillCache(const uchar8* input);
+
+public:
+ BitStream() = default;
+
+ explicit BitStream(const ByteStream& s)
+ : ByteStream(s.getSubStream(s.getPosition(), s.getRemainSize())) {}
+
+ // deprecated:
+ BitStream(const Buffer* f, size_type offset)
+ : ByteStream(DataBuffer(f->getSubView(offset))) {}
+
+private:
+ inline void fillSafe() {
+ assert(data);
+ if (pos + BitStreamCacheBase::MaxProcessBytes <= size) {
+ uchar8 tmp[BitStreamCacheBase::MaxProcessBytes] = {0};
+ assert(!(size - pos < BitStreamCacheBase::MaxProcessBytes));
+ memcpy(tmp, data + pos, BitStreamCacheBase::MaxProcessBytes);
+ pos += fillCache(tmp);
+ } else if (pos < size) {
+ uchar8 tmp[BitStreamCacheBase::MaxProcessBytes] = {0};
+ assert(size - pos < BitStreamCacheBase::MaxProcessBytes);
+ memcpy(tmp, data + pos, size - pos);
+ pos += fillCache(tmp);
+ } else if (pos < size + Cache::MaxGetBits / 8) {
+ // yes, this case needs to continue using Cache::MaxGetBits
+ // assert(size <= pos);
+ cache.push(0, Cache::MaxGetBits);
+ pos += Cache::MaxGetBits / 8;
+ } else {
+ // assert(size < pos);
+ ThrowIOE("Buffer overflow read in BitStream");
+ }
+ }
+
+public:
+ inline void fill(uint32 nbits = Cache::MaxGetBits) {
+ assert(data);
+ assert(nbits <= Cache::MaxGetBits);
+ if (cache.fillLevel < nbits) {
+#if defined(DEBUG)
+ // really slow, but best way to check all the assumptions.
+ fillSafe();
+#elif BUFFER_PADDING >= 8
+ static_assert(BitStreamCacheBase::MaxProcessBytes == 8,
+ "update these too");
+ pos += fillCache(data + pos);
+#else
+ // disabling this run-time bounds check saves about 1% on intel x86-64
+ if (pos + BitStreamCacheBase::MaxProcessBytes <= size)
+ pos += fillCache(data + pos);
+ else
+ fillSafe();
+#endif
+ }
+ }
+
+ // these methods might be specialized by implementations that support it
+ inline size_type getBufferPosition() const {
+ return pos - (cache.fillLevel >> 3);
+ }
+
+ // rewinds to the beginning of the buffer.
+ void resetBufferPosition() {
+ pos = 0;
+ cache.fillLevel = 0;
+ cache.cache = 0;
+ }
+
+ void setBufferPosition(size_type newPos);
+
+ inline uint32 __attribute__((pure)) peekBitsNoFill(uint32 nbits) {
+ assert(nbits <= Cache::MaxGetBits);
+ assert(nbits <= cache.fillLevel);
+ return cache.peek(nbits);
+ }
+
+ inline uint32 getBitsNoFill(uint32 nbits) {
+ uint32 ret = peekBitsNoFill(nbits);
+ cache.skip(nbits);
+ return ret;
+ }
+
+ inline void skipBitsNoFill(uint32 nbits) {
+ assert(nbits <= Cache::MaxGetBits);
+ assert(nbits <= cache.fillLevel);
+ cache.skip(nbits);
+ }
+
+ inline uint32 peekBits(uint32 nbits) {
+ fill(nbits);
+ return peekBitsNoFill(nbits);
+ }
+
+ inline uint32 getBits(uint32 nbits) {
+ fill(nbits);
+ return getBitsNoFill(nbits);
+ }
+
+ inline void skipBits(uint32 nbits) {
+ if (nbits > cache.fillLevel)
+ ThrowIOE("skipBits overflow");
+ cache.skip(nbits);
+ }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/Buffer.cpp b/src/external/rawspeed/src/librawspeed/io/Buffer.cpp
new file mode 100644
index 000000000..772746dfd
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/Buffer.cpp
@@ -0,0 +1,129 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h"
+#include "io/Buffer.h"
+#include "common/Common.h" // for uchar8, roundUp
+#include "common/Memory.h" // for alignedFree, alignedMalloc
+#include "io/IOException.h" // for IOException (ptr only), ThrowIOE
+#include <cassert> // for assert
+#include <memory> // for unique_ptr
+
+using std::unique_ptr;
+
+namespace rawspeed {
+
+unique_ptr<uchar8, decltype(&alignedFree)> Buffer::Create(size_type size) {
+ if (!size)
+ ThrowIOE("Trying to allocate 0 bytes sized buffer.");
+
+ unique_ptr<uchar8, decltype(&alignedFree)> data(
+ alignedMalloc<uchar8, 16>(roundUp(size + BUFFER_PADDING, 16)),
+ &alignedFree);
+ if (!data.get())
+ ThrowIOE("Failed to allocate %uz bytes memory buffer.", size);
+
+ assert(!ASAN_REGION_IS_POISONED(data.get(), size));
+
+ return data;
+}
+
+Buffer::Buffer(unique_ptr<uchar8, decltype(&alignedFree)> data_,
+ size_type size_)
+ : size(size_) {
+ if (!size)
+ ThrowIOE("Buffer has zero size?");
+
+ if (data_.get_deleter() != &alignedFree)
+ ThrowIOE("Wrong deleter. Expected rawspeed::alignedFree()");
+
+ data = data_.release();
+ if (!data)
+ ThrowIOE("Memory buffer is nonexistant");
+
+ assert(!ASAN_REGION_IS_POISONED(data, size));
+
+ isOwner = true;
+}
+
+Buffer::~Buffer() {
+ if (isOwner) {
+ alignedFreeConstPtr(data);
+ }
+}
+
+Buffer& Buffer::operator=(Buffer&& rhs) noexcept {
+ if (this == &rhs) {
+ assert(!ASAN_REGION_IS_POISONED(data, size));
+ return *this;
+ }
+
+ if (isOwner)
+ alignedFreeConstPtr(data);
+
+ data = rhs.data;
+ size = rhs.size;
+ isOwner = rhs.isOwner;
+
+ assert(!ASAN_REGION_IS_POISONED(data, size));
+
+ rhs.isOwner = false;
+
+ return *this;
+}
+
+Buffer& Buffer::operator=(const Buffer& rhs) {
+ if (this == &rhs) {
+ assert(!ASAN_REGION_IS_POISONED(data, size));
+ return *this;
+ }
+
+ Buffer unOwningTmp(rhs.data, rhs.size);
+ *this = std::move(unOwningTmp);
+ assert(!isOwner);
+ assert(!ASAN_REGION_IS_POISONED(data, size));
+
+ return *this;
+}
+
+#if 0
+Buffer* Buffer::clone() {
+ Buffer *new_map = new Buffer(size);
+ memcpy(new_map->data, data, size);
+ return new_map;
+}
+
+Buffer* Buffer::cloneRandomSize() {
+ uint32 new_size = (rand() | (rand() << 15)) % size;
+ Buffer *new_map = new Buffer(new_size);
+ memcpy(new_map->data, data, new_size);
+ return new_map;
+}
+
+void Buffer::corrupt(int errors) {
+ for (int i = 0; i < errors; i++) {
+ uint32 pos = (rand() | (rand() << 15)) % size;
+ data[pos] = rand() & 0xff;
+ }
+}
+#endif
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/Buffer.h b/src/external/rawspeed/src/librawspeed/io/Buffer.h
new file mode 100644
index 000000000..8576646d3
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/Buffer.h
@@ -0,0 +1,212 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h"
+#include "common/Common.h" // for uchar8, uint32, uint64
+#include "common/Memory.h" // for alignedFree
+#include "io/Endianness.h" // for getByteSwapped
+#include "io/IOException.h" // for ThrowIOE
+#include <algorithm> // for swap
+#include <cassert> // for assert
+#include <memory> // for unique_ptr
+
+namespace rawspeed {
+
+// This allows to specify the nuber of bytes that each Buffer needs to
+// allocate additionally to be able to remove one runtime bounds check
+// in BitStream::fill. There are two sane choices:
+// 0 : allocate exactly as much data as required, or
+// set it to the value of BitStreamCacheBase::MaxProcessBytes
+#define BUFFER_PADDING 0UL
+
+// if the padding is >= 4, bounds checking in BitStream::fill are not compiled,
+// which supposedly saves about 1% on modern CPUs
+// WARNING: if the padding is >= 4, do *NOT* create Buffer from
+// passed unowning pointer and size. Or, subtract BUFFER_PADDING from size.
+// else bound checks will malfunction => bad things can happen !!!
+
+/*************************************************************************
+ * This is the buffer abstaction.
+ *
+ * It allows access to some piece of memory, typically a whole or part
+ * of a raw file. The underlying memory may be owned by the buffer or not.
+ * It supports move operations to properly deal with owneship transfer.
+ * It intentionally supports only read/const access to the underlying memory.
+ *
+ *************************************************************************/
+class Buffer
+{
+public:
+ using size_type = uint32;
+
+protected:
+ const uchar8* data = nullptr;
+ size_type size = 0;
+ bool isOwner = false;
+
+public:
+ // allocates the databuffer, and returns owning non-const pointer.
+ static std::unique_ptr<uchar8, decltype(&alignedFree)> Create(size_type size);
+
+ // constructs an empty buffer
+ Buffer() = default;
+
+ // Allocates the memory
+ explicit Buffer(size_type size_) : Buffer(Create(size_), size_) {
+ assert(!ASAN_REGION_IS_POISONED(data, size));
+ }
+
+ // creates buffer from owning unique_ptr
+ Buffer(std::unique_ptr<uchar8, decltype(&alignedFree)> data_,
+ size_type size_);
+
+ // Data already allocated
+ explicit Buffer(const uchar8* data_, size_type size_)
+ : data(data_), size(size_) {
+ static_assert(BUFFER_PADDING == 0, "please do make sure that you do NOT "
+ "call this function from YOUR code, and "
+ "then comment-out this assert.");
+ assert(!ASAN_REGION_IS_POISONED(data, size));
+ }
+
+ // creates a (non-owning) copy / view of rhs
+ Buffer(const Buffer& rhs) : data(rhs.data), size(rhs.size) {
+ assert(!ASAN_REGION_IS_POISONED(data, size));
+ }
+
+ // Move data and ownership from rhs to this
+ Buffer(Buffer&& rhs) noexcept
+ : data(rhs.data), size(rhs.size), isOwner(rhs.isOwner) {
+ assert(!ASAN_REGION_IS_POISONED(data, size));
+ rhs.isOwner = false;
+ }
+
+ // Frees memory if owned
+ ~Buffer();
+
+ Buffer& operator=(Buffer&& rhs) noexcept;
+ Buffer& operator=(const Buffer& rhs);
+
+ Buffer getSubView(size_type offset, size_type size_) const {
+ if (!isValid(0, offset))
+ ThrowIOE("Buffer overflow: image file may be truncated");
+
+ return Buffer(getData(offset, size_), size_);
+ }
+
+ Buffer getSubView(size_type offset) const {
+ if (!isValid(0, offset))
+ ThrowIOE("Buffer overflow: image file may be truncated");
+
+ size_type newSize = size - offset;
+ return getSubView(offset, newSize);
+ }
+
+ // get pointer to memory at 'offset', make sure at least 'count' bytes are accessable
+ const uchar8* getData(size_type offset, size_type count) const {
+ if (!isValid(offset, count))
+ ThrowIOE("Buffer overflow: image file may be truncated");
+
+ assert(data);
+ assert(!ASAN_REGION_IS_POISONED(data + offset, count));
+
+ return data + offset;
+ }
+
+ // convenience getter for single bytes
+ uchar8 operator[](size_type offset) const {
+ return *getData(offset, 1);
+ }
+
+ // std begin/end iterators to allow for range loop
+ const uchar8* begin() const {
+ assert(data);
+ assert(!ASAN_REGION_IS_POISONED(data, 0));
+ return data;
+ }
+ const uchar8* end() const {
+ assert(data);
+ assert(!ASAN_REGION_IS_POISONED(data, size));
+ return data + size;
+ }
+
+ // get memory of type T from byte offset 'offset + sizeof(T)*index' and swap byte order if required
+ template<typename T> inline T get(bool inNativeByteOrder, size_type offset, size_type index = 0) const {
+ return getByteSwapped<T>(
+ getData(offset + index * static_cast<size_type>(sizeof(T)),
+ static_cast<size_type>(sizeof(T))),
+ !inNativeByteOrder);
+ }
+
+ inline size_type getSize() const {
+ assert(!ASAN_REGION_IS_POISONED(data, size));
+ return size;
+ }
+
+ inline bool isValid(size_type offset, size_type count = 1) const {
+ return static_cast<uint64>(offset) + count <=
+ static_cast<uint64>(size) + BUFFER_PADDING;
+ }
+
+// Buffer* clone();
+// /* For testing purposes */
+// void corrupt(int errors);
+// Buffer* cloneRandomSize();
+};
+
+/*
+ * DataBuffer is a simple extention to Buffer. It knows about the byte order
+ * of its contents and can therefore provide save access to larger than
+ * byte sized data, like int, float, etc.
+ */
+class DataBuffer : public Buffer {
+ // FIXME: default should be Endianness::unknown !
+
+ Endianness endianness = Endianness::little;
+
+public:
+ DataBuffer() = default;
+
+ explicit DataBuffer(const Buffer& data_,
+ Endianness endianness_ = Endianness::little)
+ : Buffer(data_), endianness(endianness_) {}
+
+ // get memory of type T from byte offset 'offset + sizeof(T)*index' and swap
+ // byte order if required
+ template <typename T>
+ inline T get(size_type offset, size_type index = 0) const {
+ assert(Endianness::unknown != endianness);
+ assert(Endianness::little == endianness || Endianness::big == endianness);
+
+ return Buffer::get<T>(getHostEndianness() == endianness, offset, index);
+ }
+
+ inline Endianness getByteOrder() const { return endianness; }
+
+ inline Endianness setByteOrder(Endianness endianness_) {
+ std::swap(endianness, endianness_);
+ return endianness_;
+ }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/ByteStream.h b/src/external/rawspeed/src/librawspeed/io/ByteStream.h
new file mode 100644
index 000000000..ddb8390d9
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/ByteStream.h
@@ -0,0 +1,245 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h" // for ASAN_REGION_IS_POISONED
+#include "common/Common.h" // for uchar8, int32, uint32, ushort16, roundUp
+#include "common/Memory.h" // for alignedMalloc
+#include "io/Buffer.h" // for Buffer::size_type, Buffer, DataBuffer
+#include "io/Endianness.h" // for Endianness, Endianness::little
+#include "io/IOException.h" // for IOException (ptr only), ThrowIOE
+#include <cassert> // for assert
+#include <cstring> // for memcmp, memcpy
+#include <limits> // for numeric_limits
+
+namespace rawspeed {
+
+class ByteStream : public DataBuffer
+{
+protected:
+ size_type pos = 0; // position of stream in bytes (this is next byte to deliver)
+
+public:
+ ByteStream() = default;
+ explicit ByteStream(const DataBuffer& buffer) : DataBuffer(buffer) {}
+ ByteStream(const Buffer& buffer, size_type offset, size_type size_,
+ Endianness endianness_ = Endianness::little)
+ : DataBuffer(buffer.getSubView(offset, size_), endianness_) {
+ check(0);
+ }
+ ByteStream(const Buffer& buffer, size_type offset,
+ Endianness endianness_ = Endianness::little)
+ : DataBuffer(buffer, endianness_), pos(offset) {
+ check(0);
+ }
+
+ // deprecated:
+ ByteStream(const Buffer* f, size_type offset, size_type size_,
+ Endianness endianness_ = Endianness::little)
+ : ByteStream(*f, offset, size_, endianness_) {}
+ ByteStream(const Buffer* f, size_type offset,
+ Endianness endianness_ = Endianness::little)
+ : ByteStream(*f, offset, endianness_) {}
+
+ // return ByteStream that starts at given offset
+ // i.e. this->data + offset == getSubStream(offset).data
+ ByteStream getSubStream(size_type offset, size_type size_) const {
+ return ByteStream(getSubView(offset, size_), 0, getByteOrder());
+ }
+
+ ByteStream getSubStream(size_type offset) const {
+ return ByteStream(getSubView(offset), 0, getByteOrder());
+ }
+
+ inline size_type check(size_type bytes) const {
+ if (static_cast<uint64>(pos) + bytes > size)
+ ThrowIOE("Out of bounds access in ByteStream");
+ assert(!ASAN_REGION_IS_POISONED(data + pos, bytes));
+ return bytes;
+ }
+
+ inline size_type check(size_type nmemb, size_type size_) const {
+ if (size_ && nmemb > std::numeric_limits<size_type>::max() / size_)
+ ThrowIOE("Integer overflow when calculating stream lenght");
+ return check(nmemb * size_);
+ }
+
+ inline size_type getPosition() const {
+ assert(size >= pos);
+ check(0);
+ return pos;
+ }
+ inline void setPosition(size_type newPos) {
+ pos = newPos;
+ check(0);
+ }
+ inline size_type getRemainSize() const {
+ assert(size >= pos);
+ check(0);
+ return size - pos;
+ }
+ inline const uchar8* peekData(size_type count) const {
+ return Buffer::getData(pos, count);
+ }
+ inline const uchar8* getData(size_type count) {
+ const uchar8* ret = Buffer::getData(pos, count);
+ pos += count;
+ return ret;
+ }
+ inline Buffer getBuffer(size_type size_) {
+ Buffer ret = getSubView(pos, size_);
+ pos += size_;
+ return ret;
+ }
+ inline ByteStream peekStream(size_type size_) const {
+ return getSubStream(pos, size_);
+ }
+ inline ByteStream peekStream(size_type nmemb, size_type size_) const {
+ if (size_ && nmemb > std::numeric_limits<size_type>::max() / size_)
+ ThrowIOE("Integer overflow when calculating stream lenght");
+ return peekStream(nmemb * size_);
+ }
+ inline ByteStream getStream(size_type size_) {
+ ByteStream ret = peekStream(size_);
+ pos += size_;
+ return ret;
+ }
+ inline ByteStream getStream(size_type nmemb, size_type size_) {
+ if (size_ && nmemb > std::numeric_limits<size_type>::max() / size_)
+ ThrowIOE("Integer overflow when calculating stream lenght");
+ return getStream(nmemb * size_);
+ }
+
+ inline uchar8 peekByte(size_type i = 0) const {
+ assert(data);
+ check(i+1);
+ return data[pos+i];
+ }
+
+ inline void skipBytes(size_type nbytes) { pos += check(nbytes); }
+ inline void skipBytes(size_type nmemb, size_type size_) {
+ pos += check(nmemb, size_);
+ }
+
+ inline bool hasPatternAt(const char *pattern, size_type size_,
+ size_type relPos) const {
+ assert(data);
+ if (!isValid(pos + relPos, size_))
+ return false;
+ return memcmp(&data[pos + relPos], pattern, size_) == 0;
+ }
+
+ inline bool hasPrefix(const char *prefix, size_type size_) const {
+ return hasPatternAt(prefix, size_, 0);
+ }
+
+ inline bool skipPrefix(const char *prefix, size_type size_) {
+ bool has_prefix = hasPrefix(prefix, size_);
+ if (has_prefix)
+ pos += size_;
+ return has_prefix;
+ }
+
+ inline uchar8 getByte() {
+ assert(data);
+ check(1);
+ return data[pos++];
+ }
+
+ template<typename T> inline T peek(size_type i = 0) const {
+ return DataBuffer::get<T>(pos, i);
+ }
+
+ inline ushort16 peekU16() { return peek<ushort16>(); }
+
+ template<typename T> inline T get() {
+ auto ret = peek<T>();
+ pos += sizeof(T);
+ return ret;
+ }
+
+ inline ushort16 getU16() { return get<ushort16>(); }
+ inline int32 getI32() { return get<int32>(); }
+ inline uint32 getU32() { return get<uint32>(); }
+ inline float getFloat() { return get<float>(); }
+
+ const char* peekString() const {
+ assert(data);
+ if (memchr(peekData(getRemainSize()), 0, getRemainSize()) == nullptr)
+ ThrowIOE("String is not null-terminated");
+ return reinterpret_cast<const char*>(&data[pos]);
+ }
+
+ // Increments the stream to after the next zero byte and returns the bytes in between (not a copy).
+ // If the first byte is zero, stream is incremented one.
+ const char* getString() {
+ assert(data);
+ size_type start = pos;
+ bool isNullTerminator = false;
+ do {
+ check(1);
+ isNullTerminator = (data[pos] == '\0');
+ pos++;
+ } while (!isNullTerminator);
+ return reinterpret_cast<const char*>(&data[start]);
+ }
+
+ // recalculate the internal data/position information such that current position
+ // i.e. getData() before == getData() after but getPosition() after == newPosition
+ // this is only used for DNGPRIVATEDATA handling to restore the original offset
+ // in case the private data / maker note has been moved within in the file
+ // TODO: could add a lower bound check later if required.
+ void rebase(const size_type newPosition, const size_type newSize) {
+// does that pair (position, size) make sense for this buffer? may throw
+#ifndef NDEBUG
+ const uchar8* const dataRebaseCheck = Buffer::getData(newPosition, newSize);
+#endif
+
+ const uchar8* dataAtNewPosition = getData(newSize);
+ data = dataAtNewPosition - newPosition;
+ size = newPosition + newSize;
+
+#ifndef NDEBUG
+ // buffer sanity self-check. should not throw, unless there is a mistake
+ const uchar8* const rebasedCheck = peekData(size);
+
+ // check that all the assumptions still hold, and we rebased correctly
+ assert(getPosition() == newPosition);
+ assert(getSize() == newSize);
+ assert(dataRebaseCheck == rebasedCheck);
+#endif
+ }
+
+ // special factory function to set up internal buffer with copy of passed data.
+ // only necessary to create 'fake' TiffEntries (see e.g. RAF)
+ static ByteStream createCopy(void* data, size_type size) {
+ ByteStream bs;
+ auto* new_data = alignedMalloc<uchar8, 8>(roundUp(size, 8));
+ memcpy(new_data, data, size);
+ bs.data = new_data;
+ bs.size = size;
+ bs.isOwner = true;
+ return bs; // hint: copy elision or move will happen
+ }
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/CMakeLists.txt b/src/external/rawspeed/src/librawspeed/io/CMakeLists.txt
new file mode 100644
index 000000000..bb1e44094
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/CMakeLists.txt
@@ -0,0 +1,23 @@
+FILE(GLOB SOURCES
+ "BitPumpJPEG.h"
+ "BitPumpLSB.h"
+ "BitPumpMSB.h"
+ "BitPumpMSB16.h"
+ "BitPumpMSB32.h"
+ "BitStream.h"
+ "Buffer.cpp"
+ "Buffer.h"
+ "ByteStream.h"
+ "Endianness.h"
+ "FileIO.h"
+ "FileIOException.h"
+ "FileReader.cpp"
+ "FileReader.h"
+ "FileWriter.cpp"
+ "FileWriter.h"
+ "IOException.h"
+)
+
+target_sources(rawspeed PRIVATE
+ ${SOURCES}
+)
diff --git a/src/external/rawspeed/src/librawspeed/io/Endianness.h b/src/external/rawspeed/src/librawspeed/io/Endianness.h
new file mode 100644
index 000000000..728a1b830
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/Endianness.h
@@ -0,0 +1,125 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, ushort16, uint64, int32, short16
+#include <cassert> // for assert
+#include <cstring> // for memcpy
+
+namespace rawspeed {
+
+enum class Endianness { little = 0xDEAD, big = 0xBEEF, unknown = 0x0BAD };
+
+inline Endianness getHostEndiannessRuntime() {
+ ushort16 testvar = 0xfeff;
+ uint32 firstbyte = (reinterpret_cast<uchar8*>(&testvar))[0];
+ if (firstbyte == 0xff)
+ return Endianness::little;
+ if (firstbyte == 0xfe)
+ return Endianness::big;
+
+ assert(false);
+
+ // Return something to make compilers happy
+ return Endianness::unknown;
+}
+
+inline Endianness getHostEndianness() {
+#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ return Endianness::little;
+#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ return Endianness::big;
+#elif defined(__BYTE_ORDER__)
+#error "uhm, __BYTE_ORDER__ has some strange value"
+#else
+ return getHostEndiannessRuntime();
+#endif
+}
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#define BSWAP16(A) _byteswap_ushort(A)
+#define BSWAP32(A) _byteswap_ulong(A)
+#define BSWAP64(A) _byteswap_uint64(A)
+#else
+#define BSWAP16(A) __builtin_bswap16(A)
+#define BSWAP32(A) __builtin_bswap32(A)
+#define BSWAP64(A) __builtin_bswap64(A)
+#endif
+
+inline short16 getByteSwapped(short16 v) { return BSWAP16(v); }
+inline ushort16 getByteSwapped(ushort16 v) { return BSWAP16(v); }
+inline int32 getByteSwapped(int32 v) { return BSWAP32(v); }
+inline uint32 getByteSwapped(uint32 v) { return BSWAP32(v); }
+inline uint64 getByteSwapped(uint64 v) { return BSWAP64(v); }
+
+// the float/double versions use two memcpy which guarantee strict aliasing
+// and are compiled into the same assembly as the popular union trick.
+inline float getByteSwapped(float f) {
+ uint32 i;
+ memcpy(&i, &f, sizeof(i));
+ i = BSWAP32(i);
+ memcpy(&f, &i, sizeof(i));
+ return f;
+}
+inline double getByteSwapped(double d) {
+ uint64 i;
+ memcpy(&i, &d, sizeof(i));
+ i = BSWAP64(i);
+ memcpy(&d, &i, sizeof(i));
+ return d;
+}
+
+template <typename T> inline T getByteSwapped(const void* data, bool bswap) {
+ T ret;
+ // all interesting compilers optimize this memcpy into a single move
+ // this is the most effective way to load some bytes without running into
+ // alignment or aliasing issues
+ memcpy(&ret, data, sizeof(T));
+ return bswap ? getByteSwapped(ret) : ret;
+}
+
+// The following functions may be used to get a multi-byte sized tyoe from some
+// memory location converted to the native byte order of the host.
+// 'BE' suffix: source byte order is known to be big endian
+// 'LE' suffix: source byte order is known to be little endian
+// Note: these functions should be avoided if higher level acess from
+// Buffer/DataBuffer classes is available.
+
+template <typename T> inline T getBE(const void* data) {
+ return getByteSwapped<T>(data, getHostEndianness() == Endianness::little);
+}
+
+template <typename T> inline T getLE(const void* data) {
+ return getByteSwapped<T>(data, getHostEndianness() == Endianness::big);
+}
+
+inline ushort16 getU16BE(const void* data) { return getBE<ushort16>(data); }
+inline ushort16 getU16LE(const void* data) { return getLE<ushort16>(data); }
+inline uint32 getU32BE(const void* data) { return getBE<uint32>(data); }
+inline uint32 getU32LE(const void* data) { return getLE<uint32>(data); }
+
+#undef BSWAP64
+#undef BSWAP32
+#undef BSWAP16
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/FileIO.h b/src/external/rawspeed/src/librawspeed/io/FileIO.h
new file mode 100644
index 000000000..a5a3ae5ff
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/FileIO.h
@@ -0,0 +1,56 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#if !(defined(__unix__) || defined(__APPLE__))
+
+#include "io/FileIOException.h" // for FileIOException (ptr only), ThrowFIE
+#include <functional> // for bind
+#include <io.h>
+#include <tchar.h>
+#include <vector> // for vector
+#include <windows.h>
+
+namespace rawspeed {
+
+inline std::wstring widenFileName(const char* fileName) {
+ assert(fileName);
+
+ std::wstring wFileName;
+
+ auto f = std::bind(MultiByteToWideChar, CP_UTF8, 0, fileName, -1,
+ std::placeholders::_1, std::placeholders::_2);
+
+ // how many wide characters are needed to store converted string?
+ const auto expectedLen = f(nullptr, 0);
+ wFileName.resize(expectedLen);
+
+ // convert.
+ const auto actualLen = f(&wFileName[0], wFileName.size());
+
+ // did we get expected number of characters?
+ if (actualLen != expectedLen)
+ ThrowFIE("Could not convert filename \"%s\".", fileName);
+
+ return wFileName;
+}
+
+} // namespace rawspeed
+
+#endif
diff --git a/src/external/rawspeed/src/librawspeed/io/FileIOException.h b/src/external/rawspeed/src/librawspeed/io/FileIOException.h
new file mode 100644
index 000000000..4c0b70164
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/FileIOException.h
@@ -0,0 +1,39 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawspeedException.h" // for ThrowExceptionHelper
+#include "decoders/RawDecoderException.h" // for RawDecoderException
+#include <string> // for string
+
+namespace rawspeed {
+
+class FileIOException final : public RawDecoderException {
+public:
+ explicit FileIOException(const std::string& msg) : RawDecoderException(msg) {}
+ explicit FileIOException(const char* msg) : RawDecoderException(msg) {}
+};
+
+#define ThrowFIE(...) \
+ ThrowExceptionHelper(rawspeed::FileIOException, __VA_ARGS__);
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/FileReader.cpp b/src/external/rawspeed/src/librawspeed/io/FileReader.cpp
new file mode 100644
index 000000000..f6d37a915
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/FileReader.cpp
@@ -0,0 +1,117 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "io/FileReader.h"
+#include "io/Buffer.h" // for Buffer
+#include "io/FileIOException.h" // for FileIOException (ptr only), ThrowFIE
+#include <algorithm> // for move
+#include <cstdio> // for fclose, fseek, fopen, fread, ftell
+#include <fcntl.h> // for SEEK_END, SEEK_SET
+#include <limits> // for numeric_limits
+#include <memory> // for unique_ptr
+#include <type_traits> // for make_unsigned
+
+#if !(defined(__unix__) || defined(__APPLE__))
+#include "io/FileIO.h" // for widenFileName
+#include <io.h>
+#include <tchar.h>
+#include <windows.h>
+#endif
+
+namespace rawspeed {
+
+std::unique_ptr<const Buffer> FileReader::readFile() {
+ size_t fileSize = 0;
+
+#if defined(__unix__) || defined(__APPLE__)
+ using file_ptr = std::unique_ptr<FILE, decltype(&fclose)>;
+ file_ptr file(fopen(fileName, "rb"), &fclose);
+
+ if (file == nullptr)
+ ThrowFIE("Could not open file \"%s\".", fileName);
+
+ fseek(file.get(), 0, SEEK_END);
+ const auto size = ftell(file.get());
+
+ if (size <= 0)
+ ThrowFIE("File is 0 bytes.");
+
+ fileSize = static_cast<std::make_unsigned<decltype(size)>::type>(size);
+
+ if (fileSize > std::numeric_limits<Buffer::size_type>::max())
+ ThrowFIE("File is too big (%zu bytes).", fileSize);
+
+ fseek(file.get(), 0, SEEK_SET);
+
+ auto dest = Buffer::Create(fileSize);
+
+ auto bytes_read = fread(dest.get(), 1, fileSize, file.get());
+ if (fileSize != bytes_read) {
+ ThrowFIE("Could not read file, %s.",
+ feof(file.get()) ? "reached end-of-file"
+ : (ferror(file.get()) ? "file reading error"
+ : "unknown problem"));
+ }
+
+#else // __unix__
+
+ auto wFileName = widenFileName(fileName);
+
+ using file_ptr = std::unique_ptr<std::remove_pointer<HANDLE>::type,
+ decltype(&CloseHandle)>;
+ file_ptr file(CreateFileW(wFileName.data(), GENERIC_READ, FILE_SHARE_READ,
+ nullptr, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN,
+ nullptr),
+ &CloseHandle);
+
+ if (file.get() == INVALID_HANDLE_VALUE)
+ ThrowFIE("Could not open file \"%s\".", fileName);
+
+ LARGE_INTEGER size;
+ GetFileSizeEx(file.get(), &size);
+
+ static_assert(
+ std::numeric_limits<Buffer::size_type>::max() ==
+ std::numeric_limits<decltype(size.LowPart)>::max(),
+ "once Buffer migrates to 64-bit index, this needs to be updated.");
+
+ if (size.HighPart > 0)
+ ThrowFIE("File is too big.");
+ if (size.LowPart <= 0)
+ ThrowFIE("File is 0 bytes.");
+
+ auto dest = Buffer::Create(size.LowPart);
+
+ DWORD bytes_read;
+ if (!ReadFile(file.get(), dest.get(), size.LowPart, &bytes_read, nullptr))
+ ThrowFIE("Could not read file.");
+
+ if (size.LowPart != bytes_read)
+ ThrowFIE("Could not read file.");
+
+ fileSize = size.LowPart;
+
+#endif // __unix__
+
+ return std::make_unique<Buffer>(move(dest), fileSize);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/FileReader.h b/src/external/rawspeed/src/librawspeed/io/FileReader.h
new file mode 100644
index 000000000..7efdd1134
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/FileReader.h
@@ -0,0 +1,39 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include <memory> // for unique_ptr
+
+namespace rawspeed {
+
+class Buffer;
+
+class FileReader
+{
+ const char* fileName;
+
+public:
+ explicit FileReader(const char* fileName_) : fileName(fileName_) {}
+
+ std::unique_ptr<const Buffer> readFile();
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/FileWriter.cpp b/src/external/rawspeed/src/librawspeed/io/FileWriter.cpp
new file mode 100644
index 000000000..ead3341f4
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/FileWriter.cpp
@@ -0,0 +1,77 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "io/FileWriter.h"
+#include "common/Common.h" // for uint32
+#include "io/Buffer.h" // for Buffer
+#include "io/FileIOException.h" // for FileIOException
+#include <cstdio> // for fclose, fopen, fwrite, FILE, NULL
+
+#if !defined(__unix__) && !defined(__APPLE__)
+#include "io/FileIO.h" // for widenFileName
+#include <io.h>
+#include <tchar.h>
+#include <windows.h>
+#endif // !defined(__unix__) && !defined(__APPLE__)
+
+namespace rawspeed {
+
+FileWriter::FileWriter(const char *_filename) : mFilename(_filename) {}
+
+void FileWriter::writeFile(Buffer* filemap, uint32 size) {
+ if (size > filemap->getSize())
+ size = filemap->getSize();
+#if defined(__unix__) || defined(__APPLE__)
+ size_t bytes_written = 0;
+ FILE *file;
+
+ file = fopen(mFilename, "wb");
+ if (file == nullptr)
+ ThrowFIE("Could not open file.");
+
+ const auto src = filemap->getData(0, filemap->getSize());
+ bytes_written = fwrite(src, 1, size != 0 ? size : filemap->getSize(), file);
+ fclose(file);
+ if (size != bytes_written) {
+ ThrowFIE("Could not write file.");
+ }
+
+#else // __unix__
+ auto wFileName = widenFileName(mFilename);
+ HANDLE file_h; // File handle
+ file_h =
+ CreateFileW(wFileName.data(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr,
+ CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, nullptr);
+ if (file_h == INVALID_HANDLE_VALUE) {
+ ThrowFIE("Could not open file.");
+ }
+
+ DWORD bytes_written;
+ if (!WriteFile(file_h, filemap->getData(0, filemap->getSize()),
+ size ? size : filemap->getSize(), &bytes_written, nullptr)) {
+ CloseHandle(file_h);
+ ThrowFIE("Could not read file.");
+ }
+ CloseHandle(file_h);
+
+#endif // __unix__
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/FileWriter.h b/src/external/rawspeed/src/librawspeed/io/FileWriter.h
new file mode 100644
index 000000000..639e3830d
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/FileWriter.h
@@ -0,0 +1,42 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+
+namespace rawspeed {
+
+class Buffer;
+
+class FileWriter
+{
+public:
+ explicit FileWriter(const char* filename);
+
+ void writeFile(Buffer* fileMap, uint32 size = 0);
+ const char* Filename() const { return mFilename; }
+ // void Filename(const char * val) { mFilename = val; }
+
+private:
+ const char* mFilename;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/io/IOException.h b/src/external/rawspeed/src/librawspeed/io/IOException.h
new file mode 100644
index 000000000..74f5c038c
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/io/IOException.h
@@ -0,0 +1,37 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawspeedException.h" // for RawspeedException
+#include <string> // for string
+
+namespace rawspeed {
+
+class IOException final : public RawspeedException {
+public:
+ explicit IOException(const std::string& msg) : RawspeedException(msg) {}
+ explicit IOException(const char* msg) : RawspeedException(msg) {}
+};
+
+#define ThrowIOE(...) ThrowExceptionHelper(rawspeed::IOException, __VA_ARGS__)
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/metadata/BlackArea.h b/src/external/rawspeed/src/librawspeed/metadata/BlackArea.h
new file mode 100644
index 000000000..e80aa218d
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/metadata/BlackArea.h
@@ -0,0 +1,36 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+
+namespace rawspeed {
+
+class BlackArea final {
+public:
+ BlackArea(int offset_, int size_, bool isVertical_)
+ : offset(offset_), size(size_), isVertical(isVertical_) {}
+ uint32 offset; // Offset in bayer pixels.
+ uint32 size; // Size in bayer pixels.
+ bool isVertical; // Otherwise horizontal
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/metadata/CMakeLists.txt b/src/external/rawspeed/src/librawspeed/metadata/CMakeLists.txt
new file mode 100644
index 000000000..6b175c675
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/metadata/CMakeLists.txt
@@ -0,0 +1,16 @@
+FILE(GLOB SOURCES
+ "BlackArea.h"
+ "Camera.cpp"
+ "Camera.h"
+ "CameraMetaData.cpp"
+ "CameraMetaData.h"
+ "CameraMetadataException.h"
+ "CameraSensorInfo.cpp"
+ "CameraSensorInfo.h"
+ "ColorFilterArray.cpp"
+ "ColorFilterArray.h"
+)
+
+target_sources(rawspeed PRIVATE
+ ${SOURCES}
+)
diff --git a/src/external/rawspeed/src/librawspeed/metadata/Camera.cpp b/src/external/rawspeed/src/librawspeed/metadata/Camera.cpp
new file mode 100644
index 000000000..f86526866
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/metadata/Camera.cpp
@@ -0,0 +1,335 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "metadata/Camera.h"
+#include "common/Common.h" // for split_string, uint32
+#include "common/Point.h" // for iPoint2D
+#include "metadata/CameraMetadataException.h" // for ThrowCME
+#include <cctype> // for tolower
+#include <cstdio> // for size_t
+#include <map> // for map
+#include <stdexcept> // for out_of_range
+#include <string> // for string, allocator, ope...
+#include <vector> // for vector
+
+#ifdef HAVE_PUGIXML
+#include <pugixml.hpp> // for xml_node, xml_attribute
+using pugi::xml_node;
+#endif
+
+using std::vector;
+using std::string;
+using std::map;
+
+namespace rawspeed {
+
+#ifdef HAVE_PUGIXML
+Camera::Camera(const pugi::xml_node& camera) : cfa(iPoint2D(0, 0)) {
+ make = canonical_make = camera.attribute("make").as_string();
+ if (make.empty())
+ ThrowCME(R"("make" attribute not found.)");
+
+ model = canonical_model = canonical_alias = camera.attribute("model").as_string();
+ // chdk cameras seem to have an empty model?
+ if (!camera.attribute("model")) // (model.empty())
+ ThrowCME(R"("model" attribute not found.)");
+
+ canonical_id = make + " " + model;
+
+ supported = camera.attribute("supported").as_string("yes") == string("yes");
+ mode = camera.attribute("mode").as_string("");
+ decoderVersion = camera.attribute("decoder_version").as_int(0);
+
+ for (xml_node c : camera.children()) {
+ parseCameraChild(c);
+ }
+}
+#endif
+
+Camera::Camera(const Camera* camera, uint32 alias_num) : cfa(iPoint2D(0,0))
+{
+ if (alias_num >= camera->aliases.size())
+ ThrowCME("Internal error, alias number out of range specified.");
+
+ *this = *camera;
+ model = camera->aliases[alias_num];
+ canonical_alias = camera->canonical_aliases[alias_num];
+ aliases.clear();
+ canonical_aliases.clear();
+}
+
+#ifdef HAVE_PUGIXML
+static string name(const xml_node &a) {
+ return string(a.name());
+}
+#endif
+
+const map<char, CFAColor> Camera::char2enum = {
+ {'g', CFA_GREEN}, {'r', CFA_RED}, {'b', CFA_BLUE},
+ {'f', CFA_FUJI_GREEN}, {'c', CFA_CYAN}, {'m', CFA_MAGENTA},
+ {'y', CFA_YELLOW},
+};
+
+const map<string, CFAColor> Camera::str2enum = {
+ {"GREEN", CFA_GREEN}, {"RED", CFA_RED},
+ {"BLUE", CFA_BLUE}, {"FUJI_GREEN", CFA_FUJI_GREEN},
+ {"CYAN", CFA_CYAN}, {"MAGENTA", CFA_MAGENTA},
+ {"YELLOW", CFA_YELLOW},
+};
+
+#ifdef HAVE_PUGIXML
+void Camera::parseCFA(const xml_node &cur) {
+ if (name(cur) != "CFA" && name(cur) != "CFA2")
+ ThrowCME("Not an CFA/CFA2 node!");
+
+ cfa.setSize(iPoint2D(cur.attribute("width").as_int(0),
+ cur.attribute("height").as_int(0)));
+ for (xml_node c : cur.children()) {
+ if (name(c) == "ColorRow") {
+ int y = c.attribute("y").as_int(-1);
+ if (y < 0 || y >= cfa.getSize().y) {
+ ThrowCME("Invalid y coordinate in CFA array of camera %s %s",
+ make.c_str(), model.c_str());
+ }
+ string key = c.child_value();
+ if (static_cast<int>(key.size()) != cfa.getSize().x) {
+ ThrowCME("Invalid number of colors in definition for row %d in "
+ "camera %s %s. Expected %d, found %zu.",
+ y, make.c_str(), model.c_str(), cfa.getSize().x, key.size());
+ }
+ for (size_t x = 0; x < key.size(); ++x) {
+ auto c1 = key[x];
+ CFAColor c2;
+
+ try {
+ c2 = char2enum.at(static_cast<char>(tolower(c1)));
+ } catch (std::out_of_range&) {
+ ThrowCME("Invalid color in CFA array of camera %s %s: %c",
+ make.c_str(), model.c_str(), c1);
+ }
+
+ cfa.setColorAt(iPoint2D(static_cast<int>(x), y), c2);
+ }
+ } else if (name(c) == "Color") {
+ int x = c.attribute("x").as_int(-1);
+ if (x < 0 || x >= cfa.getSize().x) {
+ ThrowCME("Invalid x coordinate in CFA array of camera %s %s",
+ make.c_str(), model.c_str());
+ }
+
+ int y = c.attribute("y").as_int(-1);
+ if (y < 0 || y >= cfa.getSize().y) {
+ ThrowCME("Invalid y coordinate in CFA array of camera %s %s",
+ make.c_str(), model.c_str());
+ }
+
+ auto c1 = c.child_value();
+ CFAColor c2;
+
+ try {
+ c2 = str2enum.at(c1);
+ } catch (std::out_of_range&) {
+ ThrowCME("Invalid color in CFA array of camera %s %s: %s",
+ make.c_str(), model.c_str(), c1);
+ }
+
+ cfa.setColorAt(iPoint2D(x, y), c2);
+ }
+ }
+}
+
+void Camera::parseCrop(const xml_node &cur) {
+ if (name(cur) != "Crop")
+ ThrowCME("Not an Crop node!");
+
+ cropSize.x = cur.attribute("width").as_int(0);
+ cropSize.y = cur.attribute("height").as_int(0);
+ cropPos.x = cur.attribute("x").as_int(0);
+ cropPos.y = cur.attribute("y").as_int(0);
+
+ if (cropPos.x < 0)
+ ThrowCME("Negative X axis crop specified in camera %s %s", make.c_str(),
+ model.c_str());
+ if (cropPos.y < 0)
+ ThrowCME("Negative Y axis crop specified in camera %s %s", make.c_str(),
+ model.c_str());
+}
+
+void Camera::parseBlackAreas(const xml_node &cur) {
+
+ if (name(cur) != "BlackAreas")
+ ThrowCME("Not an BlackAreas node!");
+
+ for (xml_node c : cur.children()) {
+ if (name(c) == "Vertical") {
+ int x = c.attribute("x").as_int(-1);
+ if (x < 0) {
+ ThrowCME(
+ "Invalid x coordinate in vertical BlackArea of in camera %s %s",
+ make.c_str(), model.c_str());
+ }
+
+ int w = c.attribute("width").as_int(-1);
+ if (w < 0) {
+ ThrowCME("Invalid width in vertical BlackArea of in camera %s %s",
+ make.c_str(), model.c_str());
+ }
+
+ blackAreas.emplace_back(x, w, true);
+
+ } else if (name(c) == "Horizontal") {
+
+ int y = c.attribute("y").as_int(-1);
+ if (y < 0) {
+ ThrowCME("Invalid y coordinate in horizontal BlackArea of camera %s %s",
+ make.c_str(), model.c_str());
+ }
+
+ int h = c.attribute("height").as_int(-1);
+ if (h < 0) {
+ ThrowCME("Invalid height in horizontal BlackArea of camera %s %s",
+ make.c_str(), model.c_str());
+ }
+
+ blackAreas.emplace_back(y, h, false);
+ }
+ }
+}
+
+void Camera::parseAliases(const xml_node &cur) {
+ if (name(cur) != "Aliases")
+ ThrowCME("Not an Aliases node!");
+
+ for (xml_node c : cur.children("Alias")) {
+ aliases.emplace_back(c.child_value());
+ canonical_aliases.emplace_back(
+ c.attribute("id").as_string(c.child_value()));
+ }
+}
+
+void Camera::parseHints(const xml_node &cur) {
+ if (name(cur) != "Hints")
+ ThrowCME("Not an Hints node!");
+
+ for (xml_node c : cur.children("Hint")) {
+ string name = c.attribute("name").as_string();
+ if (name.empty())
+ ThrowCME("Could not find name for hint for %s %s camera.", make.c_str(),
+ model.c_str());
+
+ string value = c.attribute("value").as_string();
+
+ hints.add(name, value);
+ }
+}
+
+void Camera::parseID(const xml_node &cur) {
+ if (name(cur) != "ID")
+ ThrowCME("Not an ID node!");
+
+ canonical_make = cur.attribute("make").as_string();
+ if (canonical_make.empty())
+ ThrowCME("Could not find make for ID for %s %s camera.", make.c_str(),
+ model.c_str());
+
+ canonical_alias = canonical_model = cur.attribute("model").as_string();
+ if (canonical_model.empty())
+ ThrowCME("Could not find model for ID for %s %s camera.", make.c_str(),
+ model.c_str());
+
+ canonical_id = cur.child_value();
+}
+
+void Camera::parseSensor(const xml_node &cur) {
+ if (name(cur) != "Sensor")
+ ThrowCME("Not an Sensor node!");
+
+ auto stringToListOfInts = [&cur](const char* attribute) {
+ vector<int> ret;
+ for (const string& s : splitString(cur.attribute(attribute).as_string()))
+ ret.push_back(stoi(s));
+ return ret;
+ };
+
+ int min_iso = cur.attribute("iso_min").as_int(0);
+ int max_iso = cur.attribute("iso_max").as_int(0);
+ int black = cur.attribute("black").as_int(-1);
+ int white = cur.attribute("white").as_int(65536);
+
+ vector<int> black_colors = stringToListOfInts("black_colors");
+ vector<int> iso_list = stringToListOfInts("iso_list");
+ if (!iso_list.empty()) {
+ for (int iso : iso_list) {
+ sensorInfo.emplace_back(black, white, iso, iso, black_colors);
+ }
+ } else {
+ sensorInfo.emplace_back(black, white, min_iso, max_iso, black_colors);
+ }
+}
+
+void Camera::parseCameraChild(const xml_node &cur) {
+ if (name(cur) == "CFA" || name(cur) == "CFA2") {
+ parseCFA(cur);
+ } else if (name(cur) == "Crop") {
+ parseCrop(cur);
+ } else if (name(cur) == "BlackAreas") {
+ parseBlackAreas(cur);
+ } else if (name(cur) == "Aliases") {
+ parseAliases(cur);
+ } else if (name(cur) == "Hints") {
+ parseHints(cur);
+ } else if (name(cur) == "ID") {
+ parseID(cur);
+ } else if (name(cur) == "Sensor") {
+ parseSensor(cur);
+ }
+}
+#endif
+
+const CameraSensorInfo* Camera::getSensorInfo(int iso) const {
+ if (sensorInfo.empty()) {
+ ThrowCME("Camera '%s' '%s', mode '%s' has no <Sensor> entries.",
+ make.c_str(), model.c_str(), mode.c_str());
+ }
+
+ // If only one, just return that
+ if (sensorInfo.size() == 1)
+ return &sensorInfo.front();
+
+ vector<const CameraSensorInfo*> candidates;
+ for (auto& i : sensorInfo) {
+ if (i.isIsoWithin(iso))
+ candidates.push_back(&i);
+ }
+
+ if (candidates.size() == 1)
+ return candidates.front();
+
+ for (auto i : candidates) {
+ if (!i->isDefault())
+ return i;
+ }
+
+ // Several defaults??? Just return first
+ return candidates.front();
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/metadata/Camera.h b/src/external/rawspeed/src/librawspeed/metadata/Camera.h
new file mode 100644
index 000000000..4a650d687
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/metadata/Camera.h
@@ -0,0 +1,121 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h"
+#include "common/Common.h" // for uint32
+#include "common/Point.h" // for iPoint2D
+#include "metadata/BlackArea.h" // for BlackArea
+#include "metadata/CameraSensorInfo.h" // for CameraSensorInfo
+#include "metadata/ColorFilterArray.h" // for ColorFilterArray
+#include <map> // for map, _Rb_tree_const_iterator
+#include <sstream> // for istringstream, basic_istream
+#include <string> // for string, basic_string, operator>>
+#include <utility> // for pair
+#include <vector> // for vector
+
+#ifdef HAVE_PUGIXML
+
+namespace pugi {
+class xml_node;
+} // namespace pugi
+
+#endif
+
+namespace rawspeed {
+
+class Hints
+{
+ std::map<std::string, std::string> data;
+public:
+ void add(const std::string& key, const std::string& value)
+ {
+ data.insert({key, value});
+ }
+
+ bool has(const std::string& key) const
+ {
+ return data.find(key) != data.end();
+ }
+
+ template <typename T>
+ T get(const std::string& key, T defaultValue) const
+ {
+ auto hint = data.find(key);
+ if (hint != data.end() && !hint->second.empty()) {
+ std::istringstream iss(hint->second);
+ iss >> defaultValue;
+ }
+ return defaultValue;
+ }
+
+ bool get(const std::string& key, bool defaultValue) const {
+ auto hint = data.find(key);
+ if (hint == data.end())
+ return defaultValue;
+ return "true" == hint->second;
+ }
+};
+
+class Camera
+{
+public:
+#ifdef HAVE_PUGIXML
+ explicit Camera(const pugi::xml_node& camera);
+#endif
+
+ Camera(const Camera* camera, uint32 alias_num);
+ const CameraSensorInfo* getSensorInfo(int iso) const;
+ std::string make;
+ std::string model;
+ std::string mode;
+ std::string canonical_make;
+ std::string canonical_model;
+ std::string canonical_alias;
+ std::string canonical_id;
+ std::vector<std::string> aliases;
+ std::vector<std::string> canonical_aliases;
+ ColorFilterArray cfa;
+ bool supported;
+ iPoint2D cropSize;
+ iPoint2D cropPos;
+ std::vector<BlackArea> blackAreas;
+ std::vector<CameraSensorInfo> sensorInfo;
+ int decoderVersion;
+ Hints hints;
+protected:
+ static const std::map<char, CFAColor> char2enum;
+ static const std::map<std::string, CFAColor> str2enum;
+
+#ifdef HAVE_PUGIXML
+ void parseCFA(const pugi::xml_node &node);
+ void parseCrop(const pugi::xml_node &node);
+ void parseBlackAreas(const pugi::xml_node &node);
+ void parseAliases(const pugi::xml_node &node);
+ void parseHints(const pugi::xml_node &node);
+ void parseID(const pugi::xml_node &node);
+ void parseSensor(const pugi::xml_node &node);
+
+ void parseCameraChild(const pugi::xml_node &node);
+#endif
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/metadata/CameraMetaData.cpp b/src/external/rawspeed/src/librawspeed/metadata/CameraMetaData.cpp
new file mode 100644
index 000000000..bb60ed5f7
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/metadata/CameraMetaData.cpp
@@ -0,0 +1,161 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "metadata/CameraMetaData.h"
+#include "common/Common.h" // for uint32, trimSpaces
+#include "metadata/Camera.h" // for Camera
+#include "metadata/CameraMetadataException.h" // for ThrowCME
+#include <algorithm> // for find_if
+#include <map> // for _Rb_tree_iterator, map
+#include <string> // for string, operator==
+#include <utility> // for pair
+#include <vector> // for vector
+
+#ifdef HAVE_PUGIXML
+#include <pugixml.hpp> // for xml_document, xml_pars...
+using pugi::xml_node;
+using pugi::xml_document;
+using pugi::xml_parse_result;
+#endif
+
+using std::string;
+
+namespace rawspeed {
+
+#ifdef HAVE_PUGIXML
+CameraMetaData::CameraMetaData(const char *docname) {
+ xml_document doc;
+
+#if defined(__unix__) || defined(__APPLE__)
+ xml_parse_result result = doc.load_file(docname);
+#else
+ xml_parse_result result = doc.load_file(pugi::as_wide(docname).c_str());
+#endif
+
+ if (!result) {
+ ThrowCME(
+ "XML Document could not be parsed successfully. Error was: %s in %s",
+ result.description(), doc.child("node").attribute("attr").value());
+ }
+
+ for (xml_node camera : doc.child("Cameras").children("Camera")) {
+ const auto* cam = addCamera(std::make_unique<Camera>(camera));
+
+ if (cam == nullptr)
+ continue;
+
+ // Create cameras for aliases.
+ for (uint32 i = 0; i < cam->aliases.size(); i++) {
+ addCamera(std::make_unique<Camera>(cam, i));
+ }
+ }
+}
+#endif
+
+static inline CameraId getId(const string& make, const string& model,
+ const string& mode) {
+ CameraId id;
+ id.make = trimSpaces(make);
+ id.model = trimSpaces(model);
+ id.mode = trimSpaces(mode);
+
+ return id;
+}
+
+const Camera* CameraMetaData::getCamera(const string& make, const string& model,
+ const string& mode) const {
+ auto camera = cameras.find(getId(make, model, mode));
+ return camera == cameras.end() ? nullptr : camera->second.get();
+}
+
+const Camera* CameraMetaData::getCamera(const string& make,
+ const string& model) const {
+ auto id = getId(make, model, "");
+
+ auto iter = find_if(cameras.cbegin(), cameras.cend(),
+ [&id](decltype(*cameras.cbegin())& i) -> bool {
+ const auto& cid = i.first;
+ return tie(id.make, id.model) ==
+ tie(cid.make, cid.model);
+ });
+
+ if (iter == cameras.end())
+ return nullptr;
+
+ return iter->second.get();
+}
+
+bool CameraMetaData::hasCamera(const string& make, const string& model,
+ const string& mode) const {
+ return getCamera(make, model, mode);
+}
+
+const Camera* __attribute__((pure))
+CameraMetaData::getChdkCamera(uint32 filesize) const {
+ auto camera = chdkCameras.find(filesize);
+ return camera == chdkCameras.end() ? nullptr : camera->second;
+}
+
+bool __attribute__((pure))
+CameraMetaData::hasChdkCamera(uint32 filesize) const {
+ return chdkCameras.end() != chdkCameras.find(filesize);
+}
+
+const Camera* CameraMetaData::addCamera(std::unique_ptr<Camera> cam) {
+ auto id = getId(cam->make, cam->model, cam->mode);
+ if (cameras.end() != cameras.find(id)) {
+ writeLog(
+ DEBUG_PRIO_WARNING,
+ "CameraMetaData: Duplicate entry found for camera: %s %s, Skipping!",
+ cam->make.c_str(), cam->model.c_str());
+ return nullptr;
+ }
+ cameras[id] = std::move(cam);
+
+ if (string::npos != cameras[id]->mode.find("chdk")) {
+ auto filesize_hint = cameras[id]->hints.get("filesize", string());
+ if (filesize_hint.empty()) {
+ writeLog(DEBUG_PRIO_WARNING,
+ "CameraMetaData: CHDK camera: %s %s, no \"filesize\" hint set!",
+ cameras[id]->make.c_str(), cameras[id]->model.c_str());
+ } else {
+ chdkCameras[stoi(filesize_hint)] = cameras[id].get();
+ // writeLog(DEBUG_PRIO_WARNING, "CHDK camera: %s %s size:%u",
+ // cameras[id]->make.c_str(), cameras[id]->model.c_str(), size);
+ }
+ }
+ return cameras[id].get();
+}
+
+void CameraMetaData::disableMake(const string &make) {
+ for (const auto& cam : cameras) {
+ if (cam.second->make == make)
+ cam.second->supported = false;
+ }
+}
+
+void CameraMetaData::disableCamera(const string &make, const string &model) {
+ for (const auto& cam : cameras) {
+ if (cam.second->make == make && cam.second->model == model)
+ cam.second->supported = false;
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/metadata/CameraMetaData.h b/src/external/rawspeed/src/librawspeed/metadata/CameraMetaData.h
new file mode 100644
index 000000000..31cc442c3
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/metadata/CameraMetaData.h
@@ -0,0 +1,75 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "rawspeedconfig.h"
+#include "common/Common.h" // for uint32
+#include <map> // for map
+#include <memory> // for unique_ptr
+#include <string> // for string
+#include <tuple> // for tuple
+
+namespace rawspeed {
+
+class Camera;
+
+struct CameraId {
+ std::string make;
+ std::string model;
+ std::string mode;
+
+ bool operator<(const CameraId& rhs) const {
+ return std::tie(make, model, mode) <
+ std::tie(rhs.make, rhs.model, rhs.mode);
+ }
+};
+
+class CameraMetaData final {
+public:
+ CameraMetaData() = default;
+
+#ifdef HAVE_PUGIXML
+ explicit CameraMetaData(const char* docname);
+#endif
+
+ std::map<CameraId, std::unique_ptr<Camera>> cameras;
+ std::map<uint32,Camera*> chdkCameras;
+
+ // searches for camera with given make + model + mode
+ const Camera* getCamera(const std::string& make, const std::string& model,
+ const std::string& mode) const;
+
+ // searches for camera with given make + model, with ANY mode
+ const Camera* getCamera(const std::string& make,
+ const std::string& model) const;
+
+ bool hasCamera(const std::string& make, const std::string& model,
+ const std::string& mode) const;
+ const Camera* __attribute__((pure)) getChdkCamera(uint32 filesize) const;
+ bool __attribute__((pure)) hasChdkCamera(uint32 filesize) const;
+ void disableMake(const std::string &make);
+ void disableCamera(const std::string &make, const std::string &model);
+
+protected:
+ const Camera* addCamera(std::unique_ptr<Camera> cam);
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/metadata/CameraMetadataException.h b/src/external/rawspeed/src/librawspeed/metadata/CameraMetadataException.h
new file mode 100644
index 000000000..b9b9fa8de
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/metadata/CameraMetadataException.h
@@ -0,0 +1,39 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawspeedException.h"
+#include <string> // for string
+
+namespace rawspeed {
+
+class CameraMetadataException final : public RawspeedException {
+public:
+ explicit CameraMetadataException(const std::string& msg)
+ : RawspeedException(msg) {}
+ explicit CameraMetadataException(const char* msg) : RawspeedException(msg) {}
+};
+
+#define ThrowCME(...) \
+ ThrowExceptionHelper(rawspeed::CameraMetadataException, __VA_ARGS__)
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/metadata/CameraSensorInfo.cpp b/src/external/rawspeed/src/librawspeed/metadata/CameraSensorInfo.cpp
new file mode 100644
index 000000000..50c90ff58
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/metadata/CameraSensorInfo.cpp
@@ -0,0 +1,43 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2011 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "metadata/CameraSensorInfo.h"
+#include <algorithm> // for move
+#include <vector> // for vector
+
+using std::vector;
+
+namespace rawspeed {
+
+CameraSensorInfo::CameraSensorInfo(int black_level, int white_level,
+ int min_iso, int max_iso,
+ vector<int> black_separate)
+ : mBlackLevel(black_level), mWhiteLevel(white_level), mMinIso(min_iso),
+ mMaxIso(max_iso), mBlackLevelSeparate(std::move(black_separate)) {}
+
+bool __attribute__((pure)) CameraSensorInfo::isIsoWithin(int iso) const {
+ return (iso >= mMinIso && iso <= mMaxIso) || (iso >= mMinIso && 0 == mMaxIso);
+}
+
+bool __attribute__((pure)) CameraSensorInfo::isDefault() const {
+ return (0 == mMinIso && 0 == mMaxIso);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/metadata/CameraSensorInfo.h b/src/external/rawspeed/src/librawspeed/metadata/CameraSensorInfo.h
new file mode 100644
index 000000000..c369e6b25
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/metadata/CameraSensorInfo.h
@@ -0,0 +1,40 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2011 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class CameraSensorInfo final {
+public:
+ CameraSensorInfo(int black_level, int white_level, int min_iso, int max_iso,
+ std::vector<int> black_separate);
+ bool __attribute__((pure)) isIsoWithin(int iso) const;
+ bool __attribute__((pure)) isDefault() const;
+ int mBlackLevel;
+ int mWhiteLevel;
+ int mMinIso;
+ int mMaxIso;
+ std::vector<int> mBlackLevelSeparate;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/metadata/ColorFilterArray.cpp b/src/external/rawspeed/src/librawspeed/metadata/ColorFilterArray.cpp
new file mode 100644
index 000000000..afd1249d5
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/metadata/ColorFilterArray.cpp
@@ -0,0 +1,225 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "metadata/ColorFilterArray.h"
+#include "common/Common.h" // for writeLog, uint32, DEBUG_PR...
+#include "common/Point.h" // for iPoint2D
+#include "decoders/RawDecoderException.h" // for ThrowRDE
+#include <algorithm> // for fill
+#include <cstdarg> // for va_arg, va_end, va_list
+#include <cstdlib> // for size_t, abs
+#include <map> // for map
+#include <stdexcept> // for out_of_range
+#include <string> // for string, allocator
+// IWYU pragma: no_include <bits/std_abs.h>
+
+using std::vector;
+using std::string;
+using std::out_of_range;
+using std::map;
+
+namespace rawspeed {
+
+ColorFilterArray::ColorFilterArray(const iPoint2D &_size) {
+ setSize(_size);
+}
+
+void ColorFilterArray::setSize(const iPoint2D& _size)
+{
+ size = _size;
+
+ if (size.area() > 36) {
+ // Bayer, FC() supports 2x8 pattern
+ // X-Trans is 6x6 pattern
+ // is there anything bigger?
+ ThrowRDE("if your CFA pattern is really %llu pixels "
+ "in area we may as well give up now",
+ size.area());
+ }
+ if (size.area() <= 0)
+ return;
+ cfa.resize(size.area());
+ fill(cfa.begin(), cfa.end(), CFA_UNKNOWN);
+}
+
+CFAColor ColorFilterArray::getColorAt( int x, int y ) const
+{
+ if (cfa.empty())
+ ThrowRDE("No CFA size set");
+
+ // calculate the positive modulo [0 .. size-1]
+ x = (x % size.x + size.x) % size.x;
+ y = (y % size.y + size.y) % size.y;
+
+ return cfa[x + static_cast<size_t>(y) * size.x];
+}
+
+void ColorFilterArray::setCFA( iPoint2D in_size, ... )
+{
+ if (in_size != size) {
+ setSize(in_size);
+ }
+ va_list arguments;
+ va_start(arguments, in_size);
+ for (uint32 i = 0; i < size.area(); i++ ) {
+ cfa[i] = static_cast<CFAColor>(va_arg(arguments, int));
+ }
+ va_end (arguments);
+}
+
+void ColorFilterArray::shiftLeft(int n) {
+ if (cfa.empty())
+ ThrowRDE("No CFA size set (or set to zero)");
+
+ writeLog(DEBUG_PRIO_EXTRA, "Shift left:%d", n);
+ n %= size.x;
+ if (n == 0)
+ return;
+
+ vector<CFAColor> tmp(size.area());
+ for (int y = 0; y < size.y; ++y) {
+ for (int x = 0; x < size.x; ++x) {
+ tmp[x + static_cast<size_t>(y) * size.x] = getColorAt(x + n, y);
+ }
+ }
+ cfa = tmp;
+}
+
+void ColorFilterArray::shiftDown(int n) {
+ if (cfa.empty())
+ ThrowRDE("No CFA size set (or set to zero)");
+
+ writeLog(DEBUG_PRIO_EXTRA, "Shift down:%d", n);
+ n %= size.y;
+ if (n == 0)
+ return;
+ vector<CFAColor> tmp(size.area());
+ for (int y = 0; y < size.y; ++y) {
+ for (int x = 0; x < size.x; ++x) {
+ tmp[x + static_cast<size_t>(y) * size.x] = getColorAt(x, y + n);
+ }
+ }
+ cfa = tmp;
+}
+
+string ColorFilterArray::asString() const {
+ string dst;
+ for (int y = 0; y < size.y; y++) {
+ for (int x = 0; x < size.x; x++) {
+ dst += colorToString(getColorAt(x,y));
+ dst += (x == size.x - 1) ? "\n" : ",";
+ }
+ }
+ return dst;
+}
+
+uint32 ColorFilterArray::shiftDcrawFilter(uint32 filter, int x, int y)
+{
+ // filter is a series of 4 bytes that describe a 2x8 matrix. 2 is the width,
+ // 8 is the height. each byte describes a 2x2 pixel block. so each pixel has
+ // 2 bits of information. This allows to distinguish 4 different colors.
+
+ if (std::abs(x) & 1) {
+ // A shift in x direction means swapping the first and second half of each
+ // nibble.
+ // see http://graphics.stanford.edu/~seander/bithacks.html#SwappingBitsXOR
+ for (int n = 0; n < 8; ++n) {
+ int i = n * 4;
+ int j = i + 2;
+ uint32 t = ((filter >> i) ^ (filter >> j)) & ((1U << 2) - 1);
+ filter = filter ^ ((t << i) | (t << j));
+ }
+ }
+
+ if (y == 0)
+ return filter;
+
+ // A shift in y direction means rotating the whole int by 4 bits.
+ y *= 4;
+ y = y >= 0 ? y % 32 : 32 - ((-y) % 32);
+ filter = (filter >> y) | (filter << (32 - y));
+
+ return filter;
+}
+
+const map<CFAColor, string> ColorFilterArray::color2String = {
+ {CFA_RED, "RED"}, {CFA_GREEN, "GREEN"},
+ {CFA_BLUE, "BLUE"}, {CFA_CYAN, "CYAN"},
+ {CFA_MAGENTA, "MAGENTA"}, {CFA_YELLOW, "YELLOW"},
+ {CFA_WHITE, "WHITE"}, {CFA_FUJI_GREEN, "FUJIGREEN"},
+ {CFA_UNKNOWN, "UNKNOWN"}};
+
+string ColorFilterArray::colorToString(CFAColor c)
+{
+ try {
+ return color2String.at(c);
+ } catch (std::out_of_range&) {
+ ThrowRDE("Unsupported CFA Color: %u", c);
+ }
+}
+
+void ColorFilterArray::setColorAt(iPoint2D pos, CFAColor c) {
+ if (pos.x >= size.x || pos.x < 0)
+ ThrowRDE("position out of CFA pattern");
+ if (pos.y >= size.y || pos.y < 0)
+ ThrowRDE("position out of CFA pattern");
+ cfa[pos.x + static_cast<size_t>(pos.y) * size.x] = c;
+}
+
+static uint32 toDcrawColor( CFAColor c )
+{
+ switch (c) {
+ case CFA_FUJI_GREEN:
+ case CFA_RED: return 0;
+ case CFA_MAGENTA:
+ case CFA_GREEN: return 1;
+ case CFA_CYAN:
+ case CFA_BLUE: return 2;
+ case CFA_YELLOW: return 3;
+ default:
+ throw out_of_range(ColorFilterArray::colorToString(c));
+ }
+}
+
+uint32 ColorFilterArray::getDcrawFilter() const
+{
+ //dcraw magic
+ if (size.x == 6 && size.y == 6)
+ return 9;
+
+ if (cfa.empty() || size.x > 2 || size.y > 8 || !isPowerOfTwo(size.y))
+ return 1;
+
+ uint32 ret = 0;
+ for (int x = 0; x < 2; x++) {
+ for (int y = 0; y < 8; y++) {
+ uint32 c = toDcrawColor(getColorAt(x,y));
+ int g = (x >> 1) * 8;
+ ret |= c << ((x&1)*2 + y*4 + g);
+ }
+ }
+
+ writeLog(DEBUG_PRIO_EXTRA, "%s", asString().c_str());
+ writeLog(DEBUG_PRIO_EXTRA, "DCRAW filter:%x", ret);
+
+ return ret;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/metadata/ColorFilterArray.h b/src/external/rawspeed/src/librawspeed/metadata/ColorFilterArray.h
new file mode 100644
index 000000000..8b66e75fa
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/metadata/ColorFilterArray.h
@@ -0,0 +1,78 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "common/Point.h" // for iPoint2D
+#include <map> // for map
+#include <string> // for string
+#include <vector> // for vector
+
+namespace rawspeed {
+
+enum CFAColor : uchar8 {
+ // see also DngDecoder
+ CFA_RED = 0,
+ CFA_GREEN = 1,
+ CFA_BLUE = 2,
+ CFA_CYAN = 3,
+ CFA_MAGENTA = 4,
+ CFA_YELLOW = 5,
+ CFA_WHITE = 6,
+ CFA_FUJI_GREEN = 7,
+ CFA_END, // keep it last!
+ CFA_UNKNOWN = 255,
+
+};
+
+class ColorFilterArray
+{
+ std::vector<CFAColor> cfa;
+ iPoint2D size;
+
+public:
+ ColorFilterArray() = default;
+ explicit ColorFilterArray(const iPoint2D& size);
+
+ void setSize(const iPoint2D& size);
+ void setColorAt(iPoint2D pos, CFAColor c);
+ void setCFA(iPoint2D size, ...);
+ void shiftLeft(int n = 1);
+ void shiftDown(int n = 1);
+
+ CFAColor getColorAt(int x, int y) const;
+ uint32 getDcrawFilter() const;
+ std::string asString() const;
+ iPoint2D getSize() const { return size; }
+
+ static std::string colorToString(CFAColor c);
+ static uint32 __attribute__((const))
+ shiftDcrawFilter(uint32 filter, int x, int y);
+
+protected:
+ static const std::map<CFAColor, std::string> color2String;
+};
+
+// FC macro from dcraw outputs, given the filters definition, the dcraw color
+// number for that given position in the CFA pattern
+// #define FC(filters,row,col) ((filters) >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/CMakeLists.txt b/src/external/rawspeed/src/librawspeed/parsers/CMakeLists.txt
new file mode 100644
index 000000000..453c2dc11
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/CMakeLists.txt
@@ -0,0 +1,18 @@
+FILE(GLOB SOURCES
+ "CiffParser.cpp"
+ "CiffParser.h"
+ "CiffParserException.h"
+ "FiffParser.cpp"
+ "FiffParser.h"
+ "FiffParserException.h"
+ "RawParser.cpp"
+ "RawParser.h"
+ "RawParserException.h"
+ "TiffParser.cpp"
+ "TiffParser.h"
+ "TiffParserException.h"
+)
+
+target_sources(rawspeed PRIVATE
+ ${SOURCES}
+)
diff --git a/src/external/rawspeed/src/librawspeed/parsers/CiffParser.cpp b/src/external/rawspeed/src/librawspeed/parsers/CiffParser.cpp
new file mode 100644
index 000000000..0a95dceed
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/CiffParser.cpp
@@ -0,0 +1,76 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "parsers/CiffParser.h"
+#include "common/Common.h" // for make_unique, trimSpaces
+#include "common/NORangesSet.h" // for NORangesSet
+#include "decoders/CrwDecoder.h" // for CrwDecoder
+#include "decoders/RawDecoder.h" // for RawDecoder
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for getHostEndianness, Endianne...
+#include "parsers/CiffParserException.h" // for CiffParserException (ptr only)
+#include "tiff/CiffEntry.h" // for CiffEntry
+#include "tiff/CiffIFD.h" // for CiffIFD
+#include "tiff/CiffTag.h" // for CiffTag::CIFF_MAKEMODEL
+#include <memory> // for unique_ptr, default_delete
+#include <string> // for operator==, basic_string
+#include <utility> // for move, pair
+
+using std::string;
+
+namespace rawspeed {
+
+CiffParser::CiffParser(const Buffer* inputData) : RawParser(inputData) {}
+
+void CiffParser::parseData() {
+ ByteStream bs(*mInput, 0);
+ bs.setByteOrder(Endianness::little);
+
+ ushort16 magic = bs.getU16();
+ if (magic != 0x4949)
+ ThrowCPE("Not a CIFF file (ID)");
+
+ NORangesSet<Buffer> ifds;
+
+ // Offset to the beginning of the CIFF
+ ByteStream subStream(bs.getSubStream(bs.getByte()));
+ mRootIFD = std::make_unique<CiffIFD>(nullptr, &ifds, &subStream);
+}
+
+std::unique_ptr<RawDecoder> CiffParser::getDecoder(const CameraMetaData* meta) {
+ if (!mRootIFD)
+ parseData();
+
+ const auto potentials(mRootIFD->getIFDsWithTag(CIFF_MAKEMODEL));
+
+ for (const auto& potential : potentials) {
+ const auto mm = potential->getEntry(CIFF_MAKEMODEL);
+ const string make = trimSpaces(mm->getString());
+
+ if (make == "Canon")
+ return std::make_unique<CrwDecoder>(move(mRootIFD), mInput);
+ }
+
+ ThrowCPE("No decoder found. Sorry.");
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/CiffParser.h b/src/external/rawspeed/src/librawspeed/parsers/CiffParser.h
new file mode 100644
index 000000000..830083858
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/CiffParser.h
@@ -0,0 +1,48 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "parsers/RawParser.h" // for RawParser
+#include "tiff/CiffIFD.h" // for CiffIFD
+#include <memory> // for unique_ptr
+
+namespace rawspeed {
+
+class Buffer;
+
+class RawDecoder;
+
+class CameraMetaData;
+
+class CiffParser final : public RawParser {
+ std::unique_ptr<const CiffIFD> mRootIFD;
+
+public:
+ explicit CiffParser(const Buffer* input);
+
+ void parseData();
+
+ std::unique_ptr<RawDecoder>
+ getDecoder(const CameraMetaData* meta = nullptr) override;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/CiffParserException.h b/src/external/rawspeed/src/librawspeed/parsers/CiffParserException.h
new file mode 100644
index 000000000..8803fb140
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/CiffParserException.h
@@ -0,0 +1,41 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawspeedException.h" // for ThrowExceptionHelper
+#include "parsers/RawParserException.h" // for ThrowRPE, RawParserException
+#include <string>
+
+namespace rawspeed {
+
+class CiffParserException final : public RawParserException {
+public:
+ explicit CiffParserException(const std::string& msg)
+ : RawParserException(msg) {}
+ explicit CiffParserException(const char* msg) : RawParserException(msg) {}
+};
+
+#define ThrowCPE(...) \
+ ThrowExceptionHelper(rawspeed::CiffParserException, __VA_ARGS__)
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/FiffParser.cpp b/src/external/rawspeed/src/librawspeed/parsers/FiffParser.cpp
new file mode 100644
index 000000000..8d5cb1065
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/FiffParser.cpp
@@ -0,0 +1,138 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+ Copyright (C) 2017-2018 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "parsers/FiffParser.h"
+#include "common/Common.h" // for make_unique, uint32, uchar8
+#include "decoders/RafDecoder.h" // for RafDecoder
+#include "decoders/RawDecoder.h" // for RawDecoder
+#include "io/Buffer.h" // for Buffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for getU32BE, getHostEndianness
+#include "parsers/FiffParserException.h" // for ThrowFPE
+#include "parsers/RawParser.h" // for RawParser
+#include "parsers/TiffParser.h" // for TiffParser::parse, TiffParser::makeDecoder
+#include "parsers/TiffParserException.h" // for TiffParserException
+#include "tiff/TiffEntry.h" // for TiffEntry, TiffDataType::TI...
+#include "tiff/TiffIFD.h" // for TiffIFD, TiffRootIFD, TiffI...
+#include "tiff/TiffTag.h" // for TiffTag, TiffTag::FUJIOLDWB
+#include <algorithm> // for move
+#include <limits> // for numeric_limits
+#include <memory> // for default_delete, unique_ptr
+
+using std::numeric_limits;
+
+namespace rawspeed {
+
+FiffParser::FiffParser(const Buffer* inputData) : RawParser(inputData) {}
+
+void FiffParser::parseData() {
+ ByteStream bs(DataBuffer(*mInput, Endianness::big));
+ bs.skipBytes(0x54);
+
+ uint32 first_ifd = bs.getU32();
+ if (first_ifd >= numeric_limits<uint32>::max() - 12)
+ ThrowFPE("Not Fiff. First IFD too far away");
+
+ first_ifd += 12;
+
+ bs.skipBytes(4);
+ const uint32 third_ifd = bs.getU32();
+ bs.skipBytes(4);
+ const uint32 second_ifd = bs.getU32();
+
+ rootIFD = TiffParser::parse(mInput->getSubView(first_ifd));
+ TiffIFDOwner subIFD = std::make_unique<TiffIFD>(rootIFD.get());
+
+ if (mInput->isValid(second_ifd)) {
+ // RAW Tiff on newer models, pointer to raw data on older models
+ // -> so we try parsing as Tiff first and add it as data if parsing fails
+ try {
+ rootIFD->add(TiffParser::parse(mInput->getSubView(second_ifd)));
+ } catch (TiffParserException&) {
+ // the offset will be interpreted relative to the rootIFD where this
+ // subIFD gets inserted
+
+ if (second_ifd <= first_ifd)
+ ThrowFPE("Fiff is corrupted: second IFD is not after the first IFD");
+
+ uint32 rawOffset = second_ifd - first_ifd;
+ subIFD->add(std::make_unique<TiffEntry>(
+ subIFD.get(), FUJI_STRIPOFFSETS, TIFF_OFFSET, 1,
+ ByteStream::createCopy(&rawOffset, 4)));
+ uint32 max_size = mInput->getSize() - second_ifd;
+ subIFD->add(std::make_unique<TiffEntry>(
+ subIFD.get(), FUJI_STRIPBYTECOUNTS, TIFF_LONG, 1,
+ ByteStream::createCopy(&max_size, 4)));
+ }
+ }
+
+ if (mInput->isValid(third_ifd)) {
+ // RAW information IFD on older
+
+ // This Fuji directory structure is similar to a Tiff IFD but with two
+ // differences:
+ // a) no type info and b) data is always stored in place.
+ // 4b: # of entries, for each entry: 2b tag, 2b len, xb data
+ ByteStream bytes(mInput, third_ifd, Endianness::big);
+ uint32 entries = bytes.getU32();
+
+ if (entries > 255)
+ ThrowFPE("Too many entries");
+
+ for (uint32 i = 0; i < entries; i++) {
+ ushort16 tag = bytes.getU16();
+ ushort16 length = bytes.getU16();
+ TiffDataType type = TIFF_UNDEFINED;
+
+ if (tag == IMAGEWIDTH || tag == FUJIOLDWB) // also 0x121?
+ type = TIFF_SHORT;
+
+ uint32 count = type == TIFF_SHORT ? length / 2 : length;
+ subIFD->add(std::make_unique<TiffEntry>(
+ subIFD.get(), static_cast<TiffTag>(tag), type, count,
+ bytes.getSubStream(bytes.getPosition(), length)));
+
+ bytes.skipBytes(length);
+ }
+ }
+
+ rootIFD->add(move(subIFD));
+}
+
+std::unique_ptr<RawDecoder> FiffParser::getDecoder(const CameraMetaData* meta) {
+ if (!rootIFD)
+ parseData();
+
+ // WARNING: do *NOT* fallback to ordinary TIFF parser here!
+ // All the FIFF raws are '.RAF' (Fujifilm). Do use RafDecoder directly.
+
+ try {
+ if (!RafDecoder::isAppropriateDecoder(rootIFD.get(), mInput))
+ ThrowFPE("Not a FUJIFILM RAF FIFF.");
+
+ return std::make_unique<RafDecoder>(std::move(rootIFD), mInput);
+ } catch (TiffParserException&) {
+ ThrowFPE("No decoder found. Sorry.");
+ }
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/FiffParser.h b/src/external/rawspeed/src/librawspeed/parsers/FiffParser.h
new file mode 100644
index 000000000..bdc7e6a8e
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/FiffParser.h
@@ -0,0 +1,46 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "parsers/RawParser.h" // for RawParser
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <memory> // for unique_ptr
+
+namespace rawspeed {
+
+class Buffer;
+
+class CameraMetaData;
+
+class RawDecoder;
+
+class FiffParser final : public RawParser {
+ TiffRootIFDOwner rootIFD;
+
+public:
+ explicit FiffParser(const Buffer* input);
+
+ void parseData();
+ std::unique_ptr<RawDecoder>
+ getDecoder(const CameraMetaData* meta = nullptr) override;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/FiffParserException.h b/src/external/rawspeed/src/librawspeed/parsers/FiffParserException.h
new file mode 100644
index 000000000..d6cb98279
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/FiffParserException.h
@@ -0,0 +1,39 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawspeedException.h" // for ThrowExceptionHelper
+#include "parsers/RawParserException.h" // for ThrowRPE, RawParserException
+#include <string>
+
+namespace rawspeed {
+
+class FiffParserException final : public RawParserException {
+public:
+ explicit FiffParserException(const std::string& msg)
+ : RawParserException(msg) {}
+ explicit FiffParserException(const char* msg) : RawParserException(msg) {}
+};
+
+#define ThrowFPE(...) \
+ ThrowExceptionHelper(rawspeed::FiffParserException, __VA_ARGS__)
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/RawParser.cpp b/src/external/rawspeed/src/librawspeed/parsers/RawParser.cpp
new file mode 100644
index 000000000..151eb4666
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/RawParser.cpp
@@ -0,0 +1,94 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "parsers/RawParser.h"
+#include "decoders/MrwDecoder.h" // for MrwDecoder
+#include "decoders/NakedDecoder.h" // for NakedDecoder
+#include "decoders/RafDecoder.h" // for RafDecoder
+#include "decoders/RawDecoder.h" // for RawDecoder
+#include "decoders/RawDecoderException.h" // for RawDecoderException, ThrowRDE
+#include "io/Buffer.h" // for Buffer
+#include "metadata/CameraMetaData.h" // for CameraMetaData
+#include "parsers/CiffParser.h" // for CiffParser
+#include "parsers/CiffParserException.h" // for CiffParserException
+#include "parsers/FiffParser.h" // for FiffParser
+#include "parsers/FiffParserException.h" // for FiffParserException
+#include "parsers/TiffParser.h" // for TiffParser
+#include "parsers/TiffParserException.h" // for TiffParserException
+
+namespace rawspeed {
+
+class Camera;
+
+std::unique_ptr<RawDecoder> RawParser::getDecoder(const CameraMetaData* meta) {
+ // We need some data.
+ // For now it is 104 bytes for RAF/FUJIFIM images.
+ // FIXME: each decoder/parser should check it on their own.
+ if (mInput->getSize() <= 104)
+ ThrowRDE("File too small");
+
+ // MRW images are easy to check for, let's try that first
+ if (MrwDecoder::isMRW(mInput)) {
+ try {
+ return std::make_unique<MrwDecoder>(mInput);
+ } catch (RawDecoderException &) {
+ }
+ }
+
+ // FUJI has pointers to IFD's at fixed byte offsets
+ // So if camera is FUJI, we cannot use ordinary TIFF parser
+ if (RafDecoder::isRAF(mInput)) {
+ try {
+ FiffParser p(mInput);
+ return p.getDecoder(meta);
+ } catch (FiffParserException&) {
+ }
+ }
+
+ // Ordinary TIFF images
+ try {
+ TiffParser p(mInput);
+ return p.getDecoder(meta);
+ } catch (TiffParserException &) {
+ }
+
+ // CIFF images
+ try {
+ CiffParser p(mInput);
+ return p.getDecoder(meta);
+ } catch (CiffParserException &) {
+ }
+
+ // Detect camera on filesize (CHDK).
+ if (meta != nullptr && meta->hasChdkCamera(mInput->getSize())) {
+ const Camera* c = meta->getChdkCamera(mInput->getSize());
+
+ try {
+ return std::make_unique<NakedDecoder>(mInput, c);
+ } catch (RawDecoderException &) {
+ }
+ }
+
+ // File could not be decoded, so no further options for now.
+ ThrowRDE("No decoder found. Sorry.");
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/RawParser.h b/src/external/rawspeed/src/librawspeed/parsers/RawParser.h
new file mode 100644
index 000000000..6580e22c2
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/RawParser.h
@@ -0,0 +1,45 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include <memory> // for unique_ptr
+
+namespace rawspeed {
+
+class Buffer;
+
+class CameraMetaData;
+
+class RawDecoder;
+
+class RawParser {
+public:
+ explicit RawParser(const Buffer* inputData) : mInput(inputData) {}
+ virtual ~RawParser() = default;
+
+ virtual std::unique_ptr<RawDecoder>
+ getDecoder(const CameraMetaData* meta = nullptr);
+
+protected:
+ const Buffer* mInput;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/RawParserException.h b/src/external/rawspeed/src/librawspeed/parsers/RawParserException.h
new file mode 100644
index 000000000..c93a3f69d
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/RawParserException.h
@@ -0,0 +1,38 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawspeedException.h"
+#include <string>
+
+namespace rawspeed {
+
+class RawParserException : public RawspeedException {
+public:
+ explicit RawParserException(const std::string& msg)
+ : RawspeedException(msg) {}
+ explicit RawParserException(const char* msg) : RawspeedException(msg) {}
+};
+
+#define ThrowRPE(...) \
+ ThrowExceptionHelper(rawspeed::RawParserException, __VA_ARGS__)
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/TiffParser.cpp b/src/external/rawspeed/src/librawspeed/parsers/TiffParser.cpp
new file mode 100644
index 000000000..6125bc3ca
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/TiffParser.cpp
@@ -0,0 +1,147 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Axel Waggershauser
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "parsers/TiffParser.h"
+#include "common/Common.h" // for make_unique, trimSpaces
+#include "common/NORangesSet.h" // for NORangesSet
+#include "decoders/ArwDecoder.h" // for ArwDecoder
+#include "decoders/Cr2Decoder.h" // for Cr2Decoder
+#include "decoders/DcrDecoder.h" // for DcrDecoder
+#include "decoders/DcsDecoder.h" // for DcsDecoder
+#include "decoders/DngDecoder.h" // for DngDecoder
+#include "decoders/ErfDecoder.h" // for ErfDecoder
+#include "decoders/IiqDecoder.h" // for IiqDecoder
+#include "decoders/KdcDecoder.h" // for KdcDecoder
+#include "decoders/MefDecoder.h" // for MefDecoder
+#include "decoders/MosDecoder.h" // for MosDecoder
+#include "decoders/NefDecoder.h" // for NefDecoder
+#include "decoders/OrfDecoder.h" // for OrfDecoder
+#include "decoders/PefDecoder.h" // for PefDecoder
+#include "decoders/RafDecoder.h" // for RafDecoder
+#include "decoders/RawDecoder.h" // for RawDecoder
+#include "decoders/Rw2Decoder.h" // for Rw2Decoder
+#include "decoders/SrwDecoder.h" // for SrwDecoder
+#include "decoders/ThreefrDecoder.h" // for ThreefrDecoder
+#include "io/ByteStream.h" // for ByteStream
+#include "parsers/TiffParserException.h" // for TiffParserException
+#include <cassert> // for assert
+#include <cstdint> // for UINT32_MAX
+#include <memory> // for unique_ptr
+#include <string> // for operator==, basic_string
+#include <tuple> // for tie, tuple
+#include <vector> // for vector
+// IWYU pragma: no_include <ext/alloc_traits.h>
+
+using std::string;
+
+namespace rawspeed {
+
+TiffParser::TiffParser(const Buffer* file) : RawParser(file) {}
+
+std::unique_ptr<RawDecoder> TiffParser::getDecoder(const CameraMetaData* meta) {
+ return TiffParser::makeDecoder(TiffParser::parse(*mInput), *mInput);
+}
+
+TiffRootIFDOwner TiffParser::parse(const Buffer& data) {
+ ByteStream bs(data, 0);
+ bs.setByteOrder(getTiffByteOrder(bs, 0, "TIFF header"));
+ bs.skipBytes(2);
+
+ ushort16 magic = bs.getU16();
+ if (magic != 42 && magic != 0x4f52 && magic != 0x5352 && magic != 0x55) // ORF has 0x4f52/0x5352, RW2 0x55 - Brillant!
+ ThrowTPE("Not a TIFF file (magic 42)");
+
+ TiffRootIFDOwner root = std::make_unique<TiffRootIFD>(
+ nullptr, nullptr, bs,
+ UINT32_MAX); // tell TiffIFD constructur not to parse bs as IFD
+
+ NORangesSet<Buffer> ifds;
+
+ for (uint32 IFDOffset = bs.getU32(); IFDOffset;
+ IFDOffset = root->getSubIFDs().back()->getNextIFD()) {
+ root->add(std::make_unique<TiffIFD>(root.get(), &ifds, bs, IFDOffset));
+ }
+
+ return root;
+}
+
+std::unique_ptr<RawDecoder> TiffParser::makeDecoder(TiffRootIFDOwner root,
+ const Buffer& data) {
+ const Buffer* mInput = &data;
+ if (!root)
+ ThrowTPE("TiffIFD is null.");
+
+ for (const auto& decoder : Map) {
+ checker_t dChecker = nullptr;
+ constructor_t dConstructor = nullptr;
+
+ std::tie(dChecker, dConstructor) = decoder;
+
+ assert(dChecker);
+ assert(dConstructor);
+
+ if (!dChecker(root.get(), mInput))
+ continue;
+
+ return dConstructor(move(root), mInput);
+ }
+
+ ThrowTPE("No decoder found. Sorry.");
+}
+
+template <class Decoder>
+std::unique_ptr<RawDecoder> TiffParser::constructor(TiffRootIFDOwner&& root,
+ const Buffer* data) {
+ return std::make_unique<Decoder>(std::move(root), data);
+}
+
+#define DECODER(name) \
+ { \
+ std::make_pair( \
+ static_cast<TiffParser::checker_t>(&name::isAppropriateDecoder), \
+ &constructor<name>) \
+ }
+
+const std::array<std::pair<TiffParser::checker_t, TiffParser::constructor_t>,
+ 16>
+ TiffParser::Map = {{
+ DECODER(DngDecoder),
+ DECODER(MosDecoder),
+ DECODER(IiqDecoder),
+ DECODER(Cr2Decoder),
+ DECODER(NefDecoder),
+ DECODER(OrfDecoder),
+ DECODER(ArwDecoder),
+ DECODER(PefDecoder),
+ DECODER(Rw2Decoder),
+ DECODER(SrwDecoder),
+ DECODER(MefDecoder),
+ DECODER(DcrDecoder),
+ DECODER(DcsDecoder),
+ DECODER(KdcDecoder),
+ DECODER(ErfDecoder),
+ DECODER(ThreefrDecoder),
+
+ }};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/TiffParser.h b/src/external/rawspeed/src/librawspeed/parsers/TiffParser.h
new file mode 100644
index 000000000..861f7a03d
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/TiffParser.h
@@ -0,0 +1,60 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "decoders/RawDecoder.h" // IWYU pragma: keep
+#include "parsers/RawParser.h" // for RawParser
+#include "tiff/TiffIFD.h" // for TiffRootIFDOwner
+#include <array> // for array
+#include <memory> // for unique_ptr
+#include <utility> // for pair
+
+namespace rawspeed {
+
+class Buffer;
+
+class CameraMetaData;
+
+class TiffParser final : public RawParser {
+public:
+ explicit TiffParser(const Buffer* file);
+
+ std::unique_ptr<RawDecoder>
+ getDecoder(const CameraMetaData* meta = nullptr) override;
+
+ // TiffRootIFDOwner contains pointers into 'data' but if is is non-owning, it
+ // may be deleted immediately
+ static TiffRootIFDOwner parse(const Buffer& data);
+
+ // transfers ownership of TiffIFD into RawDecoder
+ static std::unique_ptr<RawDecoder> makeDecoder(TiffRootIFDOwner root,
+ const Buffer& data);
+
+ template <class Decoder>
+ static std::unique_ptr<RawDecoder> constructor(TiffRootIFDOwner&& root,
+ const Buffer* data);
+ using checker_t = bool (*)(const TiffRootIFD* root, const Buffer* data);
+ using constructor_t = std::unique_ptr<RawDecoder> (*)(TiffRootIFDOwner&& root,
+ const Buffer* data);
+ static const std::array<std::pair<checker_t, constructor_t>, 16> Map;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/parsers/TiffParserException.h b/src/external/rawspeed/src/librawspeed/parsers/TiffParserException.h
new file mode 100644
index 000000000..6cb30fba0
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/parsers/TiffParserException.h
@@ -0,0 +1,40 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/RawspeedException.h" // for ThrowExceptionHelper
+#include "parsers/RawParserException.h" // for ThrowRPE, RawParserException
+#include <string>
+
+namespace rawspeed {
+
+class TiffParserException final : public RawParserException {
+public:
+ explicit TiffParserException(const std::string& msg)
+ : RawParserException(msg) {}
+ explicit TiffParserException(const char* msg) : RawParserException(msg) {}
+};
+
+#define ThrowTPE(...) \
+ ThrowExceptionHelper(rawspeed::TiffParserException, __VA_ARGS__)
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/tiff/CMakeLists.txt b/src/external/rawspeed/src/librawspeed/tiff/CMakeLists.txt
new file mode 100644
index 000000000..6c2f6d417
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/tiff/CMakeLists.txt
@@ -0,0 +1,16 @@
+FILE(GLOB SOURCES
+ "TiffEntry.cpp"
+ "TiffEntry.h"
+ "TiffIFD.cpp"
+ "TiffIFD.h"
+ "TiffTag.h"
+ "CiffEntry.cpp"
+ "CiffEntry.h"
+ "CiffIFD.cpp"
+ "CiffIFD.h"
+ "CiffTag.h"
+)
+
+target_sources(rawspeed PRIVATE
+ ${SOURCES}
+)
diff --git a/src/external/rawspeed/src/librawspeed/tiff/CiffEntry.cpp b/src/external/rawspeed/src/librawspeed/tiff/CiffEntry.cpp
new file mode 100644
index 000000000..b80a85e5a
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/tiff/CiffEntry.cpp
@@ -0,0 +1,167 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "tiff/CiffEntry.h"
+#include "common/Common.h" // for uchar8, uint32, ushort16
+#include "io/ByteStream.h" // for ByteStream
+#include "parsers/CiffParserException.h" // for CiffParserException (ptr only)
+#include <string> // for string, allocator
+#include <vector> // for vector
+
+using std::string;
+using std::vector;
+
+namespace rawspeed {
+
+CiffEntry::CiffEntry(ByteStream* bs) {
+ ushort16 p = bs->getU16();
+
+ tag = static_cast<CiffTag>(p & 0x3fff);
+ ushort16 datalocation = (p & 0xc000);
+ type = static_cast<CiffDataType>(p & 0x3800);
+
+ uint32 data_offset;
+ uint32 bytesize;
+
+ switch (datalocation) {
+ case 0x0000:
+ // Data is offset in value_data
+ bytesize = bs->getU32();
+ data_offset = bs->getU32();
+ break;
+ case 0x4000:
+ // Data is stored directly in entry
+ data_offset = bs->getPosition();
+ // Maximum of 8 bytes of data (the size and offset fields)
+ bytesize = 8;
+ bs->skipBytes(bytesize);
+ break;
+ default:
+ ThrowCPE("Don't understand data location 0x%x", datalocation);
+ }
+
+ data = bs->getSubStream(data_offset, bytesize);
+
+ // Set the number of items using the shift
+ count = bytesize >> getElementShift();
+}
+
+uint32 __attribute__((pure)) CiffEntry::getElementShift() const {
+ switch (type) {
+ case CIFF_SHORT:
+ return 1;
+ case CIFF_LONG:
+ case CIFF_MIX:
+ case CIFF_SUB1:
+ case CIFF_SUB2:
+ return 2;
+ default:
+ // e.g. CIFF_BYTE or CIFF_ASCII
+ return 0;
+ }
+}
+
+uint32 __attribute__((pure)) CiffEntry::getElementSize() const {
+ switch (type) {
+ case CIFF_BYTE:
+ case CIFF_ASCII:
+ return 1;
+ case CIFF_SHORT:
+ return 2;
+ case CIFF_LONG:
+ case CIFF_MIX:
+ case CIFF_SUB1:
+ case CIFF_SUB2:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+bool __attribute__((pure)) CiffEntry::isInt() const {
+ return (type == CIFF_LONG || type == CIFF_SHORT || type == CIFF_BYTE);
+}
+
+uint32 CiffEntry::getU32(uint32 num) const {
+ if (!isInt()) {
+ ThrowCPE(
+ "Wrong type 0x%x encountered. Expected Long, Short or Byte at 0x%x",
+ type, tag);
+ }
+
+ if (type == CIFF_BYTE)
+ return getByte(num);
+ if (type == CIFF_SHORT)
+ return getU16(num);
+
+ return data.peek<uint32>(num);
+}
+
+ushort16 CiffEntry::getU16(uint32 num) const {
+ if (type != CIFF_SHORT && type != CIFF_BYTE)
+ ThrowCPE("Wrong type 0x%x encountered. Expected Short at 0x%x", type, tag);
+
+ return data.peek<ushort16>(num);
+}
+
+uchar8 CiffEntry::getByte(uint32 num) const {
+ if (type != CIFF_BYTE)
+ ThrowCPE("Wrong type 0x%x encountered. Expected Byte at 0x%x", type, tag);
+
+ return data.peek<uchar8>(num);
+}
+
+string CiffEntry::getString() const {
+ if (type != CIFF_ASCII)
+ ThrowCPE("Wrong type 0x%x encountered. Expected Ascii", type);
+
+ if (count == 0)
+ return string("");
+
+ return data.peekString();
+}
+
+vector<string> CiffEntry::getStrings() const {
+ if (type != CIFF_ASCII)
+ ThrowCPE("Wrong type 0x%x encountered. Expected Ascii", type);
+
+ const string str(reinterpret_cast<const char*>(data.peekData(count)), count);
+
+ vector<string> strs;
+
+ uint32 start = 0;
+ for (uint32 i = 0; i < count; i++) {
+ if (str[i] != 0)
+ continue;
+
+ strs.emplace_back(reinterpret_cast<const char*>(&str[start]));
+ start = i + 1;
+ }
+
+ return strs;
+}
+
+bool __attribute__((pure)) CiffEntry::isString() const {
+ return (type == CIFF_ASCII);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/tiff/CiffEntry.h b/src/external/rawspeed/src/librawspeed/tiff/CiffEntry.h
new file mode 100644
index 000000000..950e60a67
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/tiff/CiffEntry.h
@@ -0,0 +1,77 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, uchar8, ushort16
+#include "io/ByteStream.h" // for ByteStream
+#include "tiff/CiffTag.h" // for CiffTag
+#include <string> // for string
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class CiffIFD;
+
+/*
+ * Tag data type information.
+ */
+enum CiffDataType {
+ CIFF_BYTE = 0x0000, /* 8-bit unsigned integer */
+ CIFF_ASCII = 0x0800, /* 8-bit bytes w/ last byte null */
+ CIFF_SHORT = 0x1000, /* 16-bit unsigned integer */
+ CIFF_LONG = 0x1800, /* 32-bit unsigned integer */
+ CIFF_MIX = 0x2000, /* 32-bit unsigned integer */
+ CIFF_SUB1 = 0x2800, /* 32-bit unsigned integer */
+ CIFF_SUB2 = 0x3000, /* 32-bit unsigned integer */
+
+};
+
+class CiffEntry
+{
+ friend class CiffIFD;
+
+ CiffIFD* parent = nullptr;
+ ByteStream data;
+
+public:
+ explicit CiffEntry(ByteStream* bs);
+
+ uchar8 getByte(uint32 num = 0) const;
+ uint32 getU32(uint32 num = 0) const;
+ ushort16 getU16(uint32 num = 0) const;
+
+ std::string getString() const;
+ std::vector<std::string> getStrings() const;
+
+ uint32 __attribute__((pure)) getElementSize() const;
+ uint32 __attribute__((pure)) getElementShift() const;
+
+ // variables:
+ CiffTag tag;
+ CiffDataType type;
+ uint32 count;
+
+ bool __attribute__((pure)) isInt() const;
+ bool __attribute__((pure)) isString() const;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/tiff/CiffIFD.cpp b/src/external/rawspeed/src/librawspeed/tiff/CiffIFD.cpp
new file mode 100644
index 000000000..0cc22ccae
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/tiff/CiffIFD.cpp
@@ -0,0 +1,230 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "tiff/CiffIFD.h"
+#include "common/Common.h" // for uint32, ushort16
+#include "common/NORangesSet.h" // for NORangesSet
+#include "common/RawspeedException.h" // for RawspeedException
+#include "io/ByteStream.h" // for ByteStream
+#include "io/IOException.h" // for IOException
+#include "parsers/CiffParserException.h" // for ThrowCPE, CiffParserException
+#include "tiff/CiffEntry.h" // for CiffEntry, CiffDataType::CI...
+#include <cassert> // for assert
+#include <map> // for map, _Rb_tree_iterator
+#include <memory> // for unique_ptr
+#include <string> // for allocator, operator==, string
+#include <utility> // for pair
+#include <vector> // for vector
+
+using std::string;
+using std::vector;
+using std::unique_ptr;
+
+namespace rawspeed {
+
+void CiffIFD::parseIFDEntry(NORangesSet<Buffer>* ifds, ByteStream* bs) {
+ assert(ifds);
+ assert(bs);
+
+ unique_ptr<CiffEntry> t;
+
+ auto origPos = bs->getPosition();
+
+ try {
+ t = std::make_unique<CiffEntry>(bs);
+ } catch (IOException&) {
+ // Ignore unparsable entry, but fix probably broken position due to
+ // interruption by exception; i.e. setting it to the next entry.
+ bs->setPosition(origPos + 10);
+ return;
+ }
+
+ try {
+ switch (t->type) {
+ case CIFF_SUB1:
+ case CIFF_SUB2: {
+ add(std::make_unique<CiffIFD>(this, ifds, &t->data));
+ break;
+ }
+
+ default:
+ add(move(t));
+ }
+ } catch (RawspeedException&) {
+ // Unparsable private data are added as entries
+ add(move(t));
+ }
+}
+
+CiffIFD::CiffIFD(const CiffIFD* parent_, NORangesSet<Buffer>* ifds,
+ ByteStream* mFile)
+ : parent(parent_) {
+ assert(ifds);
+ assert(mFile);
+
+ checkOverflow();
+
+ if (mFile->getSize() < 4)
+ ThrowCPE("File is probably corrupted.");
+
+ // last 4 bytes is the offset to the beginning of the [first?] IFD
+ mFile->setPosition(mFile->getSize() - 4);
+ uint32 offset = mFile->getU32();
+ mFile->setPosition(offset);
+
+ // count of the Directory entries in this IFD
+ ushort16 dircount = mFile->getU16();
+
+ // 2 bytes for entry count
+ // each entry is 10 bytes
+ const auto IFDFullSize = 2 + 10 * dircount;
+ const Buffer IFDBuf(mFile->getSubView(offset, IFDFullSize));
+ if (!ifds->emplace(IFDBuf).second)
+ ThrowCPE("Two IFD's overlap. Raw corrupt!");
+
+ for (uint32 i = 0; i < dircount; i++)
+ parseIFDEntry(ifds, mFile);
+}
+
+void CiffIFD::checkOverflow() const {
+ const CiffIFD* p = this;
+ int i = 0;
+ while ((p = p->parent) != nullptr) {
+ i++;
+ if (i > 5)
+ ThrowCPE("CiffIFD cascading overflow.");
+ }
+}
+
+void CiffIFD::add(std::unique_ptr<CiffIFD> subIFD) {
+ if (mSubIFD.size() > 100)
+ ThrowCPE("CIFF file has too many SubIFDs, probably broken");
+
+ subIFD->parent = this;
+ mSubIFD.push_back(move(subIFD));
+}
+
+void CiffIFD::add(std::unique_ptr<CiffEntry> entry) {
+ entry->parent = this;
+ mEntry[entry->tag] = move(entry);
+}
+
+template <typename Lambda>
+std::vector<const CiffIFD*> CiffIFD::getIFDsWithTagIf(CiffTag tag,
+ const Lambda& f) const {
+ std::vector<const CiffIFD*> matchingIFDs;
+
+ const auto found = mEntry.find(tag);
+ if (found != mEntry.end()) {
+ const auto entry = found->second.get();
+ if (f(entry))
+ matchingIFDs.push_back(this);
+ }
+
+ for (const auto& i : mSubIFD) {
+ const auto t = i->getIFDsWithTagIf(tag, f);
+ matchingIFDs.insert(matchingIFDs.end(), t.begin(), t.end());
+ }
+
+ return matchingIFDs;
+}
+
+template <typename Lambda>
+const CiffEntry* CiffIFD::getEntryRecursiveIf(CiffTag tag,
+ const Lambda& f) const {
+ const auto found = mEntry.find(tag);
+ if (found != mEntry.end()) {
+ const auto entry = found->second.get();
+ if (f(entry))
+ return entry;
+ }
+
+ for (const auto& i : mSubIFD) {
+ const CiffEntry* entry = i->getEntryRecursiveIf(tag, f);
+ if (entry)
+ return entry;
+ }
+
+ return nullptr;
+}
+
+vector<const CiffIFD*> CiffIFD::getIFDsWithTag(CiffTag tag) const {
+ return getIFDsWithTagIf(tag, [](const CiffEntry*) { return true; });
+}
+
+vector<const CiffIFD*> CiffIFD::getIFDsWithTagWhere(CiffTag tag,
+ uint32 isValue) const {
+ return getIFDsWithTagIf(tag, [&isValue](const CiffEntry* entry) {
+ return entry->isInt() && entry->getU32() == isValue;
+ });
+}
+
+vector<const CiffIFD*>
+CiffIFD::getIFDsWithTagWhere(CiffTag tag, const string& isValue) const {
+ return getIFDsWithTagIf(tag, [&isValue](const CiffEntry* entry) {
+ return entry->isString() && isValue == entry->getString();
+ });
+}
+
+bool __attribute__((pure)) CiffIFD::hasEntry(CiffTag tag) const {
+ return mEntry.count(tag) > 0;
+}
+
+bool __attribute__((pure)) CiffIFD::hasEntryRecursive(CiffTag tag) const {
+ if (mEntry.count(tag) > 0)
+ return true;
+
+ for (const auto& i : mSubIFD) {
+ if (i->hasEntryRecursive(tag))
+ return true;
+ }
+
+ return false;
+}
+
+const CiffEntry* CiffIFD::getEntry(CiffTag tag) const {
+ const auto found = mEntry.find(tag);
+ if (found != mEntry.end())
+ return found->second.get();
+
+ ThrowCPE("Entry 0x%x not found.", tag);
+}
+
+const CiffEntry* CiffIFD::getEntryRecursive(CiffTag tag) const {
+ return getEntryRecursiveIf(tag, [](const CiffEntry*) { return true; });
+}
+
+const CiffEntry* CiffIFD::getEntryRecursiveWhere(CiffTag tag,
+ uint32 isValue) const {
+ return getEntryRecursiveIf(tag, [&isValue](const CiffEntry* entry) {
+ return entry->isInt() && entry->getU32() == isValue;
+ });
+}
+
+const CiffEntry* CiffIFD::getEntryRecursiveWhere(CiffTag tag,
+ const string& isValue) const {
+ return getEntryRecursiveIf(tag, [&isValue](const CiffEntry* entry) {
+ return entry->isString() && isValue == entry->getString();
+ });
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/tiff/CiffIFD.h b/src/external/rawspeed/src/librawspeed/tiff/CiffIFD.h
new file mode 100644
index 000000000..7bfd6ee81
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/tiff/CiffIFD.h
@@ -0,0 +1,79 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32
+#include "common/NORangesSet.h" // for NORangesSet
+#include "tiff/CiffEntry.h" // IWYU pragma: keep
+#include "tiff/CiffTag.h" // for CiffTag
+#include <map> // for map
+#include <memory> // for unique_ptr
+#include <string> // for string
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class ByteStream;
+
+class CiffIFD final {
+ const CiffIFD* parent;
+
+ std::vector<std::unique_ptr<const CiffIFD>> mSubIFD;
+ std::map<CiffTag, std::unique_ptr<const CiffEntry>> mEntry;
+
+ void checkOverflow() const;
+
+ void add(std::unique_ptr<CiffIFD> subIFD);
+ void add(std::unique_ptr<CiffEntry> entry);
+
+ void parseIFDEntry(NORangesSet<Buffer>* ifds, ByteStream* bs);
+
+ template <typename Lambda>
+ std::vector<const CiffIFD*> __attribute__((pure))
+ getIFDsWithTagIf(CiffTag tag, const Lambda& f) const;
+
+ template <typename Lambda>
+ const CiffEntry* __attribute__((pure))
+ getEntryRecursiveIf(CiffTag tag, const Lambda& f) const;
+
+public:
+ CiffIFD(const CiffIFD* parent, NORangesSet<Buffer>* ifds, ByteStream* mFile);
+
+ std::vector<const CiffIFD*> __attribute__((pure))
+ getIFDsWithTag(CiffTag tag) const;
+ std::vector<const CiffIFD*> __attribute__((pure))
+ getIFDsWithTagWhere(CiffTag tag, uint32 isValue) const;
+ std::vector<const CiffIFD*> __attribute__((pure))
+ getIFDsWithTagWhere(CiffTag tag, const std::string& isValue) const;
+
+ bool __attribute__((pure)) hasEntry(CiffTag tag) const;
+ bool __attribute__((pure)) hasEntryRecursive(CiffTag tag) const;
+
+ const CiffEntry* __attribute__((pure)) getEntry(CiffTag tag) const;
+ const CiffEntry* __attribute__((pure)) getEntryRecursive(CiffTag tag) const;
+ const CiffEntry* __attribute__((pure))
+ getEntryRecursiveWhere(CiffTag tag, uint32 isValue) const;
+ const CiffEntry* __attribute__((pure))
+ getEntryRecursiveWhere(CiffTag tag, const std::string& isValue) const;
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/tiff/CiffTag.h b/src/external/rawspeed/src/librawspeed/tiff/CiffTag.h
new file mode 100644
index 000000000..5e4d12146
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/tiff/CiffTag.h
@@ -0,0 +1,39 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2014 Pedro Côrte-Real
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+namespace rawspeed {
+
+enum CiffTag {
+ CIFF_NULL = 0x0000,
+ CIFF_MAKEMODEL = 0x080a,
+ CIFF_SHOTINFO = 0x102a,
+ CIFF_WHITEBALANCE = 0x10a9,
+ CIFF_SENSORINFO = 0x1031,
+ CIFF_IMAGEINFO = 0x1810,
+ CIFF_DECODERTABLE = 0x1835,
+ CIFF_RAWDATA = 0x2005,
+ CIFF_SUBIFD = 0x300a,
+ CIFF_EXIF = 0x300b,
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/tiff/TiffEntry.cpp b/src/external/rawspeed/src/librawspeed/tiff/TiffEntry.cpp
new file mode 100644
index 000000000..44fdba316
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/tiff/TiffEntry.cpp
@@ -0,0 +1,237 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2015 Pedro Côrte-Real
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "tiff/TiffEntry.h"
+#include "common/Common.h" // for uint32, ushort16, int32
+#include "parsers/TiffParserException.h" // for ThrowTPE
+#include "tiff/TiffIFD.h" // for TiffIFD, TiffRootIFD
+#include "tiff/TiffTag.h" // for ::DNGPRIVATEDATA, ::EXIFIFD...
+#include <algorithm> // for move
+#include <cassert> // for assert
+#include <cstdint> // for UINT32_MAX
+#include <cstring> // for strnlen
+#include <string> // for string
+
+using std::string;
+
+namespace rawspeed {
+
+class DataBuffer;
+
+// order see TiffDataType
+const uint32 TiffEntry::datashifts[] = {0, 0, 0, 1, 2, 3, 0,
+ 0, 1, 2, 3, 2, 3, 2};
+// 0-1-2-3-4-5-6-7-8-9-10-11-12-13
+
+TiffEntry::TiffEntry(TiffIFD* parent_, ByteStream* bs) : parent(parent_) {
+ tag = static_cast<TiffTag>(bs->getU16());
+ const ushort16 numType = bs->getU16();
+ if (numType > TIFF_OFFSET)
+ ThrowTPE("Error reading TIFF structure. Unknown Type 0x%x encountered.", numType);
+ type = static_cast<TiffDataType>(numType);
+ count = bs->getU32();
+
+ // check for count << datashift overflow
+ if (count > UINT32_MAX >> datashifts[type])
+ ThrowTPE("integer overflow in size calculation.");
+
+ uint32 byte_size = count << datashifts[type];
+ uint32 data_offset = UINT32_MAX;
+
+ if (byte_size <= 4) {
+ data_offset = bs->getPosition();
+ data = bs->getSubStream(bs->getPosition(), byte_size);
+ bs->skipBytes(4);
+ } else {
+ data_offset = bs->getU32();
+ if (type == TIFF_OFFSET || isIn(tag, {DNGPRIVATEDATA, MAKERNOTE, MAKERNOTE_ALT, FUJI_RAW_IFD, SUBIFDS, EXIFIFDPOINTER})) {
+ // preserve offset for SUB_IFD/EXIF/MAKER_NOTE data
+#if 0
+ // limit access to range from 0 to data_offset+byte_size
+ data = ByteStream(bs, data_offset, byte_size, bs.getByteOrder());
+#else
+ // allow access to whole file, necesary if offsets inside the maker note
+ // point to outside data, which is forbidden due to the TIFF/DNG spec but
+ // may happen none the less (see e.g. "old" ORF files like EX-1, note:
+ // the tags outside of the maker note area are currently not used anyway)
+ data = *bs;
+ data.setPosition(data_offset);
+ data.check(byte_size);
+#endif
+ } else {
+ data = bs->getSubStream(data_offset, byte_size);
+ }
+ }
+}
+
+TiffEntry::TiffEntry(TiffIFD* parent_, TiffTag tag_, TiffDataType type_,
+ uint32 count_, ByteStream&& data_)
+ : parent(parent_), data(std::move(data_)), tag(tag_), type(type_),
+ count(count_) {
+ // check for count << datashift overflow
+ if (count > UINT32_MAX >> datashifts[type])
+ ThrowTPE("integer overflow in size calculation.");
+
+ uint32 bytesize = count << datashifts[type];
+
+ if (data.getSize() != bytesize)
+ ThrowTPE("data set larger than entry size given");
+}
+
+bool __attribute__((pure)) TiffEntry::isInt() const {
+ return type == TIFF_LONG || type == TIFF_SHORT || type == TIFF_BYTE;
+}
+
+bool __attribute__((pure)) TiffEntry::isString() const {
+ return type == TIFF_ASCII;
+}
+
+bool __attribute__((pure)) TiffEntry::isFloat() const {
+ switch (type) {
+ case TIFF_FLOAT:
+ case TIFF_DOUBLE:
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ case TIFF_LONG:
+ case TIFF_SLONG:
+ case TIFF_SHORT:
+ case TIFF_SSHORT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+uchar8 TiffEntry::getByte(uint32 index) const {
+ if (type != TIFF_BYTE && type != TIFF_UNDEFINED)
+ ThrowTPE("Wrong type %u encountered. Expected Byte on 0x%x", type, tag);
+
+ return data.peekByte(index);
+}
+
+ushort16 TiffEntry::getU16(uint32 index) const {
+ if (type != TIFF_SHORT && type != TIFF_UNDEFINED)
+ ThrowTPE("Wrong type %u encountered. Expected Short or Undefined on 0x%x",
+ type, tag);
+
+ return data.peek<ushort16>(index);
+}
+
+short16 TiffEntry::getI16(uint32 index) const {
+ if (type != TIFF_SSHORT && type != TIFF_UNDEFINED)
+ ThrowTPE("Wrong type %u encountered. Expected Short or Undefined on 0x%x",
+ type, tag);
+
+ return data.peek<short16>(index);
+}
+
+uint32 TiffEntry::getU32(uint32 index) const {
+ if (type == TIFF_SHORT)
+ return getU16(index);
+
+ switch (type) {
+ case TIFF_LONG:
+ case TIFF_OFFSET:
+ case TIFF_BYTE:
+ case TIFF_UNDEFINED:
+ case TIFF_RATIONAL:
+ case TIFF_SRATIONAL:
+ break;
+ default:
+ ThrowTPE("Wrong type %u encountered. Expected Long, Offset, Rational or "
+ "Undefined on 0x%x",
+ type, tag);
+ }
+
+ return data.peek<uint32>(index);
+}
+
+int32 TiffEntry::getI32(uint32 index) const {
+ if (type == TIFF_SSHORT)
+ return getI16(index);
+ if (!(type == TIFF_SLONG || type == TIFF_UNDEFINED))
+ ThrowTPE("Wrong type %u encountered. Expected SLong or Undefined on 0x%x",
+ type, tag);
+
+ return data.peek<int32>(index);
+}
+
+float TiffEntry::getFloat(uint32 index) const {
+ if (!isFloat()) {
+ ThrowTPE("Wrong type 0x%x encountered. Expected Float or something "
+ "convertible on 0x%x",
+ type, tag);
+ }
+
+ switch (type) {
+ case TIFF_DOUBLE: return data.peek<double>(index);
+ case TIFF_FLOAT: return data.peek<float>(index);
+ case TIFF_LONG:
+ case TIFF_SHORT:
+ return static_cast<float>(getU32(index));
+ case TIFF_SLONG:
+ case TIFF_SSHORT:
+ return static_cast<float>(getI32(index));
+ case TIFF_RATIONAL: {
+ uint32 a = getU32(index*2);
+ uint32 b = getU32(index*2+1);
+ return b != 0 ? static_cast<float>(a) / b : 0.0F;
+ }
+ case TIFF_SRATIONAL: {
+ auto a = static_cast<int>(getU32(index * 2));
+ auto b = static_cast<int>(getU32(index * 2 + 1));
+ return b ? static_cast<float>(a) / b : 0.0F;
+ }
+ default:
+ // unreachable
+ return 0.0F;
+ }
+}
+
+string TiffEntry::getString() const {
+ if (type != TIFF_ASCII && type != TIFF_BYTE)
+ ThrowTPE("Wrong type 0x%x encountered. Expected Ascii or Byte", type);
+
+ // *NOT* ByteStream::peekString() !
+ const auto bufSize = data.getRemainSize();
+ const auto* buf = data.peekData(bufSize);
+ const auto* s = reinterpret_cast<const char*>(buf);
+ return string(s, strnlen(s, bufSize));
+}
+
+const DataBuffer &TiffEntry::getRootIfdData() const {
+ TiffIFD* p = parent;
+ TiffRootIFD* r = nullptr;
+ while (p) {
+ r = dynamic_cast<TiffRootIFD*>(p);
+ if (r)
+ break;
+ p = p->parent;
+ }
+ if (!r)
+ ThrowTPE("Internal error in TiffIFD data structure.");
+
+ assert(r != nullptr);
+ return r->rootBuffer;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/tiff/TiffEntry.h b/src/external/rawspeed/src/librawspeed/tiff/TiffEntry.h
new file mode 100644
index 000000000..93edcc3e3
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/tiff/TiffEntry.h
@@ -0,0 +1,118 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2015 Pedro Côrte-Real
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, uchar8, ushort16, int32, short16
+#include "io/ByteStream.h" // for ByteStream
+#include "tiff/TiffTag.h" // for TiffTag
+#include <string> // for string
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class DataBuffer;
+
+class TiffIFD;
+
+/*
+ * Tag data type information.
+ *
+ * Note: RATIONALs are the ratio of two 32-bit integer values.
+ */
+enum TiffDataType {
+ TIFF_NOTYPE = 0, /* placeholder */
+ TIFF_BYTE = 1, /* 8-bit unsigned integer */
+ TIFF_ASCII = 2, /* 8-bit bytes w/ last byte null */
+ TIFF_SHORT = 3, /* 16-bit unsigned integer */
+ TIFF_LONG = 4, /* 32-bit unsigned integer */
+ TIFF_RATIONAL = 5, /* 64-bit unsigned fraction */
+ TIFF_SBYTE = 6, /* !8-bit signed integer */
+ TIFF_UNDEFINED = 7, /* !8-bit untyped data */
+ TIFF_SSHORT = 8, /* !16-bit signed integer */
+ TIFF_SLONG = 9, /* !32-bit signed integer */
+ TIFF_SRATIONAL = 10, /* !64-bit signed fraction */
+ TIFF_FLOAT = 11, /* !32-bit IEEE floating point */
+ TIFF_DOUBLE = 12, /* !64-bit IEEE floating point */
+ TIFF_OFFSET = 13, /* 32-bit unsigned offset used for IFD and other offsets */
+};
+
+class TiffEntry
+{
+ TiffIFD* parent;
+ ByteStream data;
+
+ friend class TiffIFD;
+
+ template <typename T, T (TiffEntry::*getter)(uint32 index) const>
+ std::vector<T> getArray(uint32 count_) const {
+ std::vector<T> res(count_);
+ for (uint32 i = 0; i < count_; ++i)
+ res[i] = (this->*getter)(i);
+ return res;
+ }
+
+public:
+ TiffTag tag;
+ TiffDataType type;
+ uint32 count;
+
+ TiffEntry(TiffIFD* parent, TiffTag tag, TiffDataType type, uint32 count,
+ ByteStream&& data);
+ TiffEntry(TiffIFD* parent, ByteStream* bs);
+
+ bool __attribute__((pure)) isFloat() const;
+ bool __attribute__((pure)) isInt() const;
+ bool __attribute__((pure)) isString() const;
+ uchar8 getByte(uint32 index = 0) const;
+ uint32 getU32(uint32 index = 0) const;
+ int32 getI32(uint32 index = 0) const;
+ ushort16 getU16(uint32 index = 0) const;
+ short16 getI16(uint32 index = 0) const;
+ float getFloat(uint32 index = 0) const;
+ std::string getString() const;
+
+ inline std::vector<ushort16> getU16Array(uint32 count_) const
+ {
+ return getArray<ushort16, &TiffEntry::getU16>(count_);
+ }
+
+ inline std::vector<uint32> getU32Array(uint32 count_) const
+ {
+ return getArray<uint32, &TiffEntry::getU32>(count_);
+ }
+
+ inline std::vector<float> getFloatArray(uint32 count_) const
+ {
+ return getArray<float, &TiffEntry::getFloat>(count_);
+ }
+
+ ByteStream& getData() { return data; }
+ const uchar8* getData(uint32 size) { return data.getData(size); }
+
+ const DataBuffer& getRootIfdData() const;
+
+protected:
+ static const uint32 datashifts[];
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/tiff/TiffIFD.cpp b/src/external/rawspeed/src/librawspeed/tiff/TiffIFD.cpp
new file mode 100644
index 000000000..cc30339d1
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/tiff/TiffIFD.cpp
@@ -0,0 +1,310 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2015 Pedro Côrte-Real
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "tiff/TiffIFD.h"
+#include "common/Common.h" // for getHostEndianness, uint32, make_...
+#include "common/NORangesSet.h" // for NORangesSet
+#include "common/RawspeedException.h" // for RawspeedException
+#include "io/IOException.h" // for IOException
+#include "tiff/TiffEntry.h" // for TiffEntry
+#include "tiff/TiffTag.h" // for TiffTag, ::DNGPRIVATEDATA, ::EXI...
+#include <algorithm> // for move
+#include <cstdint> // for UINT32_MAX
+#include <map> // for map, _Rb_tree_const_iterator, al...
+#include <memory> // for default_delete, unique_ptr
+#include <string> // for operator==, string, basic_string
+#include <utility> // for pair
+#include <vector> // for vector
+
+using std::string;
+using std::vector;
+
+namespace rawspeed {
+
+void TiffIFD::parseIFDEntry(NORangesSet<Buffer>* ifds, ByteStream* bs) {
+ assert(ifds);
+
+ TiffEntryOwner t;
+
+ auto origPos = bs->getPosition();
+
+ try {
+ t = std::make_unique<TiffEntry>(this, bs);
+ } catch (IOException&) { // Ignore unparsable entry
+ // fix probably broken position due to interruption by exception
+ // i.e. setting it to the next entry.
+ bs->setPosition(origPos + 12);
+ return;
+ }
+
+ try {
+ switch (t->tag) {
+ case DNGPRIVATEDATA:
+ add(parseDngPrivateData(ifds, t.get()));
+ break;
+
+ case MAKERNOTE:
+ case MAKERNOTE_ALT:
+ add(parseMakerNote(ifds, t.get()));
+ break;
+
+ case FUJI_RAW_IFD:
+ case SUBIFDS:
+ case EXIFIFDPOINTER:
+ for (uint32 j = 0; j < t->count; j++)
+ add(std::make_unique<TiffIFD>(this, ifds, *bs, t->getU32(j)));
+ break;
+
+ default:
+ add(move(t));
+ }
+ } catch (RawspeedException&) { // Unparsable private data are added as entries
+ add(move(t));
+ }
+}
+
+TiffIFD::TiffIFD(TiffIFD* parent_) : parent(parent_) {}
+
+TiffIFD::TiffIFD(TiffIFD* parent_, NORangesSet<Buffer>* ifds,
+ const DataBuffer& data, uint32 offset)
+ : TiffIFD(parent_) {
+ // see TiffParser::parse: UINT32_MAX is used to mark the "virtual" top level
+ // TiffRootIFD in a tiff file
+ if (offset == UINT32_MAX)
+ return;
+
+ assert(ifds);
+
+ checkOverflow();
+
+ ByteStream bs(data);
+ bs.setPosition(offset);
+
+ // Directory entries in this IFD
+ auto numEntries = bs.getU16();
+
+ // 2 bytes for entry count
+ // each entry is 12 bytes
+ // 4-byte offset to the next IFD at the end
+ const auto IFDFullSize = 2 + 4 + 12 * numEntries;
+ const Buffer IFDBuf(data.getSubView(offset, IFDFullSize));
+ if (!ifds->emplace(IFDBuf).second)
+ ThrowTPE("Two IFD's overlap. Raw corrupt!");
+
+ for (uint32 i = 0; i < numEntries; i++)
+ parseIFDEntry(ifds, &bs);
+
+ nextIFD = bs.getU32();
+}
+
+TiffRootIFDOwner TiffIFD::parseDngPrivateData(NORangesSet<Buffer>* ifds,
+ TiffEntry* t) {
+ assert(ifds);
+
+ /*
+ 1. Six bytes containing the zero-terminated string "Adobe". (The DNG specification calls for the DNGPrivateData tag to start with an ASCII string identifying the creator/format).
+ 2. 4 bytes: an ASCII string ("MakN" for a Makernote), indicating what sort of data is being stored here. Note that this is not zero-terminated.
+ 3. A four-byte count (number of data bytes following); this is the length of the original MakerNote data. (This is always in "most significant byte first" format).
+ 4. 2 bytes: the byte-order indicator from the original file (the usual 'MM'/4D4D or 'II'/4949).
+ 5. 4 bytes: the original file offset for the MakerNote tag data (stored according to the byte order given above).
+ 6. The contents of the MakerNote tag. This is a simple byte-for-byte copy, with no modification.
+ */
+ ByteStream& bs = t->getData();
+ if (!bs.skipPrefix("Adobe", 6))
+ ThrowTPE("Not Adobe Private data");
+
+ if (!bs.skipPrefix("MakN", 4))
+ ThrowTPE("Not Makernote");
+
+ bs.setByteOrder(Endianness::big);
+ uint32 makerNoteSize = bs.getU32();
+ if (makerNoteSize != bs.getRemainSize())
+ ThrowTPE("Error reading TIFF structure (invalid size). File Corrupt");
+
+ bs.setByteOrder(getTiffByteOrder(bs, 0, "DNG makernote"));
+ bs.skipBytes(2);
+
+ uint32 makerNoteOffset = bs.getU32();
+ makerNoteSize -= 6; // update size of orinial maker note, we skipped 2+4 bytes
+
+ // Update the underlying buffer of t, such that the maker note data starts at its original offset
+ bs.rebase(makerNoteOffset, makerNoteSize);
+
+ return parseMakerNote(ifds, t);
+}
+
+/* This will attempt to parse makernotes and return it as an IFD */
+TiffRootIFDOwner TiffIFD::parseMakerNote(NORangesSet<Buffer>* ifds,
+ TiffEntry* t) {
+ assert(ifds);
+
+ // go up the IFD tree and try to find the MAKE entry on each level.
+ // we can not go all the way to the top first because this partial tree
+ // is not yet added to the TiffRootIFD.
+ TiffIFD* p = this;
+ TiffEntry* makeEntry;
+ do {
+ makeEntry = p->getEntryRecursive(MAKE);
+ p = p->parent;
+ } while (!makeEntry && p);
+ string make = makeEntry != nullptr ? trimSpaces(makeEntry->getString()) : "";
+
+ ByteStream bs = t->getData();
+
+ // helper function for easy setup of ByteStream buffer for the different maker note types
+ // 'rebase' means position 0 of new stream equals current position
+ // 'newPosition' is the position where the IFD starts
+ // 'byteOrderOffset' is the position wher the 2 magic bytes (II/MM) may be found
+ // 'context' is a string providing error information in case the byte order parsing should fail
+ auto setup = [&bs](bool rebase, uint32 newPosition,
+ uint32 byteOrderOffset = 0,
+ const char *context = nullptr) {
+ if (rebase)
+ bs = bs.getSubStream(bs.getPosition(), bs.getRemainSize());
+ if (context)
+ bs.setByteOrder(getTiffByteOrder(bs, byteOrderOffset, context));
+ bs.skipBytes(newPosition);
+ };
+
+ if (bs.hasPrefix("AOC\0", 4)) {
+ setup(false, 6, 4, "Pentax makernote");
+ } else if (bs.hasPrefix("PENTAX", 6)) {
+ setup(true, 10, 8, "Pentax makernote");
+ } else if (bs.hasPrefix("FUJIFILM\x0c\x00\x00\x00", 12)) {
+ bs.setByteOrder(Endianness::little);
+ setup(true, 12);
+ } else if (bs.hasPrefix("Nikon\x00\x02", 7)) {
+ // this is Nikon type 3 maker note format
+ // TODO: implement Nikon type 1 maker note format
+ // see http://www.ozhiker.com/electronics/pjmt/jpeg_info/nikon_mn.html
+ bs.skipBytes(10);
+ setup(true, 8, 0, "Nikon makernote");
+ } else if (bs.hasPrefix("OLYMPUS", 7)) { // new Olympus
+ setup(true, 12);
+ } else if (bs.hasPrefix("OLYMP", 5)) { // old Olympus
+ setup(true, 8);
+ } else if (bs.hasPrefix("EPSON", 5)) {
+ setup(false, 8);
+ } else if (bs.hasPatternAt("Exif", 4, 6)) {
+ // TODO: for none of the rawsamples.ch files from Panasonic is this true, instead their MakerNote start with "Panasonic"
+ // Panasonic has the word Exif at byte 6, a complete Tiff header starts at byte 12
+ // This TIFF is 0 offset based
+ setup(false, 20, 12, "Panosonic makernote");
+ } else if (make == "SAMSUNG") {
+ // Samsung has no identification in its MakerNote but starts with the IFD right away
+ setup(true, 0);
+ } else {
+ // cerr << "default MakerNote from " << make << endl; // Canon, Nikon (type 2), Sony, Minolta, Ricoh, Leica, Hasselblad, etc.
+
+ // At least one MAKE has not been handled explicitly and starts its MakerNote with an endian prefix: Kodak
+ if (bs.skipPrefix("II", 2)) {
+ bs.setByteOrder(Endianness::little);
+ } else if (bs.skipPrefix("MM", 2)) {
+ bs.setByteOrder(Endianness::big);
+ }
+ }
+
+ // Attempt to parse the rest as an IFD
+ return std::make_unique<TiffRootIFD>(this, ifds, bs, bs.getPosition());
+}
+
+std::vector<const TiffIFD*> TiffIFD::getIFDsWithTag(TiffTag tag) const {
+ vector<const TiffIFD*> matchingIFDs;
+ if (entries.find(tag) != entries.end()) {
+ matchingIFDs.push_back(this);
+ }
+ for (auto& i : subIFDs) {
+ vector<const TiffIFD*> t = i->getIFDsWithTag(tag);
+ matchingIFDs.insert(matchingIFDs.end(), t.begin(), t.end());
+ }
+ return matchingIFDs;
+}
+
+const TiffIFD* TiffIFD::getIFDWithTag(TiffTag tag, uint32 index) const
+{
+ auto ifds = getIFDsWithTag(tag);
+ if (index >= ifds.size())
+ ThrowTPE("failed to find %u ifs with tag 0x%04x", index + 1, tag);
+ return ifds[index];
+}
+
+TiffEntry* __attribute__((pure)) TiffIFD::getEntryRecursive(TiffTag tag) const {
+ auto i = entries.find(tag);
+ if (i != entries.end()) {
+ return i->second.get();
+ }
+ for (auto &j : subIFDs) {
+ TiffEntry *entry = j->getEntryRecursive(tag);
+ if (entry)
+ return entry;
+ }
+ return nullptr;
+}
+
+void TiffIFD::checkOverflow() {
+ TiffIFD* p = this;
+ int i = 0;
+ while ((p = p->parent) != nullptr) {
+ i++;
+ if (i > 5)
+ ThrowTPE("TiffIFD cascading overflow.");
+ }
+}
+
+void TiffIFD::add(TiffIFDOwner subIFD) {
+ checkOverflow();
+ if (subIFDs.size() > 100)
+ ThrowTPE("TIFF file has too many SubIFDs, probably broken");
+ subIFD->parent = this;
+ subIFDs.push_back(move(subIFD));
+}
+
+void TiffIFD::add(TiffEntryOwner entry) {
+ entry->parent = this;
+ entries[entry->tag] = move(entry);
+}
+
+TiffEntry* TiffIFD::getEntry(TiffTag tag) const {
+ auto i = entries.find(tag);
+ if (i == entries.end())
+ ThrowTPE("Entry 0x%x not found.", tag);
+ return i->second.get();
+}
+
+TiffID TiffRootIFD::getID() const
+{
+ TiffID id;
+ auto makeE = getEntryRecursive(MAKE);
+ auto modelE = getEntryRecursive(MODEL);
+
+ if (!makeE)
+ ThrowTPE("Failed to find MAKE entry.");
+ if (!modelE)
+ ThrowTPE("Failed to find MODEL entry.");
+
+ id.make = trimSpaces(makeE->getString());
+ id.model = trimSpaces(modelE->getString());
+
+ return id;
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/tiff/TiffIFD.h b/src/external/rawspeed/src/librawspeed/tiff/TiffIFD.h
new file mode 100644
index 000000000..dd272e617
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/tiff/TiffIFD.h
@@ -0,0 +1,121 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for uint32, ushort16
+#include "common/NORangesSet.h" // for NORangesSet
+#include "io/Buffer.h" // for Buffer (ptr only), DataBuffer
+#include "io/ByteStream.h" // for ByteStream
+#include "io/Endianness.h" // for getHostEndianness, Endianne...
+#include "parsers/TiffParserException.h" // for ThrowTPE
+#include "tiff/TiffEntry.h" // IWYU pragma: keep
+#include "tiff/TiffTag.h" // for TiffTag
+#include <map> // for map, _Rb_tree_const_iterator
+#include <memory> // for unique_ptr
+#include <string> // for string
+#include <vector> // for vector
+
+namespace rawspeed {
+
+class TiffIFD;
+
+class TiffRootIFD;
+
+using TiffIFDOwner = std::unique_ptr<TiffIFD>;
+using TiffRootIFDOwner = std::unique_ptr<TiffRootIFD>;
+using TiffEntryOwner = std::unique_ptr<TiffEntry>;
+
+class TiffIFD
+{
+ uint32 nextIFD = 0;
+ TiffIFD* parent;
+ std::vector<TiffIFDOwner> subIFDs;
+ std::map<TiffTag, TiffEntryOwner> entries;
+
+ friend class TiffEntry;
+ friend class FiffParser;
+ friend class TiffParser;
+
+ void checkOverflow();
+ void add(TiffIFDOwner subIFD);
+ void add(TiffEntryOwner entry);
+ TiffRootIFDOwner parseDngPrivateData(NORangesSet<Buffer>* ifds, TiffEntry* t);
+ TiffRootIFDOwner parseMakerNote(NORangesSet<Buffer>* ifds, TiffEntry* t);
+ void parseIFDEntry(NORangesSet<Buffer>* ifds, ByteStream* bs);
+
+public:
+ explicit TiffIFD(TiffIFD* parent);
+
+ TiffIFD(TiffIFD* parent, NORangesSet<Buffer>* ifds, const DataBuffer& data,
+ uint32 offset);
+
+ virtual ~TiffIFD() = default;
+
+ // make sure we never copy-constuct/assign a TiffIFD to keep the owning
+ // subcontainers contents save
+ TiffIFD(const TiffIFD&) = delete;
+ TiffIFD& operator=(const TiffIFD&) = delete;
+
+ uint32 getNextIFD() const {return nextIFD;}
+ std::vector<const TiffIFD*> getIFDsWithTag(TiffTag tag) const;
+ const TiffIFD* getIFDWithTag(TiffTag tag, uint32 index = 0) const;
+ TiffEntry* getEntry(TiffTag tag) const;
+ TiffEntry* __attribute__((pure)) getEntryRecursive(TiffTag tag) const;
+ bool __attribute__((pure)) hasEntry(TiffTag tag) const {
+ return entries.find(tag) != entries.end();
+ }
+ bool hasEntryRecursive(TiffTag tag) const { return getEntryRecursive(tag) != nullptr; }
+
+ const std::vector<TiffIFDOwner>& getSubIFDs() const { return subIFDs; }
+// const std::map<TiffTag, TiffEntry*>& getEntries() const { return entries; }
+};
+
+struct TiffID
+{
+ std::string make;
+ std::string model;
+};
+
+class TiffRootIFD final : public TiffIFD {
+public:
+ const DataBuffer rootBuffer;
+
+ TiffRootIFD(TiffIFD* parent_, NORangesSet<Buffer>* ifds,
+ const DataBuffer& data, uint32 offset)
+ : TiffIFD(parent_, ifds, data, offset), rootBuffer(data) {}
+
+ // find the MAKE and MODEL tags identifying the camera
+ // note: the returned strings are trimmed automatically
+ TiffID getID() const;
+};
+
+inline Endianness getTiffByteOrder(const ByteStream& bs, uint32 pos,
+ const char* context = "") {
+ if (bs.hasPatternAt("II", 2, pos))
+ return Endianness::little;
+ if (bs.hasPatternAt("MM", 2, pos))
+ return Endianness::big;
+
+ ThrowTPE("Failed to parse TIFF endianess information in %s.", context);
+}
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/librawspeed/tiff/TiffTag.h b/src/external/rawspeed/src/librawspeed/tiff/TiffTag.h
new file mode 100644
index 000000000..4d8a2320c
--- /dev/null
+++ b/src/external/rawspeed/src/librawspeed/tiff/TiffTag.h
@@ -0,0 +1,355 @@
+// Authors:
+// Larry Ewing <lewing@novell.com>
+//
+//
+// Copyright (C) 2004 - 2006 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#pragma once
+
+namespace rawspeed {
+
+enum TiffTag {
+ INTEROPERABILITYINDEX = 0x0001,
+ INTEROPERABILITYVERSION = 0x0002,
+ CANONSHOTINFO = 0x0004,
+ CANONPOWERSHOTG9WB = 0x0029,
+ PANASONIC_ISO_SPEED = 23,
+ NEWSUBFILETYPE = 0x00FE,
+ SUBFILETYPE = 0x00FF,
+ MAKERNOTE_ALT = 0x2e,
+
+ IMAGEWIDTH = 0x0100,
+ IMAGELENGTH = 0x0101,
+ BITSPERSAMPLE = 0x0102,
+ COMPRESSION = 0x0103,
+ PHOTOMETRICINTERPRETATION = 0x0106,
+ FILLORDER = 0x010A,
+ DOCUMENTNAME = 0x010D,
+ IMAGEDESCRIPTION = 0x010E,
+ MAKE = 0x010F,
+ MODEL = 0x0110,
+ STRIPOFFSETS = 0x0111,
+ ORIENTATION = 0x0112,
+ SAMPLESPERPIXEL = 0x0115,
+ ROWSPERSTRIP = 0x0116,
+ STRIPBYTECOUNTS = 0x0117,
+ PANASONIC_STRIPOFFSET = 0x118,
+ XRESOLUTION = 0x011A,
+ YRESOLUTION = 0x011B,
+ PLANARCONFIGURATION = 0x011C,
+
+ GRAYRESPONSECURVE = 0x0123,
+
+ T4OPTIONS = 0x0124,
+ T6OPTIONS = 0x0125,
+
+ RESOLUTIONUNIT = 0x0128,
+ TRANSFERFUNCTION = 0x012D,
+ FUJI_LAYOUT = 0x0130,
+ SOFTWARE = 0x0131,
+ DATETIME = 0x0132,
+ ARTIST = 0x013B,
+ PREDICTOR = 0x013D,
+ WHITEPOINT = 0x013E,
+ PRIMARYCHROMATICITIES = 0x013F,
+
+ HALFTONEHINTS = 0x0141,
+ // TILED IMAGES
+ TILEWIDTH = 0x0142,
+ TILELENGTH = 0x0143,
+ TILEOFFSETS = 0x0144,
+ TILEBYTECOUNTS = 0x0145,
+
+ SUBIFDS = 0x014A, // TIFF-EP
+
+ // CMYK IMAGES
+ INKSET = 0x014C,
+ NUMBEROFINKS = 0x014E,
+ INKNAMES = 0x014D,
+ DOTRANGE = 0x0150,
+ TARGETPRINTER = 0x0151,
+ EXTRASAMPLES = 0x0152,
+ SAMPLEFORMAT = 0x0153,
+ SMINSAMPLEVALUE = 0x0154,
+ SMAXSAMPLEVALUE = 0x0155,
+
+ TRANSFERRANGE = 0x0156,
+
+ CLIPPATH = 0x0157, // TIFF PAGEMAKER TECHNOTE #2.
+
+ JPEGTABLES = 0x015B, // TIFF-EP
+
+ JPEGPROC = 0x0200,
+ JPEGINTERCHANGEFORMAT = 0x0201,
+ JPEGINTERCHANGEFORMATLENGTH = 0x0202,
+ JPEGRESTARTINTERVAL = 0x0203,
+ JPEGLOSSLESSPREDICTORS = 0x0205,
+ JPEGPOINTTRANSFORMS = 0x0206,
+ JPEGQTABLES = 0x0207,
+ JPEGDCTABLES = 0x0208,
+ JPEGACTABLES = 0x0209,
+
+ YCBCRCOEFFICIENTS = 0x0211,
+ YCBCRSUBSAMPLING = 0x0212,
+ YCBCRPOSITIONING = 0x0213,
+
+ REFERENCEBLACKWHITE = 0x0214,
+ KODAKWB = 0x0F00,
+ EPSONWB = 0x0E80,
+ RELATEDIMAGEFILEFORMAT = 0x1000,
+ RELATEDIMAGEWIDTH = 0x1001,
+ RELATEDIMAGELENGTH = 0x1002,
+ OLYMPUSREDMULTIPLIER = 0x1017,
+ OLYMPUSBLUEMULTIPLIER = 0x1018,
+ OLYMPUSIMAGEPROCESSING = 0x2040,
+ FUJIOLDWB = 0x2ff0,
+
+ CANONCOLORDATA = 0x4001,
+
+ SONYGRBGLEVELS = 0x7303,
+ SONYRGGBLEVELS = 0x7313,
+
+ CFAREPEATPATTERNDIM = 0x828D,
+ CFAPATTERN = 0x828E,
+ BATTERYLEVEL = 0x828F,
+ COPYRIGHT = 0x8298,
+ EXPOSURETIME = 0x829A,
+ FNUMBER = 0x829D,
+
+ // THESE ARE FROM THE NIFF SPEC AND ONLY REALLY VALID WHEN THE HEADER BEGINS WITH IIN1
+ // SEE THE NIFFTAG ENUM FOR THE SPECIFCATION SPECIFIC NAMES
+ ROTATION = 0x82B9,
+ NAVYCOMPRESSION = 0x82BA,
+ TILEINDEX = 0x82BB,
+ // END NIFF SPECIFIC
+
+ IPTCNAA = 0x83BB,
+
+ LEAFMETADATA = 0x8606,
+
+ PHOTOSHOPPRIVATE = 0x8649,
+
+ EXIFIFDPOINTER = 0x8769,
+ INTERCOLORPROFILE = 0x8773,
+ EXPOSUREPROGRAM = 0x8822,
+ SPECTRALSENSITIVITY = 0x8824,
+ GPSINFOIFDPOINTER = 0x8825,
+ ISOSPEEDRATINGS = 0x8827,
+ OECF = 0x8828,
+ EXIFVERSION = 0x9000,
+ DATETIMEORIGINAL = 0x9003,
+ DATETIMEDIGITIZED = 0x9004,
+ COMPONENTSCONFIGURATION = 0x9101,
+ COMPRESSEDBITSPERPIXEL = 0x9102,
+ SHUTTERSPEEDVALUE = 0x9201,
+ APERTUREVALUE = 0x9202,
+ BRIGHTNESSVALUE = 0x9203,
+ EXPOSUREBIASVALUE = 0x9204,
+ MAXAPERTUREVALUE = 0x9205,
+ SUBJECTDISTANCE = 0x9206,
+ METERINGMODE = 0x9207,
+ LIGHTSOURCE = 0x9208,
+ FLASH = 0x9209,
+ FOCALLENGTH = 0x920A,
+
+ FLASHENERGY_TIFFEP = 0x920B,// TIFF-EP
+ SPACIALFREQUENCYRESPONSE = 0x920C,// TIFF-EP
+ NOISE = 0x920D,// TIFF-EP
+ FOCALPLANEXRESOLUTION_TIFFEP = 0x920E,// TIFF-EP
+ FOCALPLANEYRESOLUTION_TIFFEP = 0x920F,// TIFF-EP
+ FOCALPLANERESOLUTIONUNIT_TIFFEP = 0x9210,// TIFF-EP
+ IMAGENAME = 0x9211,// TIFF-EP
+ SECURITYCLASSIFICATION = 0x9212,// TIFF-EP
+
+ IMAGEHISTORY = 0x9213, // TIFF-EP NULL SEPARATED LIST
+
+ SUBJECTAREA = 0x9214,
+
+ EXPOSUREINDEX_TIFFEP = 0x9215, // TIFF-EP
+ TIFFEPSTANDARDID = 0x9216, // TIFF-EP
+ SENSINGMETHOD_TIFFEP = 0x9217, // TIFF-EP
+
+ MAKERNOTE = 0x927C,
+ USERCOMMENT = 0x9286,
+ SUBSECTIME = 0x9290,
+ SUBSECTIMEORIGINAL = 0x9291,
+ SUBSECTIMEDIGITIZED = 0x9292,
+ FLASHPIXVERSION = 0xA000,
+ COLORSPACE = 0xA001,
+ PIXELXDIMENSION = 0xA002,
+ PIXELYDIMENSION = 0xA003,
+ RELATEDSOUNDFILE = 0xA004,
+ INTEROPERABILITYIFDPOINTER = 0xA005,
+ SAMSUNG_WB_RGGBLEVELSUNCORRECTED = 0xa021,
+ SAMSUNG_WB_RGGBLEVELSBLACK = 0xa028,
+ FLASHENERGY = 0xA20B,
+ SPATIALFREQUENCYRESPONSE = 0xA20C,
+ FOCALPLANEXRESOLUTION = 0xA20E,
+ FOCALPLANEYRESOLUTION = 0xA20F,
+ FOCALPLANERESOLUTIONUNIT = 0xA210,
+ SUBJECTLOCATION = 0xA214,
+ EXPOSUREINDEX = 0xA215,
+ SENSINGMETHOD = 0xA217,
+ FILESOURCE = 0xA300,
+ SCENETYPE = 0xA301,
+ EXIFCFAPATTERN = 0xA302,
+ CUSTOMRENDERED = 0xA401,
+ EXPOSUREMODE = 0xA402,
+ WHITEBALANCE = 0xA403,
+ DIGITALZOOMRATIO = 0xA404,
+ FOCALLENGTHIN35MMFILM = 0xA405,
+ SCENECAPTURETYPE = 0xA406,
+ GAINCONTROL = 0xA407,
+ CONTRAST = 0xA408,
+ SATURATION = 0xA409,
+ SHARPNESS = 0xA40A,
+ DEVICESETTINGDESCRIPTION = 0xA40B,
+ SUBJECTDISTANCERANGE = 0xA40C,
+ IMAGEUNIQUEID = 0xA420,
+
+ // THE FOLLOWING IDS ARE NOT DESCRIBED THE EXIF SPEC
+#ifndef GAMMA
+ GAMMA = 0xA500,
+#endif
+
+ // THE XMP SPEC DECLARES THAT XMP DATA SHOULD LIVE 0x2BC WHEN
+ // EMBEDDED IN TIFF IMAGES.
+ XMP = 0x02BC,
+ // Canon tag for uncompressed RGB preview
+ CANON_UNCOMPRESSED = 0xC5D9,
+
+ // FROM THE DNG SPEC
+ DNGVERSION = 0xC612, // IFD0
+ DNGBACKWARDVERSION = 0xC613, // IFD0
+ UNIQUECAMERAMODEL = 0xC614, // IFD0
+ LOCALIZEDCAMERAMODEL = 0xC615, // IFD0
+ CFAPLANECOLOR = 0xC616, // RAWIFD
+ CFALAYOUT = 0xC617, // RAWIFD
+ LINEARIZATIONTABLE = 0xC618, // RAWIFD
+ BLACKLEVELREPEATDIM = 0xC619, // RAWIFD
+ BLACKLEVEL = 0xC61A, // RAWIFD
+ BLACKLEVELDELTAH = 0xC61B, // RAWIFD
+ BLACKLEVELDELTAV = 0xC61C, // RAWIFD
+ WHITELEVEL = 0xC61D, // RAWIFD
+ DEFAULTSCALE = 0xC61E, // RAWIFD
+ DEFAULTCROPORIGIN = 0xC61F, // RAWIFD
+ DEFAULTCROPSIZE = 0xC620, // RAWIFD
+ COLORMATRIX1 = 0xC621, // IFD0
+ COLORMATRIX2 = 0xC622, // IFD0
+ CAMERACALIBRATION1 = 0xC623, // IFD0
+ CAMERACALIBRATION2 = 0xC624, // IFD0
+ REDUCTIONMATRIX1 = 0xC625, // IFD0
+ REDUCTIONMATRIX2 = 0xC626, // IFD0
+ ANALOGBALANCE = 0xC627, // IFD0
+ ASSHOTNEUTRAL = 0xC628, // IFD0
+ ASSHOTWHITEXY = 0xC629, // IFD0
+ BASELINEEXPOSURE = 0xC62A, // IFD0
+ BASELINENOISE = 0xC62B, // IFD0
+ BASELINESHARPNESS = 0xC62C, // IFD0
+ BAYERGREESPIT = 0xC62D, // IFD0
+ LINEARRESPONSELIMIT = 0xC62E, // IFD0
+ CAMERASERIALNUMBER = 0xC62F, // IFD0
+ LENSINFO = 0xC630, // IFD0
+ CHROMABLURRADIUS = 0xC631, // RAWIFD
+ ANTIALIASSTRENGTH = 0xC632, // RAWIFD
+ DNGPRIVATEDATA = 0xC634, // IFD0
+
+ MAKERNOTESAFETY = 0xC635, // IFD0
+
+ // THE SPEC SAYS BESTQUALITYSCALE IS 0xC635 BUT IT APPEARS TO BE WRONG
+ //BESTQUALITYSCALE = 0xC635, // RAWIFD
+ BESTQUALITYSCALE = 0xC65C, // RAWIFD THIS LOOKS LIKE THE CORRECT VALUE
+ SHADOWSCALE = 50739,
+ RAWDATAUNIQUEID = 50781,
+ ORIGINALRAWFILENAME = 50827,
+ ORIGINALRAWFILEDATA = 50828,
+ ACTIVEAREA = 50829,
+ MASKEDAREAS = 50830,
+ ASSHOTICCPROFILE = 50831,
+ ASSHOTPREPROFILEMATRIX = 50832,
+ CURRENTICCPROFILE = 50833,
+ CURRENTPREPROFILEMATRIX = 50834,
+ COLORIMETRICREFERENCE = 50879,
+ KODAKKDCPRIVATEIFD = 65024,
+ CAMERACALIBRATIONSIGNATURE = 0xC6F3,
+ PROFILECALIBRATIONSIGNATURE = 0xC6F4,
+ EXTRACAMERAPROFILES = 0xC6F5,
+ ASSHOTPROFILENAME = 0xC6F6,
+ NOISEREDUCTIONAPPLIED = 0xC6F7,
+ PROFILENAME = 0xC6F8,
+ PROFILEHUESATMAPDIMS = 0xC6F9,
+ PROFILEHUESATMAPDATA1 = 0xC6FA,
+ PROFILEHUESATMAPDATA2 = 0xC6FB,
+ PROFILETONECURVE = 0xC6FC,
+ PROFILEEMBEDPOLICY = 0xC6FD,
+ PROFILECOPYRIGHT = 0xC6FE,
+ FORWARDMATRIX1 = 0xC714,
+ FORWARDMATRIX2 = 0xC715,
+ PREVIEWAPPLICATIONNAME = 0xC716,
+ PREVIEWAPPLICATIONVERSION = 0xC717,
+ PREVIEWSETTINGSNAME = 0xC718,
+ PREVIEWSETTINGSDIGEST = 0xC719,
+ PREVIEWCOLORSPACE = 0xC71A,
+ PREVIEWDATETIME = 0xC71B,
+ RAWIMAGEDIGEST = 0xC71C,
+ ORIGINALRAWFILEDIGEST = 0xC71D,
+ SUBTILEBLOCKSIZE = 0xC71E,
+ ROWINTERLEAVEFACTOR = 0xC71F,
+ PROFILELOOKTABLEDIMS = 0xC725,
+ PROFILELOOKTABLEDATA = 0xC726,
+ OPCODELIST1 = 0xC740,
+ OPCODELIST2 = 0xC741,
+ OPCODELIST3 = 0xC742,
+ NOISEPROFILE = 0xC761,
+ CANONCR2SLICE = 0xC640, // CANON CR2
+ CANON_SRAWTYPE = 0xC6C5, // IFD3
+ CANON_SENSOR_INFO = 0x00E0, // MakerNote
+ CANON_RAW_DATA_OFFSET = 0x0081, // MakerNote TIF
+
+ CALIBRATIONILLUMINANT1 = 0xC65A, // IFD0
+ CALIBRATIONILLUMINANT2 = 0xC65B, // IFD0
+ SONY_CURVE = 28688,
+ SONY_OFFSET = 0x7200,
+ SONY_LENGTH = 0x7201,
+ SONY_KEY = 0x7221,
+
+ // PRINT IMAGE MATCHING DATA
+ PIMIFDPOINTER = 0xC4A5,
+ FUJI_RAW_IFD = 0xF000,
+ FUJI_RAWIMAGEFULLWIDTH = 0xF001,
+ FUJI_RAWIMAGEFULLHEIGHT = 0xF002,
+ FUJI_BITSPERSAMPLE = 0xF003,
+ FUJI_STRIPOFFSETS = 0xF007,
+ FUJI_STRIPBYTECOUNTS = 0xF008,
+ FUJI_BLACKLEVEL = 0xF00A,
+ FUJI_WB_GRBLEVELS = 0xF00E,
+
+ KODAK_IFD = 0x8290,
+ KODAK_LINEARIZATION = 0x090D,
+ KODAK_KDC_WB = 0xFA2A,
+ KODAK_KDC_OFFSET = 0xFD04,
+ KODAK_KDC_WIDTH = 0xFD00,
+ KODAK_KDC_HEIGHT = 0xFD01,
+ KODAK_IFD2 = 0xFE00,
+};
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/utilities/CMakeLists.txt b/src/external/rawspeed/src/utilities/CMakeLists.txt
new file mode 100644
index 000000000..3d410e8f0
--- /dev/null
+++ b/src/external/rawspeed/src/utilities/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_subdirectory(identify)
+
+if(BUILD_TESTING)
+ add_subdirectory(rstest)
+endif()
+
+if(BUILD_BENCHMARKING)
+ add_subdirectory(rsbench)
+endif()
diff --git a/src/external/rawspeed/src/utilities/identify/CMakeLists.txt b/src/external/rawspeed/src/utilities/identify/CMakeLists.txt
new file mode 100644
index 000000000..779323a1d
--- /dev/null
+++ b/src/external/rawspeed/src/utilities/identify/CMakeLists.txt
@@ -0,0 +1,21 @@
+set(rsidentify "rs-identify")
+if(DEFINED RAWSPEED_BINARY_PREFIX)
+ set(rsidentify "${RAWSPEED_BINARY_PREFIX}-${rsidentify}")
+endif()
+
+add_executable(${rsidentify} rawspeed-identify.cpp)
+target_compile_definitions(${rsidentify}
+ PRIVATE -DRS_CAMERAS_XML_PATH="${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATAROOTDIR}/rawspeed/cameras.xml"
+)
+
+target_link_libraries(${rsidentify} rawspeed)
+
+if(WITH_OPENMP AND OPENMP_FOUND AND TARGET OpenMP::OpenMP)
+ target_link_libraries(${rsidentify} OpenMP::OpenMP)
+endif()
+
+if(BUILD_TESTING)
+ add_test(NAME utilities/${rsidentify} COMMAND ${rsidentify})
+endif()
+
+install(TARGETS ${rsidentify} DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/external/rawspeed/src/utilities/identify/rawspeed-identify.cpp b/src/external/rawspeed/src/utilities/identify/rawspeed-identify.cpp
new file mode 100644
index 000000000..2f77c8211
--- /dev/null
+++ b/src/external/rawspeed/src/utilities/identify/rawspeed-identify.cpp
@@ -0,0 +1,318 @@
+/*
+ This file is part of darktable,
+ copyright (c) 2009--2011 johannes hanika.
+ copyright (c) 2016 Pedro Côrte-Real
+
+ darktable is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ darktable is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with darktable. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "RawSpeed-API.h" // for RawImage, RawImageData, iPoint2D, ImageMet...
+
+#include <cstddef> // for size_t
+#include <cstdint> // for uint16_t
+#include <cstdio> // for fprintf, stdout, stderr, printf
+#include <memory> // for unique_ptr
+#include <string> // for string, operator+
+#include <sys/stat.h> // for stat
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+// define this function, it is only declared in rawspeed:
+#ifdef _OPENMP
+extern "C" int rawspeed_get_number_of_processor_cores() {
+ return omp_get_num_procs();
+}
+#else
+extern "C" int __attribute__((const)) rawspeed_get_number_of_processor_cores() {
+ return 1;
+}
+#endif
+
+namespace rawspeed {
+
+namespace identify {
+
+std::string find_cameras_xml(const char* argv0);
+
+std::string find_cameras_xml(const char *argv0) {
+ struct stat statbuf;
+
+#ifdef RS_CAMERAS_XML_PATH
+ static const char set_camfile[] = RS_CAMERAS_XML_PATH;
+ if (stat(set_camfile, &statbuf)) {
+ fprintf(stderr, "WARNING: Couldn't find cameras.xml in '%s'\n",
+ set_camfile);
+ } else {
+ return set_camfile;
+ }
+#endif
+
+ const std::string self(argv0);
+
+ // If we haven't been provided with a valid cameras.xml path on compile try
+ // relative to argv[0]
+ const std::size_t lastslash = self.find_last_of(R"(/\)");
+ const std::string bindir(self.substr(0, lastslash));
+
+ std::string found_camfile(bindir +
+ "/../share/darktable/rawspeed/cameras.xml");
+
+ if (stat(found_camfile.c_str(), &statbuf)) {
+#ifndef __APPLE__
+ fprintf(stderr, "WARNING: Couldn't find cameras.xml in '%s'\n",
+ found_camfile.c_str());
+#else
+ fprintf(stderr, "WARNING: Couldn't find cameras.xml in '%s'\n",
+ found_camfile.c_str());
+ found_camfile =
+ bindir + "/../Resources/share/darktable/rawspeed/cameras.xml";
+ if (stat(found_camfile.c_str(), &statbuf)) {
+ fprintf(stderr, "WARNING: Couldn't find cameras.xml in '%s'\n",
+ found_camfile.c_str());
+ }
+#endif
+ }
+
+#ifdef RAWSPEED_STANDALONE_BUILD
+ // running from build dir?
+ found_camfile = std::string(CMAKE_SOURCE_DIR "/data/cameras.xml");
+#endif
+
+ if (stat(found_camfile.c_str(), &statbuf)) {
+#ifndef __APPLE__
+ fprintf(stderr, "ERROR: Couldn't find cameras.xml in '%s'\n",
+ found_camfile.c_str());
+ return nullptr;
+#else
+ fprintf(stderr, "WARNING: Couldn't find cameras.xml in '%s'\n",
+ found_camfile.c_str());
+ found_camfile =
+ bindir + "/../Resources/share/darktable/rawspeed/cameras.xml";
+ if (stat(found_camfile.c_str(), &statbuf)) {
+ fprintf(stderr, "ERROR: Couldn't find cameras.xml in '%s'\n",
+ found_camfile.c_str());
+ return nullptr;
+ }
+#endif
+ }
+
+ return found_camfile;
+}
+
+} // namespace identify
+
+} // namespace rawspeed
+
+using rawspeed::CameraMetaData;
+using rawspeed::FileReader;
+using rawspeed::RawParser;
+using rawspeed::RawImage;
+using rawspeed::uchar8;
+using rawspeed::uint32;
+using rawspeed::iPoint2D;
+using rawspeed::TYPE_USHORT16;
+using rawspeed::TYPE_FLOAT32;
+using rawspeed::RawspeedException;
+using rawspeed::identify::find_cameras_xml;
+
+int main(int argc, char* argv[]) { // NOLINT
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: darktable-rs-identify <file>\n");
+ return 0;
+ }
+
+ const std::string camfile = find_cameras_xml(argv[0]);
+ if (camfile.empty()) {
+ // fprintf(stderr, "ERROR: Couldn't find cameras.xml\n");
+ return 2;
+ }
+ // fprintf(stderr, "Using cameras.xml from '%s'\n", camfile.c_str());
+
+ try {
+ std::unique_ptr<const CameraMetaData> meta;
+
+#ifdef HAVE_PUGIXML
+ meta = std::make_unique<CameraMetaData>(camfile.c_str());
+#else
+ meta = std::make_unique<CameraMetaData>();
+#endif
+
+ if (!meta.get()) {
+ fprintf(stderr, "ERROR: Couldn't get a CameraMetaData instance\n");
+ return 2;
+ }
+
+#ifndef _WIN32
+ char* imageFileName = argv[1];
+#else
+ // turn the locale ANSI encoded string into UTF-8 so that FileReader can
+ // turn it into UTF-16 later
+ int size = MultiByteToWideChar(CP_ACP, 0, argv[1], -1, NULL, 0);
+ std::wstring wImageFileName;
+ wImageFileName.resize(size);
+ MultiByteToWideChar(CP_ACP, 0, argv[1], -1, &wImageFileName[0], size);
+ size = WideCharToMultiByte(CP_UTF8, 0, &wImageFileName[0], -1, NULL, 0,
+ NULL, NULL);
+ std::string _imageFileName;
+ _imageFileName.resize(size);
+ char* imageFileName = &_imageFileName[0];
+ WideCharToMultiByte(CP_UTF8, 0, &wImageFileName[0], -1, imageFileName, size,
+ NULL, NULL);
+#endif
+
+ fprintf(stderr, "Loading file: \"%s\"\n", imageFileName);
+
+ FileReader f(imageFileName);
+
+ auto m(f.readFile());
+
+ RawParser t(m.get());
+
+ auto d(t.getDecoder(meta.get()));
+
+ if (!d.get()) {
+ fprintf(stderr, "ERROR: Couldn't get a RawDecoder instance\n");
+ return 2;
+ }
+
+ d->applyCrop = false;
+ d->failOnUnknown = true;
+ RawImage r = d->mRaw;
+ const RawImage* const raw = &r;
+
+ d->decodeMetaData(meta.get());
+
+ fprintf(stdout, "make: %s\n", r->metadata.make.c_str());
+ fprintf(stdout, "model: %s\n", r->metadata.model.c_str());
+
+ fprintf(stdout, "canonical_make: %s\n", r->metadata.canonical_make.c_str());
+ fprintf(stdout, "canonical_model: %s\n",
+ r->metadata.canonical_model.c_str());
+ fprintf(stdout, "canonical_alias: %s\n",
+ r->metadata.canonical_alias.c_str());
+
+ d->checkSupport(meta.get());
+ d->decodeRaw();
+ d->decodeMetaData(meta.get());
+ r = d->mRaw;
+
+ const auto errors = r->getErrors();
+ for (auto& error : errors)
+ fprintf(stderr, "WARNING: [rawspeed] %s\n", error.c_str());
+
+ fprintf(stdout, "blackLevel: %d\n", r->blackLevel);
+ fprintf(stdout, "whitePoint: %d\n", r->whitePoint);
+
+ fprintf(stdout, "blackLevelSeparate: %d %d %d %d\n",
+ r->blackLevelSeparate[0], r->blackLevelSeparate[1],
+ r->blackLevelSeparate[2], r->blackLevelSeparate[3]);
+
+ fprintf(stdout, "wbCoeffs: %f %f %f %f\n", r->metadata.wbCoeffs[0],
+ r->metadata.wbCoeffs[1], r->metadata.wbCoeffs[2],
+ r->metadata.wbCoeffs[3]);
+
+ fprintf(stdout, "isCFA: %d\n", r->isCFA);
+ uint32 filters = r->cfa.getDcrawFilter();
+ fprintf(stdout, "filters: %d (0x%x)\n", filters, filters);
+ const uint32 bpp = r->getBpp();
+ fprintf(stdout, "bpp: %d\n", bpp);
+ const uint32 cpp = r->getCpp();
+ fprintf(stdout, "cpp: %d\n", cpp);
+ fprintf(stdout, "dataType: %d\n", r->getDataType());
+
+ // dimensions of uncropped image
+ const iPoint2D dimUncropped = r->getUncroppedDim();
+ fprintf(stdout, "dimUncropped: %dx%d\n", dimUncropped.x, dimUncropped.y);
+
+ // dimensions of cropped image
+ iPoint2D dimCropped = r->dim;
+ fprintf(stdout, "dimCropped: %dx%d\n", dimCropped.x, dimCropped.y);
+
+ // crop - Top,Left corner
+ iPoint2D cropTL = r->getCropOffset();
+ fprintf(stdout, "cropOffset: %dx%d\n", cropTL.x, cropTL.y);
+
+ fprintf(stdout, "fuji_rotation_pos: %d\n", r->metadata.fujiRotationPos);
+ fprintf(stdout, "pixel_aspect_ratio: %f\n", r->metadata.pixelAspectRatio);
+
+ double sum = 0.0F;
+#ifdef _OPENMP
+#pragma omp parallel for default(none) schedule(static) reduction(+ : sum)
+#endif
+ for (int y = 0; y < dimUncropped.y; ++y) {
+ uchar8* const data = (*raw)->getDataUncropped(0, y);
+
+ for (unsigned x = 0; x < bpp * dimUncropped.x; ++x)
+ sum += static_cast<double>(data[x]);
+ }
+ fprintf(stdout, "Image byte sum: %lf\n", sum);
+ fprintf(stdout, "Image byte avg: %lf\n",
+ sum / static_cast<double>(dimUncropped.y * dimUncropped.x * bpp));
+
+ if (r->getDataType() == TYPE_FLOAT32) {
+ sum = 0.0F;
+
+#ifdef _OPENMP
+#pragma omp parallel for default(none) schedule(static) reduction(+ : sum)
+#endif
+ for (int y = 0; y < dimUncropped.y; ++y) {
+ auto* const data =
+ reinterpret_cast<float*>((*raw)->getDataUncropped(0, y));
+
+ for (unsigned x = 0; x < cpp * dimUncropped.x; ++x)
+ sum += static_cast<double>(data[x]);
+ }
+
+ fprintf(stdout, "Image float sum: %lf\n", sum);
+ fprintf(stdout, "Image float avg: %lf\n",
+ sum / static_cast<double>(dimUncropped.y * dimUncropped.x));
+ } else if (r->getDataType() == TYPE_USHORT16) {
+ sum = 0.0F;
+
+#ifdef _OPENMP
+#pragma omp parallel for default(none) schedule(static) reduction(+ : sum)
+#endif
+ for (int y = 0; y < dimUncropped.y; ++y) {
+ auto* const data =
+ reinterpret_cast<uint16_t*>((*raw)->getDataUncropped(0, y));
+
+ for (unsigned x = 0; x < cpp * dimUncropped.x; ++x)
+ sum += static_cast<double>(data[x]);
+ }
+
+ fprintf(stdout, "Image uint16_t sum: %lf\n", sum);
+ fprintf(stdout, "Image uint16_t avg: %lf\n",
+ sum / static_cast<double>(dimUncropped.y * dimUncropped.x));
+ }
+ } catch (RawspeedException& e) {
+ fprintf(stderr, "ERROR: [rawspeed] %s\n", e.what());
+
+ /* if an exception is raised lets not retry or handle the
+ specific ones, consider the file as corrupted */
+ return 2;
+ }
+
+ return 0;
+}
+
+// vim: shiftwidth=2 expandtab tabstop=2 cindent
+// kate: indent-mode cstyle; replace-tabs on; tab-indents: off;
+// kate: remove-trailing-space on;
diff --git a/src/external/rawspeed/src/utilities/rsbench/CMakeLists.txt b/src/external/rawspeed/src/utilities/rsbench/CMakeLists.txt
new file mode 100644
index 000000000..c76640cad
--- /dev/null
+++ b/src/external/rawspeed/src/utilities/rsbench/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_executable(rsbench main.cpp)
+
+target_link_libraries(rsbench rawspeed)
+target_link_libraries(rsbench rawspeed_bench)
+
+if(WITH_OPENMP AND OPENMP_FOUND AND TARGET OpenMP::OpenMP)
+ target_link_libraries(rsbench OpenMP::OpenMP)
+endif()
+
+add_dependencies(benchmarks rsbench)
diff --git a/src/external/rawspeed/src/utilities/rsbench/main.cpp b/src/external/rawspeed/src/utilities/rsbench/main.cpp
new file mode 100644
index 000000000..10bf5a5ba
--- /dev/null
+++ b/src/external/rawspeed/src/utilities/rsbench/main.cpp
@@ -0,0 +1,196 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "RawSpeed-API.h" // for RawDecoder, Buffer, FileReader
+#include <benchmark/benchmark.h> // for State, Benchmark, DoNotOptimize
+#include <chrono> // for duration, high_resolution_clock
+#include <ctime> // for clock, clock_t
+#include <map> // for map<>::mapped_type
+#include <memory> // for unique_ptr
+#include <ratio> // for milli, ratio
+#include <string> // for string, to_string
+// IWYU pragma: no_include <sys/time.h>
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+#define HAVE_STEADY_CLOCK
+
+using rawspeed::CameraMetaData;
+using rawspeed::FileReader;
+using rawspeed::RawImage;
+using rawspeed::RawParser;
+
+namespace {
+
+struct CPUClock {
+ using rep = std::clock_t;
+ using period = std::ratio<1, CLOCKS_PER_SEC>;
+ using duration = std::chrono::duration<rep, period>;
+ using time_point = std::chrono::time_point<CPUClock, duration>;
+
+ // static constexpr bool is_steady = false;
+
+ static time_point now() noexcept {
+ return time_point{duration{std::clock()}};
+ }
+};
+
+#if defined(HAVE_STEADY_CLOCK)
+template <bool HighResIsSteady = std::chrono::high_resolution_clock::is_steady>
+struct ChooseSteadyClock {
+ using type = std::chrono::high_resolution_clock;
+};
+
+template <> struct ChooseSteadyClock<false> {
+ using type = std::chrono::steady_clock;
+};
+#endif
+
+struct ChooseClockType {
+#if defined(HAVE_STEADY_CLOCK)
+ using type = ChooseSteadyClock<>::type;
+#else
+ using type = std::chrono::high_resolution_clock;
+#endif
+};
+
+template <typename Clock, typename period = std::ratio<1, 1>> struct Timer {
+ using rep = double;
+ using duration = std::chrono::duration<rep, period>;
+
+ mutable typename Clock::time_point start = Clock::now();
+
+ duration operator()() const {
+ duration elapsed = Clock::now() - start;
+ start = Clock::now();
+ return elapsed;
+ }
+};
+
+} // namespace
+
+static int currThreadCount;
+
+extern "C" int __attribute__((pure)) rawspeed_get_number_of_processor_cores() {
+ return currThreadCount;
+}
+
+static inline void BM_RawSpeed(benchmark::State& state, const char* fileName,
+ int threads) {
+ currThreadCount = threads;
+
+#ifdef HAVE_PUGIXML
+ static const CameraMetaData metadata(CMAKE_SOURCE_DIR "/data/cameras.xml");
+#else
+ static const CameraMetaData metadata{};
+#endif
+
+ FileReader reader(fileName);
+ const auto map(reader.readFile());
+
+ Timer<ChooseClockType::type> WT;
+ Timer<CPUClock> TT;
+
+ unsigned pixels = 0;
+ for (auto _ : state) {
+ RawParser parser(map.get());
+ auto decoder(parser.getDecoder(&metadata));
+
+ decoder->failOnUnknown = false;
+ decoder->checkSupport(&metadata);
+
+ decoder->decodeRaw();
+ decoder->decodeMetaData(&metadata);
+ RawImage raw = decoder->mRaw;
+
+ benchmark::DoNotOptimize(raw);
+
+ pixels = raw->getUncroppedDim().area();
+ }
+
+ std::string label("FileSize,MB=");
+ label += std::to_string(double(map->getSize()) / double(1UL << 20UL));
+ label += "; MPix=";
+ label += std::to_string(double(pixels) / 1e+06);
+ state.SetLabel(label.c_str());
+
+ const auto WallTime = WT();
+ const auto TotalTime = TT();
+ const auto ThreadingFactor = TotalTime.count() / WallTime.count();
+
+ state.counters.insert({
+ {"Pixels/s", benchmark::Counter(pixels, benchmark::Counter::kIsRate)},
+ {"CPUTime,s", TotalTime.count()},
+ {"ThreadingFactor", ThreadingFactor},
+ });
+
+ state.SetItemsProcessed(state.iterations());
+ state.SetBytesProcessed(state.iterations() * map->getSize());
+}
+
+static void addBench(const char* fName, std::string tName, int threads) {
+ tName += std::to_string(threads);
+
+ auto* b =
+ benchmark::RegisterBenchmark(tName.c_str(), &BM_RawSpeed, fName, threads);
+ b->Unit(benchmark::kMillisecond);
+ b->UseRealTime();
+}
+
+int main(int argc, char** argv) {
+ benchmark::Initialize(&argc, argv);
+
+ auto hasFlag = [argc, argv](std::string flag) {
+ bool found = false;
+ for (int i = 1; i < argc; ++i) {
+ if (!argv[i] || argv[i] != flag)
+ continue;
+ found = true;
+ argv[i] = nullptr;
+ }
+ return found;
+ };
+
+ bool threading = hasFlag("-t");
+
+#ifdef _OPENMP
+ const auto threadsMax = omp_get_num_procs();
+#else
+ const auto threadsMax = 1;
+#endif
+
+ const auto threadsMin = threading ? 1 : threadsMax;
+
+ for (int i = 1; i < argc; i++) {
+ if (!argv[i])
+ continue;
+
+ const char* fName = argv[i];
+ std::string tName(fName);
+ tName += "/threads:";
+
+ for (auto threads = threadsMin; threads <= threadsMax; threads++)
+ addBench(fName, tName, threads);
+ }
+
+ benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/src/external/rawspeed/src/utilities/rstest/CMakeLists.txt b/src/external/rawspeed/src/utilities/rstest/CMakeLists.txt
new file mode 100644
index 000000000..b2256f421
--- /dev/null
+++ b/src/external/rawspeed/src/utilities/rstest/CMakeLists.txt
@@ -0,0 +1,47 @@
+add_executable(rstest rstest.cpp md5.cpp)
+target_link_libraries(rstest rawspeed)
+
+if(WITH_OPENMP AND OPENMP_FOUND AND TARGET OpenMP::OpenMP)
+ target_link_libraries(rstest OpenMP::OpenMP)
+endif()
+
+if(BUILD_TESTING)
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wno-suggest-attribute=const)
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wno-suggest-override)
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wno-missing-prototypes)
+
+ if(NOT SPECIAL_BUILD)
+ # should be < 64Kb
+ math(EXPR MAX_MEANINGFUL_SIZE 4*1024)
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wstack-usage=${MAX_MEANINGFUL_SIZE})
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wframe-larger-than=${MAX_MEANINGFUL_SIZE})
+
+ # as small as possible, but 1Mb+ is ok.
+ math(EXPR MAX_MEANINGFUL_SIZE 32*1024)
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wlarger-than=${MAX_MEANINGFUL_SIZE})
+ endif()
+
+ set(CMAKE_CXX_CLANG_TIDY_SAVE "${CMAKE_CXX_CLANG_TIDY}")
+
+ unset(CMAKE_CXX_CLANG_TIDY)
+
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wno-c99-extensions)
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wno-missing-variable-declarations)
+ add_executable(MD5Test md5.cpp MD5Test.cpp)
+ target_link_libraries(MD5Test gtest_main)
+ add_test(NAME utilities/rstest/md5 COMMAND MD5Test --gtest_output=xml:${UNITTEST_REPORT_PATH})
+ add_dependencies(tests MD5Test)
+
+ add_test(NAME utilities/rstest COMMAND rstest)
+endif()
+
+if(BUILD_BENCHMARKING)
+ add_executable(MD5Benchmark md5.cpp MD5Benchmark.cpp)
+ target_link_libraries(MD5Benchmark benchmark)
+
+ add_dependencies(benchmarks MD5Benchmark)
+endif()
+
+if(ENABLE_SAMPLEBASED_TESTING)
+ include(sample-based-testing)
+endif()
diff --git a/src/external/rawspeed/src/utilities/rstest/MD5Benchmark.cpp b/src/external/rawspeed/src/utilities/rstest/MD5Benchmark.cpp
new file mode 100644
index 000000000..d1009b2f9
--- /dev/null
+++ b/src/external/rawspeed/src/utilities/rstest/MD5Benchmark.cpp
@@ -0,0 +1,53 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "md5.h" // for md5_hash, md5_state
+#include <benchmark/benchmark.h> // for State, Benchmark, BENCHMARK
+#include <cstdint> // for uint8_t
+#include <cstdlib> // for free, malloc, size_t
+#include <memory> // for unique_ptr
+
+static inline void BM_MD5(benchmark::State& state) {
+ const size_t bufsize = state.range(0) * sizeof(char);
+ std::unique_ptr<char, decltype(&free)> buf((char*)malloc(bufsize), &free);
+
+ for (auto _ : state) {
+ rawspeed::md5::md5_state hash;
+ rawspeed::md5::md5_hash((uint8_t*)buf.get(), bufsize, &hash);
+ }
+
+ state.SetComplexityN(state.range(0));
+ state.SetItemsProcessed(state.complexity_length_n() * state.iterations());
+ state.SetBytesProcessed(1UL * sizeof(char) * state.items_processed());
+}
+
+static inline void CustomArguments(benchmark::internal::Benchmark* b) {
+ b->RangeMultiplier(2);
+#if 1
+ b->Arg(256 << 20);
+#else
+ b->Range(1, 1024 << 20)->Complexity(benchmark::oN);
+#endif
+ b->Unit(benchmark::kMillisecond);
+}
+
+BENCHMARK(BM_MD5)->Apply(CustomArguments);
+
+BENCHMARK_MAIN();
diff --git a/src/external/rawspeed/src/utilities/rstest/MD5Test.cpp b/src/external/rawspeed/src/utilities/rstest/MD5Test.cpp
new file mode 100644
index 000000000..4c76251b1
--- /dev/null
+++ b/src/external/rawspeed/src/utilities/rstest/MD5Test.cpp
@@ -0,0 +1,82 @@
+/*
+ * MD5 hash in C and x86 assembly
+ *
+ * Copyright (c) 2016 Project Nayuki
+ * https://www.nayuki.io/page/fast-md5-hash-implementation-in-x86-assembly
+ *
+ * (MIT License)
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of
+ * the Software, and to permit persons to whom the Software is furnished to do
+ * so,
+ * subject to the following conditions:
+ * - The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * - The Software is provided "as is", without warranty of any kind, express or
+ * implied, including but not limited to the warranties of merchantability,
+ * fitness for a particular purpose and noninfringement. In no event shall the
+ * authors or copyright holders be liable for any claim, damages or other
+ * liability, whether in an action of contract, tort or otherwise, arising
+ * from,
+ * out of or in connection with the Software or the use or other dealings in
+ * the
+ * Software.
+ */
+
+#include "md5.h" // for rawspeed::md5::state, md5_hash
+#include <cstdint> // for UINT32_C, uint8_t
+#include <cstring> // for strlen
+#include <gtest/gtest.h> // for AssertionResult, IsNullLiteralHelper, Param...
+#include <utility> // for pair, make_pair
+
+using MD5Testcase = std::pair<rawspeed::md5::md5_state, const uint8_t*>;
+class MD5Test : public ::testing::TestWithParam<MD5Testcase> {
+protected:
+ MD5Test() = default;
+ virtual void SetUp() override {
+ auto p = GetParam();
+
+ answer = p.first;
+ message = p.second;
+ }
+
+ rawspeed::md5::md5_state answer;
+ const uint8_t* message = nullptr;
+};
+
+#define TESTCASE(a, b, c, d, msg) \
+ { \
+ std::make_pair((rawspeed::md5::md5_state){{UINT32_C(a), UINT32_C(b), \
+ UINT32_C(c), UINT32_C(d)}}, \
+ (const uint8_t*)(msg)) \
+ }
+
+// Note: The MD5 standard specifies that uint32 are serialized to/from bytes in
+// little endian
+static MD5Testcase testCases[] = {
+ TESTCASE(0xD98C1DD4, 0x04B2008F, 0x980980E9, 0x7E42F8EC, ""),
+ TESTCASE(0xB975C10C, 0xA8B6F1C0, 0xE299C331, 0x61267769, "a"),
+ TESTCASE(0x98500190, 0xB04FD23C, 0x7D3F96D6, 0x727FE128, "abc"),
+ TESTCASE(0x7D696BF9, 0x8D93B77C, 0x312F5A52, 0xD061F1AA, "message digest"),
+ TESTCASE(0xD7D3FCC3, 0x00E49261, 0x6C49FB7D, 0x3BE167CA,
+ "abcdefghijklmnopqrstuvwxyz"),
+ TESTCASE(0x98AB74D1, 0xF5D977D2, 0x2C1C61A5, 0x9F9D419F,
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"),
+ TESTCASE(0xA2F4ED57, 0x55C9E32B, 0x2EDA49AC, 0x7AB60721,
+ "12345678901234567890123456789012345678901234567890123456789012345"
+ "678901234567890"),
+};
+
+INSTANTIATE_TEST_CASE_P(MD5Test, MD5Test, ::testing::ValuesIn(testCases));
+TEST_P(MD5Test, CheckTestCaseSet) {
+ ASSERT_NO_THROW({
+ rawspeed::md5::md5_state hash;
+ rawspeed::md5::md5_hash(message, strlen((const char*)message), &hash);
+
+ ASSERT_EQ(hash, answer);
+ });
+}
diff --git a/src/external/rawspeed/src/utilities/rstest/md5.cpp b/src/external/rawspeed/src/utilities/rstest/md5.cpp
new file mode 100644
index 000000000..c6417861e
--- /dev/null
+++ b/src/external/rawspeed/src/utilities/rstest/md5.cpp
@@ -0,0 +1,210 @@
+/*
+ * MD5 hash in C and x86 assembly
+ *
+ * Copyright (c) 2016 Project Nayuki
+ * https://www.nayuki.io/page/fast-md5-hash-implementation-in-x86-assembly
+ *
+ * (MIT License)
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of
+ * the Software, and to permit persons to whom the Software is furnished to do
+ * so,
+ * subject to the following conditions:
+ * - The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * - The Software is provided "as is", without warranty of any kind, express or
+ * implied, including but not limited to the warranties of merchantability,
+ * fitness for a particular purpose and noninfringement. In no event shall the
+ * authors or copyright holders be liable for any claim, damages or other
+ * liability, whether in an action of contract, tort or otherwise, arising
+ * from,
+ * out of or in connection with the Software or the use or other dealings in
+ * the
+ * Software.
+ */
+
+#include "md5.h"
+#include <cstdint> // for uint32_t, uint8_t, UINT32_C
+#include <cstdio> // for printf, snprintf
+#include <cstring> // for memset, strlen, memcmp, memcpy
+#include <string> // for string
+
+namespace rawspeed {
+
+namespace md5 {
+
+// hashes 64 bytes at once
+static void md5_compress(md5_state* state, const uint8_t block[64]);
+
+static void md5_compress(md5_state* state, const uint8_t block[64]) {
+ uint32_t schedule[16] = {};
+
+ auto LOADSCHEDULE = [&block, &schedule](int i) {
+ for (int k = 3; k >= 0; k--)
+ schedule[i] |= uint32_t(block[4 * i + k]) << (8 * k);
+ };
+
+ for (int i = 0; i < 16; i++)
+ LOADSCHEDULE(i);
+
+ // Assumes that x is uint32_t and 0 < n < 32
+ auto ROTL32 = [](uint32_t x, int n) __attribute__((pure)) {
+ return (x << n) | (x >> (32 - n));
+ };
+
+ auto ROUND_TAIL = [ROTL32, &schedule](uint32_t& a, uint32_t b, uint32_t expr,
+ uint32_t k, uint32_t s, uint32_t t) {
+ a = 0UL + a + expr + t + schedule[k];
+ (a) = 0UL + b + ROTL32(a, s);
+ };
+
+ auto ROUND0 = [ROUND_TAIL](uint32_t& a, uint32_t b, uint32_t c, uint32_t d,
+ uint32_t k, uint32_t s, uint32_t t) {
+ ROUND_TAIL(a, b, d ^ (b & (c ^ d)), k, s, t);
+ };
+
+ auto ROUND1 = [ROUND_TAIL](uint32_t& a, uint32_t b, uint32_t c, uint32_t d,
+ uint32_t k, uint32_t s, uint32_t t) {
+ ROUND_TAIL(a, b, c ^ (d & (b ^ c)), k, s, t);
+ };
+
+ auto ROUND2 = [ROUND_TAIL](uint32_t& a, uint32_t b, uint32_t c, uint32_t d,
+ uint32_t k, uint32_t s, uint32_t t) {
+ ROUND_TAIL(a, b, b ^ c ^ d, k, s, t);
+ };
+
+ auto ROUND3 = [ROUND_TAIL](uint32_t& a, uint32_t b, uint32_t c, uint32_t d,
+ uint32_t k, uint32_t s, uint32_t t) {
+ ROUND_TAIL(a, b, c ^ (b | ~d), k, s, t);
+ };
+
+ uint32_t a = (*state)[0];
+ uint32_t b = (*state)[1];
+ uint32_t c = (*state)[2];
+ uint32_t d = (*state)[3];
+
+ ROUND0(a, b, c, d, 0, 7, 0xD76AA478);
+ ROUND0(d, a, b, c, 1, 12, 0xE8C7B756);
+ ROUND0(c, d, a, b, 2, 17, 0x242070DB);
+ ROUND0(b, c, d, a, 3, 22, 0xC1BDCEEE);
+ ROUND0(a, b, c, d, 4, 7, 0xF57C0FAF);
+ ROUND0(d, a, b, c, 5, 12, 0x4787C62A);
+ ROUND0(c, d, a, b, 6, 17, 0xA8304613);
+ ROUND0(b, c, d, a, 7, 22, 0xFD469501);
+ ROUND0(a, b, c, d, 8, 7, 0x698098D8);
+ ROUND0(d, a, b, c, 9, 12, 0x8B44F7AF);
+ ROUND0(c, d, a, b, 10, 17, 0xFFFF5BB1);
+ ROUND0(b, c, d, a, 11, 22, 0x895CD7BE);
+ ROUND0(a, b, c, d, 12, 7, 0x6B901122);
+ ROUND0(d, a, b, c, 13, 12, 0xFD987193);
+ ROUND0(c, d, a, b, 14, 17, 0xA679438E);
+ ROUND0(b, c, d, a, 15, 22, 0x49B40821);
+ ROUND1(a, b, c, d, 1, 5, 0xF61E2562);
+ ROUND1(d, a, b, c, 6, 9, 0xC040B340);
+ ROUND1(c, d, a, b, 11, 14, 0x265E5A51);
+ ROUND1(b, c, d, a, 0, 20, 0xE9B6C7AA);
+ ROUND1(a, b, c, d, 5, 5, 0xD62F105D);
+ ROUND1(d, a, b, c, 10, 9, 0x02441453);
+ ROUND1(c, d, a, b, 15, 14, 0xD8A1E681);
+ ROUND1(b, c, d, a, 4, 20, 0xE7D3FBC8);
+ ROUND1(a, b, c, d, 9, 5, 0x21E1CDE6);
+ ROUND1(d, a, b, c, 14, 9, 0xC33707D6);
+ ROUND1(c, d, a, b, 3, 14, 0xF4D50D87);
+ ROUND1(b, c, d, a, 8, 20, 0x455A14ED);
+ ROUND1(a, b, c, d, 13, 5, 0xA9E3E905);
+ ROUND1(d, a, b, c, 2, 9, 0xFCEFA3F8);
+ ROUND1(c, d, a, b, 7, 14, 0x676F02D9);
+ ROUND1(b, c, d, a, 12, 20, 0x8D2A4C8A);
+ ROUND2(a, b, c, d, 5, 4, 0xFFFA3942);
+ ROUND2(d, a, b, c, 8, 11, 0x8771F681);
+ ROUND2(c, d, a, b, 11, 16, 0x6D9D6122);
+ ROUND2(b, c, d, a, 14, 23, 0xFDE5380C);
+ ROUND2(a, b, c, d, 1, 4, 0xA4BEEA44);
+ ROUND2(d, a, b, c, 4, 11, 0x4BDECFA9);
+ ROUND2(c, d, a, b, 7, 16, 0xF6BB4B60);
+ ROUND2(b, c, d, a, 10, 23, 0xBEBFBC70);
+ ROUND2(a, b, c, d, 13, 4, 0x289B7EC6);
+ ROUND2(d, a, b, c, 0, 11, 0xEAA127FA);
+ ROUND2(c, d, a, b, 3, 16, 0xD4EF3085);
+ ROUND2(b, c, d, a, 6, 23, 0x04881D05);
+ ROUND2(a, b, c, d, 9, 4, 0xD9D4D039);
+ ROUND2(d, a, b, c, 12, 11, 0xE6DB99E5);
+ ROUND2(c, d, a, b, 15, 16, 0x1FA27CF8);
+ ROUND2(b, c, d, a, 2, 23, 0xC4AC5665);
+ ROUND3(a, b, c, d, 0, 6, 0xF4292244);
+ ROUND3(d, a, b, c, 7, 10, 0x432AFF97);
+ ROUND3(c, d, a, b, 14, 15, 0xAB9423A7);
+ ROUND3(b, c, d, a, 5, 21, 0xFC93A039);
+ ROUND3(a, b, c, d, 12, 6, 0x655B59C3);
+ ROUND3(d, a, b, c, 3, 10, 0x8F0CCC92);
+ ROUND3(c, d, a, b, 10, 15, 0xFFEFF47D);
+ ROUND3(b, c, d, a, 1, 21, 0x85845DD1);
+ ROUND3(a, b, c, d, 8, 6, 0x6FA87E4F);
+ ROUND3(d, a, b, c, 15, 10, 0xFE2CE6E0);
+ ROUND3(c, d, a, b, 6, 15, 0xA3014314);
+ ROUND3(b, c, d, a, 13, 21, 0x4E0811A1);
+ ROUND3(a, b, c, d, 4, 6, 0xF7537E82);
+ ROUND3(d, a, b, c, 11, 10, 0xBD3AF235);
+ ROUND3(c, d, a, b, 2, 15, 0x2AD7D2BB);
+ ROUND3(b, c, d, a, 9, 21, 0xEB86D391);
+
+ (*state)[0] = 0UL + (*state)[0] + a;
+ (*state)[1] = 0UL + (*state)[1] + b;
+ (*state)[2] = 0UL + (*state)[2] + c;
+ (*state)[3] = 0UL + (*state)[3] + d;
+}
+
+/* Full message hasher */
+
+void md5_hash(const uint8_t* message, size_t len, md5_state* hash) {
+ *hash = md5_init;
+
+ size_t i;
+ for (i = 0; len - i >= 64; i += 64)
+ md5_compress(hash, &message[i]);
+
+ uint8_t block[64];
+ size_t rem = len - i;
+ memcpy(block, &message[i], rem);
+
+ block[rem] = 0x80;
+ rem++;
+ if (64 - rem >= 8)
+ memset(&block[rem], 0, 56 - rem);
+ else {
+ memset(&block[rem], 0, 64 - rem);
+ md5_compress(hash, block);
+ memset(block, 0, 56);
+ }
+
+ block[64 - 8] = static_cast<uint8_t>((len & 0x1FU) << 3);
+ len >>= 5;
+ for (i = 1; i < 8; i++) {
+ block[64 - 8 + i] = static_cast<uint8_t>(len);
+ len >>= 8;
+ }
+ md5_compress(hash, block);
+}
+
+std::string hash_to_string(const md5_state& hash) {
+ char res[2 * sizeof(hash) + 1];
+ auto* h = reinterpret_cast<const uint8_t*>(&hash[0]);
+ for (int i = 0; i < static_cast<int>(sizeof(hash)); ++i)
+ snprintf(res + 2 * i, 3, "%02x", h[i]);
+ res[32] = 0;
+ return res;
+}
+
+std::string md5_hash(const uint8_t* message, size_t len) {
+ md5_state hash;
+ md5_hash(message, len, &hash);
+ return hash_to_string(hash);
+}
+
+} // namespace md5
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/utilities/rstest/md5.h b/src/external/rawspeed/src/utilities/rstest/md5.h
new file mode 100644
index 000000000..0b76895d2
--- /dev/null
+++ b/src/external/rawspeed/src/utilities/rstest/md5.h
@@ -0,0 +1,56 @@
+/*
+ * MD5 hash in C and x86 assembly
+ *
+ * Copyright (c) 2016 Project Nayuki
+ * https://www.nayuki.io/page/fast-md5-hash-implementation-in-x86-assembly
+ *
+ * (MIT License)
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of
+ * the Software, and to permit persons to whom the Software is furnished to do
+ * so,
+ * subject to the following conditions:
+ * - The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * - The Software is provided "as is", without warranty of any kind, express or
+ * implied, including but not limited to the warranties of merchantability,
+ * fitness for a particular purpose and noninfringement. In no event shall the
+ * authors or copyright holders be liable for any claim, damages or other
+ * liability, whether in an action of contract, tort or otherwise, arising
+ * from,
+ * out of or in connection with the Software or the use or other dealings in
+ * the
+ * Software.
+ */
+
+#include <array> // for array
+#include <cstdint> // for uint8_t, uint32_t
+#include <cstdio> // for size_t
+#include <string> // for string
+
+namespace rawspeed {
+
+namespace md5 {
+
+using md5_state = std::array<uint32_t, 4>;
+
+static constexpr const md5_state md5_init = {
+ {UINT32_C(0x67452301), UINT32_C(0xEFCDAB89), UINT32_C(0x98BADCFE),
+ UINT32_C(0x10325476)}};
+
+// computes hash of the buffer message with length len
+void md5_hash(const uint8_t* message, size_t len, md5_state* hash);
+
+// returns hash as string
+std::string hash_to_string(const md5_state& hash);
+
+// computes hash of the buffer message with length len and returns it as string
+std::string md5_hash(const uint8_t* message, size_t len);
+
+} // namespace md5
+
+} // namespace rawspeed
diff --git a/src/external/rawspeed/src/utilities/rstest/rstest.cpp b/src/external/rawspeed/src/utilities/rstest/rstest.cpp
new file mode 100644
index 000000000..6ddc0e801
--- /dev/null
+++ b/src/external/rawspeed/src/utilities/rstest/rstest.cpp
@@ -0,0 +1,568 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Axel Waggershauser
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "RawSpeed-API.h"
+
+#include "md5.h" // for md5_hash
+#include <cassert> // for assert
+#include <chrono> // for milliseconds, steady_clock, duration, dur...
+#include <cstdarg> // for va_end, va_list, va_start
+#include <cstdint> // for uint8_t
+#include <cstdio> // for snprintf, size_t, fclose, fopen, fprintf
+#include <cstdlib> // for system
+#include <fstream> // IWYU pragma: keep
+#include <iostream> // for cout, cerr, left, internal
+#include <map> // for map
+#include <memory> // for unique_ptr, allocator
+#include <sstream> // IWYU pragma: keep
+#include <string> // for string, char_traits, operator+, operator<<
+#include <type_traits> // for enable_if<>::type
+#include <utility> // for pair
+#include <vector> // for vector
+
+// IWYU pragma: no_include <ext/alloc_traits.h>
+
+#if !defined(__has_feature) || !__has_feature(thread_sanitizer)
+#include <iomanip> // for operator<<, setw
+#endif
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+// define this function, it is only declared in rawspeed:
+#ifdef _OPENMP
+extern "C" int rawspeed_get_number_of_processor_cores() {
+ return omp_get_num_procs();
+}
+#else
+extern "C" int __attribute__((const)) rawspeed_get_number_of_processor_cores() {
+ return 1;
+}
+#endif
+
+using std::chrono::steady_clock;
+using std::string;
+using std::ostringstream;
+using std::vector;
+using std::ifstream;
+using std::istreambuf_iterator;
+using std::ofstream;
+using std::cout;
+using std::endl;
+using std::map;
+using std::cerr;
+using rawspeed::CameraMetaData;
+using rawspeed::FileReader;
+using rawspeed::RawParser;
+using rawspeed::RawImage;
+using rawspeed::uchar8;
+using rawspeed::uint32;
+using rawspeed::iPoint2D;
+using rawspeed::TYPE_USHORT16;
+using rawspeed::TYPE_FLOAT32;
+using rawspeed::getU16BE;
+using rawspeed::getU32LE;
+using rawspeed::isAligned;
+using rawspeed::roundUp;
+using rawspeed::RawspeedException;
+
+#if !defined(__has_feature) || !__has_feature(thread_sanitizer)
+using std::setw;
+using std::left;
+using std::internal;
+#endif
+
+namespace rawspeed {
+
+namespace rstest {
+
+std::string img_hash(const rawspeed::RawImage& r);
+
+void writePPM(const rawspeed::RawImage& raw, const std::string& fn);
+void writePFM(const rawspeed::RawImage& raw, const std::string& fn);
+
+md5::md5_state imgDataHash(const rawspeed::RawImage& raw);
+
+void writeImage(const rawspeed::RawImage& raw, const std::string& fn);
+
+struct options {
+ bool create;
+ bool force;
+ bool dump;
+};
+
+size_t process(const std::string& filename,
+ const rawspeed::CameraMetaData* metadata, const options& o);
+
+class RstestHashMismatch final : public rawspeed::RawspeedException {
+public:
+ size_t time;
+
+ explicit RstestHashMismatch(const std::string& msg, size_t time_)
+ : RawspeedException(msg), time(time_) {}
+ explicit RstestHashMismatch(const char* msg, size_t time_)
+ : RawspeedException(msg), time(time_) {}
+};
+
+struct Timer {
+ mutable std::chrono::steady_clock::time_point start =
+ std::chrono::steady_clock::now();
+ size_t operator()() const {
+ auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
+ std::chrono::steady_clock::now() - start)
+ .count();
+ start = std::chrono::steady_clock::now();
+ return ms;
+ }
+};
+
+// yes, this is not cool. but i see no way to compute the hash of the
+// full image, without duplicating image, and copying excluding padding
+md5::md5_state imgDataHash(const RawImage& raw) {
+ md5::md5_state ret = md5::md5_init;
+
+ const iPoint2D dimUncropped = raw->getUncroppedDim();
+
+ vector<md5::md5_state> line_hashes;
+ line_hashes.resize(dimUncropped.y, md5::md5_init);
+
+ for (int j = 0; j < dimUncropped.y; j++) {
+ auto* d = raw->getDataUncropped(0, j);
+ md5::md5_hash(d, raw->pitch - raw->padding, &line_hashes[j]);
+ }
+
+ md5::md5_hash(reinterpret_cast<const uint8_t*>(&line_hashes[0]),
+ sizeof(line_hashes[0]) * line_hashes.size(), &ret);
+
+ return ret;
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Wunknown-warning-option"
+#pragma GCC diagnostic ignored "-Wunknown-pragmas"
+#pragma GCC diagnostic ignored "-Wframe-larger-than="
+#pragma GCC diagnostic ignored "-Wstack-usage="
+
+static void __attribute__((format(printf, 2, 3)))
+APPEND(ostringstream* oss, const char* format, ...) {
+ char line[1024];
+
+ va_list args;
+ va_start(args, format);
+ vsnprintf(line, sizeof(line), format, args);
+ va_end(args);
+
+ *oss << line;
+}
+
+string img_hash(const RawImage& r) {
+ ostringstream oss;
+
+ APPEND(&oss, "make: %s\n", r->metadata.make.c_str());
+ APPEND(&oss, "model: %s\n", r->metadata.model.c_str());
+ APPEND(&oss, "mode: %s\n", r->metadata.mode.c_str());
+
+ APPEND(&oss, "canonical_make: %s\n", r->metadata.canonical_make.c_str());
+ APPEND(&oss, "canonical_model: %s\n", r->metadata.canonical_model.c_str());
+ APPEND(&oss, "canonical_alias: %s\n", r->metadata.canonical_alias.c_str());
+ APPEND(&oss, "canonical_id: %s\n", r->metadata.canonical_id.c_str());
+
+ APPEND(&oss, "isoSpeed: %d\n", r->metadata.isoSpeed);
+ APPEND(&oss, "blackLevel: %d\n", r->blackLevel);
+ APPEND(&oss, "whitePoint: %d\n", r->whitePoint);
+
+ APPEND(&oss, "blackLevelSeparate: %d %d %d %d\n", r->blackLevelSeparate[0],
+ r->blackLevelSeparate[1], r->blackLevelSeparate[2],
+ r->blackLevelSeparate[3]);
+
+ APPEND(&oss, "wbCoeffs: %f %f %f %f\n", r->metadata.wbCoeffs[0],
+ r->metadata.wbCoeffs[1], r->metadata.wbCoeffs[2],
+ r->metadata.wbCoeffs[3]);
+
+ APPEND(&oss, "isCFA: %d\n", r->isCFA);
+ APPEND(&oss, "cfa: %s\n", r->cfa.asString().c_str());
+ APPEND(&oss, "filters: 0x%x\n", r->cfa.getDcrawFilter());
+ APPEND(&oss, "bpp: %d\n", r->getBpp());
+ APPEND(&oss, "cpp: %d\n", r->getCpp());
+ APPEND(&oss, "dataType: %d\n", r->getDataType());
+
+ const iPoint2D dimUncropped = r->getUncroppedDim();
+ APPEND(&oss, "dimUncropped: %dx%d\n", dimUncropped.x, dimUncropped.y);
+ APPEND(&oss, "dimCropped: %dx%d\n", r->dim.x, r->dim.y);
+ const iPoint2D cropTL = r->getCropOffset();
+ APPEND(&oss, "cropOffset: %dx%d\n", cropTL.x, cropTL.y);
+
+ // NOTE: pitch is internal property, a function of dimUncropped.x, bpp and
+ // some additional padding overhead, to align each line lenght to be a
+ // multiple of (currently) 16 bytes. And maybe with some additional
+ // const offset. there is no point in showing it here, it may differ.
+ // APPEND(&oss, "pitch: %d\n", r->pitch);
+
+ APPEND(&oss, "blackAreas: ");
+ for (auto ba : r->blackAreas)
+ APPEND(&oss, "%d:%dx%d, ", ba.isVertical, ba.offset, ba.size);
+ APPEND(&oss, "\n");
+
+ APPEND(&oss, "fuji_rotation_pos: %d\n", r->metadata.fujiRotationPos);
+ APPEND(&oss, "pixel_aspect_ratio: %f\n", r->metadata.pixelAspectRatio);
+
+ APPEND(&oss, "badPixelPositions: ");
+ {
+ MutexLocker guard(&r->mBadPixelMutex);
+ for (uint32 p : r->mBadPixelPositions)
+ APPEND(&oss, "%d, ", p);
+ }
+
+ APPEND(&oss, "\n");
+
+ rawspeed::md5::md5_state hash_of_line_hashes = imgDataHash(r);
+ APPEND(&oss, "md5sum of per-line md5sums: %s\n",
+ rawspeed::md5::hash_to_string(hash_of_line_hashes).c_str());
+
+ const auto errors = r->getErrors();
+ for (const string& e : errors)
+ APPEND(&oss, "WARNING: [rawspeed] %s\n", e.c_str());
+
+#undef APPEND
+
+ return oss.str();
+}
+
+using file_ptr = std::unique_ptr<FILE, decltype(&fclose)>;
+
+void writePPM(const RawImage& raw, const string& fn) {
+ file_ptr f(fopen((fn + ".ppm").c_str(), "wb"), &fclose);
+
+ const iPoint2D dimUncropped = raw->getUncroppedDim();
+ int width = dimUncropped.x;
+ int height = dimUncropped.y;
+ string format = raw->getCpp() == 1 ? "P5" : "P6";
+
+ // Write PPM header
+ fprintf(f.get(), "%s\n%d %d\n65535\n", format.c_str(), width, height);
+
+ width *= raw->getCpp();
+
+ // Write pixels
+ for (int y = 0; y < height; ++y) {
+ auto* row = reinterpret_cast<unsigned short*>(raw->getDataUncropped(0, y));
+ // PPM is big-endian
+ for (int x = 0; x < width; ++x)
+ row[x] = getU16BE(row + x);
+
+ fwrite(row, sizeof(*row), width, f.get());
+ }
+}
+
+void writePFM(const RawImage& raw, const string& fn) {
+ file_ptr f(fopen((fn + ".pfm").c_str(), "wb"), &fclose);
+
+ const iPoint2D dimUncropped = raw->getUncroppedDim();
+ int width = dimUncropped.x;
+ int height = dimUncropped.y;
+ string format = raw->getCpp() == 1 ? "Pf" : "PF";
+
+ // Write PFM header. if scale < 0, it is little-endian, if >= 0 - big-endian
+ int len = fprintf(f.get(), "%s\n%d %d\n-1.0", format.c_str(), width, height);
+
+ // make sure that data starts at aligned offset. for sse
+ static const auto dataAlignment = 16;
+
+ // regardless of padding, we need to write \n separator
+ const int realLen = len + 1;
+ // the first byte after that \n will be aligned
+ const int paddedLen = roundUp(realLen, dataAlignment);
+ assert(paddedLen > len);
+ assert(isAligned(paddedLen, dataAlignment));
+
+ // how much padding?
+ const int padding = paddedLen - realLen;
+ assert(padding >= 0);
+ assert(isAligned(realLen + padding, dataAlignment));
+
+ // and actually write padding + new line
+ len += fprintf(f.get(), "%0*i\n", padding, 0);
+ assert(paddedLen == len);
+
+ // did we write a multiple of an alignment value?
+ assert(isAligned(len, dataAlignment));
+ assert(ftell(f.get()) == len);
+ assert(isAligned(ftell(f.get()), dataAlignment));
+
+ width *= raw->getCpp();
+
+ // Write pixels
+ for (int y = 0; y < height; ++y) {
+ // NOTE: pfm has rows in reverse order
+ const int row_in = height - 1 - y;
+ auto* row = reinterpret_cast<float*>(raw->getDataUncropped(0, row_in));
+
+ // PFM can have any endiannes, let's write little-endian
+ for (int x = 0; x < width; ++x)
+ row[x] = getU32LE(row + x);
+
+ fwrite(row, sizeof(*row), width, f.get());
+ }
+}
+
+void writeImage(const RawImage& raw, const string& fn) {
+ switch (raw->getDataType()) {
+ case TYPE_USHORT16:
+ writePPM(raw, fn);
+ break;
+ case TYPE_FLOAT32:
+ writePFM(raw, fn);
+ break;
+ default:
+ __builtin_unreachable();
+ }
+}
+
+size_t process(const string& filename, const CameraMetaData* metadata,
+ const options& o) {
+
+ const string hashfile(filename + ".hash");
+
+ // if creating hash and hash exists -> skip current file
+ // if not creating and hash is missing -> skip as well
+ // unless in force mode
+ ifstream hf(hashfile);
+ if (hf.good() == o.create && !o.force) {
+#if !defined(__has_feature) || !__has_feature(thread_sanitizer)
+#ifdef _OPENMP
+#pragma omp critical(io)
+#endif
+ cout << left << setw(55) << filename << ": hash "
+ << (o.create ? "exists" : "missing") << ", skipping" << endl;
+#endif
+ return 0;
+ }
+
+// to narrow down the list of files that could have causes the crash
+#if !defined(__has_feature) || !__has_feature(thread_sanitizer)
+#ifdef _OPENMP
+#pragma omp critical(io)
+#endif
+ cout << left << setw(55) << filename << ": starting decoding ... " << endl;
+#endif
+
+ FileReader reader(filename.c_str());
+
+ auto map(reader.readFile());
+ // Buffer* map = readFile( argv[1] );
+
+ Timer t;
+
+ RawParser parser(map.get());
+ auto decoder(parser.getDecoder(metadata));
+ // RawDecoder* decoder = parseRaw( map );
+
+ decoder->failOnUnknown = false;
+ decoder->checkSupport(metadata);
+
+ decoder->decodeRaw();
+ decoder->decodeMetaData(metadata);
+ RawImage raw = decoder->mRaw;
+ // RawImage raw = decoder->decode();
+
+ auto time = t();
+#if !defined(__has_feature) || !__has_feature(thread_sanitizer)
+#ifdef _OPENMP
+#pragma omp critical(io)
+#endif
+ cout << left << setw(55) << filename << ": " << internal << setw(3)
+ << map->getSize() / 1000000 << " MB / " << setw(4) << time << " ms"
+ << endl;
+#endif
+
+ if (o.create) {
+ // write the hash. if force is set, then we are potentially overwriting here
+ ofstream f(hashfile);
+ f << img_hash(raw);
+ if (o.dump)
+ writeImage(raw, filename);
+ } else {
+ // do generate the hash string regardless.
+ string h = img_hash(raw);
+
+ // normally, here we would compare the old hash with the new one
+ // but if the force is set, and the hash does not exist, do nothing.
+ if (!hf.good() && o.force)
+ return time;
+
+ string truth((istreambuf_iterator<char>(hf)), istreambuf_iterator<char>());
+ if (h != truth) {
+ ofstream f(filename + ".hash.failed");
+ f << h;
+ if (o.dump)
+ writeImage(raw, filename + ".failed");
+ throw RstestHashMismatch("hash/metadata mismatch", time);
+ }
+ }
+
+ return time;
+}
+
+#pragma GCC diagnostic pop
+
+static int results(const map<string, string>& failedTests, const options& o) {
+ if (failedTests.empty()) {
+ cout << "All good, ";
+ if (!o.create)
+ cout << "no tests failed!" << endl;
+ else
+ cout << "all hashes created!" << endl;
+ return 0;
+ }
+
+ cerr << "WARNING: the following " << failedTests.size()
+ << " tests have failed:\n";
+
+ bool rstestlog = false;
+ for (const auto& i : failedTests) {
+ cerr << i.second << "\n";
+#ifndef WIN32
+ const string oldhash(i.first + ".hash");
+ const string newhash(oldhash + ".failed");
+
+ ifstream oldfile(oldhash);
+ ifstream newfile(newhash);
+
+ // if neither hashes exist, nothing to append...
+ if (!(oldfile.good() || newfile.good()))
+ continue;
+
+ rstestlog = true;
+
+ // DIFF(1): -N, --new-file treat absent files as empty
+ string cmd(R"(diff -N -u0 ")");
+ cmd += oldhash;
+ cmd += R"(" ")";
+ cmd += newhash;
+ cmd += R"(" >> rstest.log)";
+ if (system(cmd.c_str())) {
+ }
+ }
+#endif
+
+ if (rstestlog)
+ cerr << "See rstest.log for details.\n";
+
+ return 1;
+}
+
+static int usage(const char* progname) {
+ cout << "usage: " << progname << R"(
+ [-h] print this help
+ [-c] for each file: decode, compute hash and store it.
+ If hash exists, it does not recompute it, unless option -f is set!
+ [-f] if -c is set, then it will override the existing hashes.
+ If -c is not set, and the hash does not exist, then just decode,
+ but do not write the hash!
+ [-d] store decoded image as PPM
+ <FILE[S]> the file[s] to work on.
+
+ With no options given, each raw with an accompanying hash will be decoded
+ and compared (unless option -f is set!) to the existing hash. A summary of
+ all errors/failed hash comparisons will be reported at the end.
+
+ Suggested workflow for easy regression testing:
+ 1. remove all .hash files and build 'trusted' version of this program
+ 2. run with option '-c' -> creates .hash for all supported files
+ 3. build new version to test for regressions
+ 4. run with no option -> checks files with existing .hash
+ If the second run shows no errors, you have no regressions,
+ otherwise, the diff between hashes is appended to rstest.log
+)";
+ return 0;
+}
+
+} // namespace rstest
+
+} // namespace rawspeed
+
+using rawspeed::rstest::usage;
+using rawspeed::rstest::options;
+using rawspeed::rstest::process;
+using rawspeed::rstest::results;
+
+int main(int argc, char **argv) {
+
+ auto hasFlag = [argc, argv](string flag) {
+ bool found = false;
+ for (int i = 1; i < argc; ++i) {
+ if (!argv[i] || argv[i] != flag)
+ continue;
+ found = true;
+ argv[i] = nullptr;
+ }
+ return found;
+ };
+
+ if (1 == argc || hasFlag("-h"))
+ return usage(argv[0]);
+
+ options o;
+ o.create = hasFlag("-c");
+ o.force = hasFlag("-f");
+ o.dump = hasFlag("-d");
+
+#ifdef HAVE_PUGIXML
+ const CameraMetaData metadata(CMAKE_SOURCE_DIR "/data/cameras.xml");
+#else
+ const CameraMetaData metadata{};
+#endif
+
+ size_t time = 0;
+ map<string, string> failedTests;
+#ifdef _OPENMP
+#pragma omp parallel for default(shared) schedule(dynamic, 1) reduction(+ : time)
+#endif
+ for (int i = 1; i < argc; ++i) {
+ if (!argv[i])
+ continue;
+
+ try {
+ try {
+ time += process(argv[i], &metadata, o);
+ } catch (rawspeed::rstest::RstestHashMismatch& e) {
+ time += e.time;
+ throw;
+ }
+ } catch (RawspeedException& e) {
+#ifdef _OPENMP
+#pragma omp critical(io)
+#endif
+ {
+ string msg = string(argv[i]) + " failed: " + e.what();
+#if !defined(__has_feature) || !__has_feature(thread_sanitizer)
+ cerr << msg << endl;
+#endif
+ failedTests.emplace(argv[i], msg);
+ }
+ }
+ }
+
+ cout << "Total decoding time: " << time / 1000.0 << "s" << endl << endl;
+
+ return results(failedTests, o);
+}
diff --git a/src/external/rawspeed/test/CMakeLists.txt b/src/external/rawspeed/test/CMakeLists.txt
new file mode 100644
index 000000000..d7b85e3e1
--- /dev/null
+++ b/src/external/rawspeed/test/CMakeLists.txt
@@ -0,0 +1,30 @@
+set (DISABLED_WARNING_FLAGS
+ "missing-prototypes"
+ "missing-variable-declarations"
+ "suggest-attribute=const"
+ "suggest-override"
+ "used-but-marked-unused"
+)
+
+foreach(warning ${DISABLED_WARNING_FLAGS})
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wno-${warning})
+endforeach()
+
+if(NOT SPECIAL_BUILD)
+ # should be < 64Kb
+ math(EXPR MAX_MEANINGFUL_SIZE 4*1024)
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wstack-usage=${MAX_MEANINGFUL_SIZE})
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wframe-larger-than=${MAX_MEANINGFUL_SIZE})
+
+ # as small as possible, but 1Mb+ is ok.
+ math(EXPR MAX_MEANINGFUL_SIZE 32*1024)
+ CHECK_CXX_COMPILER_FLAG_AND_ENABLE_IT(-Wlarger-than=${MAX_MEANINGFUL_SIZE})
+endif()
+
+set(CMAKE_CXX_CLANG_TIDY_SAVE "${CMAKE_CXX_CLANG_TIDY}")
+
+unset(CMAKE_CXX_CLANG_TIDY)
+
+add_subdirectory(librawspeed)
+
+set(CMAKE_CXX_CLANG_TIDY "${CMAKE_CXX_CLANG_TIDY_SAVE}")
diff --git a/src/external/rawspeed/test/librawspeed/CMakeLists.txt b/src/external/rawspeed/test/librawspeed/CMakeLists.txt
new file mode 100644
index 000000000..e51f669a0
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/CMakeLists.txt
@@ -0,0 +1,36 @@
+if(CMAKE_BUILD_TYPE STREQUAL "COVERAGE")
+ # want all the symbols.
+ add_library(rawspeed_test SHARED)
+else()
+ add_library(rawspeed_test STATIC)
+endif()
+
+target_link_libraries(rawspeed_test PUBLIC rawspeed)
+target_link_libraries(rawspeed_test PUBLIC gtest gmock_main)
+target_include_directories(rawspeed_test PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
+
+if(WITH_OPENMP AND OPENMP_FOUND AND TARGET OpenMP::OpenMP)
+ target_link_libraries(rawspeed_test PUBLIC OpenMP::OpenMP)
+endif()
+
+
+# FIXME: it should be PATH, but then it is escaped, and that breaks gtest
+set(UNITTEST_REPORT_PATH ${CMAKE_BINARY_DIR}/unittest-reports/ CACHE STRING "" FORCE)
+file(MAKE_DIRECTORY "${UNITTEST_REPORT_PATH}")
+
+function(add_rs_test src)
+ get_filename_component(TESTNAME ${src} NAME_WE)
+ add_executable(${TESTNAME} ${src})
+ target_link_libraries(${TESTNAME} rawspeed)
+ target_link_libraries(${TESTNAME} rawspeed_test)
+ # GTEST_ADD_TESTS(${TESTNAME} "" AUTO)
+ add_test(NAME ${TESTNAME}
+ COMMAND ${TESTNAME} --gtest_output=xml:${UNITTEST_REPORT_PATH}
+ WORKING_DIRECTORY "$<TARGET_PROPERTY:rawspeed_test,BINARY_DIR>")
+ add_dependencies(tests ${TESTNAME})
+endfunction()
+
+add_subdirectory(common)
+add_subdirectory(io)
+add_subdirectory(metadata)
+add_subdirectory(test)
diff --git a/src/external/rawspeed/test/librawspeed/common/CMakeLists.txt b/src/external/rawspeed/test/librawspeed/common/CMakeLists.txt
new file mode 100644
index 000000000..f0348252a
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/common/CMakeLists.txt
@@ -0,0 +1,14 @@
+FILE(GLOB RAWSPEED_TEST_SOURCES
+ "CommonTest.cpp"
+ "CpuidTest.cpp"
+ "MemoryTest.cpp"
+ "NORangesSetTest.cpp"
+ "PointTest.cpp"
+ "RangeTest.cpp"
+ "SplineTest.cpp"
+ "ThreadingTest.cpp"
+)
+
+foreach(IN ${RAWSPEED_TEST_SOURCES})
+ add_rs_test(${IN})
+endforeach()
diff --git a/src/external/rawspeed/test/librawspeed/common/CommonTest.cpp b/src/external/rawspeed/test/librawspeed/common/CommonTest.cpp
new file mode 100644
index 000000000..a3b46079d
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/common/CommonTest.cpp
@@ -0,0 +1,449 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; withexpected even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Common.h" // for uchar8, clampBits, isIn, isPower...
+#include <algorithm> // for fill, min, equal
+#include <cassert> // for assert
+#include <cstddef> // for size_t
+#include <gtest/gtest.h> // for make_tuple, get, IsNullLiteralHe...
+#include <limits> // for numeric_limits
+#include <memory> // for unique_ptr
+#include <string> // for basic_string, string, allocator
+#include <vector> // for vector
+// IWYU pragma: no_include <type_traits>
+
+using rawspeed::clampBits;
+using rawspeed::copyPixels;
+using rawspeed::getThreadCount;
+using rawspeed::isAligned;
+using rawspeed::isIn;
+using rawspeed::isPowerOfTwo;
+using rawspeed::roundUp;
+using rawspeed::roundUpDivision;
+using rawspeed::splitString;
+using rawspeed::trimSpaces;
+using rawspeed::uchar8;
+using rawspeed::unroll_loop;
+using rawspeed::ushort16;
+using std::make_tuple;
+using std::min;
+using std::numeric_limits;
+using std::string;
+using std::vector;
+
+namespace rawspeed_test {
+
+using powerOfTwoType = std::tr1::tuple<int, bool>;
+class PowerOfTwoTest : public ::testing::TestWithParam<powerOfTwoType> {
+protected:
+ PowerOfTwoTest() = default;
+ virtual void SetUp() {
+ in = std::tr1::get<0>(GetParam());
+ expected = std::tr1::get<1>(GetParam());
+ }
+
+ int in; // input
+ bool expected; // expected output
+};
+static const powerOfTwoType powerOfTwoValues[] = {
+ make_tuple(0, true), make_tuple(1, true), make_tuple(2, true),
+ make_tuple(3, false), make_tuple(4, true), make_tuple(5, false),
+ make_tuple(6, false), make_tuple(7, false), make_tuple(8, true),
+ make_tuple(9, false), make_tuple(10, false), make_tuple(11, false),
+
+};
+INSTANTIATE_TEST_CASE_P(PowerOfTwoTest, PowerOfTwoTest,
+ ::testing::ValuesIn(powerOfTwoValues));
+TEST_P(PowerOfTwoTest, PowerOfTwoTest) {
+ ASSERT_EQ(isPowerOfTwo(in), expected);
+}
+
+using RoundUpType = std::tr1::tuple<size_t, size_t, size_t>;
+class RoundUpTest : public ::testing::TestWithParam<RoundUpType> {
+protected:
+ RoundUpTest() = default;
+ virtual void SetUp() {
+ in = std::tr1::get<0>(GetParam());
+ multiple = std::tr1::get<1>(GetParam());
+ expected = std::tr1::get<2>(GetParam());
+ }
+
+ size_t in; // input
+ size_t multiple;
+ size_t expected; // expected output
+};
+static const RoundUpType RoundUpValues[] = {
+ make_tuple(0, 0, 0), make_tuple(0, 10, 0), make_tuple(10, 0, 10),
+ make_tuple(10, 10, 10), make_tuple(10, 1, 10), make_tuple(10, 2, 10),
+ make_tuple(10, 3, 12), make_tuple(10, 4, 12), make_tuple(10, 5, 10),
+ make_tuple(10, 6, 12), make_tuple(10, 7, 14), make_tuple(10, 8, 16),
+ make_tuple(10, 9, 18), make_tuple(10, 11, 11), make_tuple(10, 12, 12),
+
+};
+INSTANTIATE_TEST_CASE_P(RoundUpTest, RoundUpTest,
+ ::testing::ValuesIn(RoundUpValues));
+TEST_P(RoundUpTest, RoundUpTest) { ASSERT_EQ(roundUp(in, multiple), expected); }
+
+using RoundUpDivisionType = std::tr1::tuple<size_t, size_t, size_t>;
+class RoundUpDivisionTest
+ : public ::testing::TestWithParam<RoundUpDivisionType> {
+protected:
+ RoundUpDivisionTest() = default;
+ virtual void SetUp() {
+ in = std::tr1::get<0>(GetParam());
+ divider = std::tr1::get<1>(GetParam());
+ expected = std::tr1::get<2>(GetParam());
+ }
+
+ size_t in; // input
+ size_t divider;
+ size_t expected; // expected output
+};
+static const RoundUpDivisionType RoundUpDivisionValues[] = {
+ make_tuple(0, 10, 0),
+ make_tuple(10, 10, 1),
+ make_tuple(10, 1, 10),
+ make_tuple(10, 2, 5),
+ make_tuple(10, 3, 4),
+ make_tuple(10, 4, 3),
+ make_tuple(10, 5, 2),
+ make_tuple(10, 6, 2),
+ make_tuple(10, 7, 2),
+ make_tuple(10, 8, 2),
+ make_tuple(10, 9, 2),
+ make_tuple(0, 1, 0),
+ make_tuple(1, 1, 1),
+ make_tuple(numeric_limits<size_t>::max() - 1, 1,
+ numeric_limits<size_t>::max() - 1),
+ make_tuple(numeric_limits<size_t>::max(), 1, numeric_limits<size_t>::max()),
+ make_tuple(0, numeric_limits<size_t>::max() - 1, 0),
+ make_tuple(1, numeric_limits<size_t>::max() - 1, 1),
+ make_tuple(numeric_limits<size_t>::max() - 1,
+ numeric_limits<size_t>::max() - 1, 1),
+ make_tuple(numeric_limits<size_t>::max(), numeric_limits<size_t>::max() - 1,
+ 2),
+ make_tuple(0, numeric_limits<size_t>::max(), 0),
+ make_tuple(1, numeric_limits<size_t>::max(), 1),
+ make_tuple(numeric_limits<size_t>::max() - 1, numeric_limits<size_t>::max(),
+ 1),
+ make_tuple(numeric_limits<size_t>::max(), numeric_limits<size_t>::max(), 1),
+
+};
+INSTANTIATE_TEST_CASE_P(RoundUpDivisionTest, RoundUpDivisionTest,
+ ::testing::ValuesIn(RoundUpDivisionValues));
+TEST_P(RoundUpDivisionTest, RoundUpDivisionTest) {
+ ASSERT_EQ(roundUpDivision(in, divider), expected);
+}
+
+using IsAlignedType = std::tr1::tuple<int, int>;
+class IsAlignedTest : public ::testing::TestWithParam<IsAlignedType> {
+protected:
+ IsAlignedTest() = default;
+ virtual void SetUp() {
+ value = std::tr1::get<0>(GetParam());
+ multiple = std::tr1::get<1>(GetParam());
+ }
+
+ int value;
+ int multiple;
+};
+INSTANTIATE_TEST_CASE_P(IsAlignedTest, IsAlignedTest,
+ ::testing::Combine(::testing::Range(0, 32),
+ ::testing::Range(0, 32)));
+TEST_P(IsAlignedTest, IsAlignedAfterRoundUpTest) {
+ ASSERT_TRUE(isAligned(roundUp(value, multiple), multiple));
+}
+
+using IsInType = std::tr1::tuple<string, bool>;
+class IsInTest : public ::testing::TestWithParam<IsInType> {
+protected:
+ IsInTest() = default;
+ virtual void SetUp() {
+ in = std::tr1::get<0>(GetParam());
+ expected = std::tr1::get<1>(GetParam());
+ }
+
+ string in; // input
+ bool expected; // expected output
+};
+
+static const IsInType IsInValues[] = {
+ make_tuple("foo", true), make_tuple("foo2", true),
+ make_tuple("bar", true), make_tuple("baz", true),
+ make_tuple("foo1", false), make_tuple("bar2", false),
+ make_tuple("baz-1", false), make_tuple("quz", false),
+
+};
+INSTANTIATE_TEST_CASE_P(IsInTest, IsInTest, ::testing::ValuesIn(IsInValues));
+TEST_P(IsInTest, IsInTest) {
+ ASSERT_EQ(isIn(in, {"foo", "foo2", "bar", "baz"}), expected);
+}
+
+using ClampBitsType = std::tr1::tuple<int, int, ushort16>;
+class ClampBitsTest : public ::testing::TestWithParam<ClampBitsType> {
+protected:
+ ClampBitsTest() = default;
+ virtual void SetUp() {
+ in = std::tr1::get<0>(GetParam());
+ n = std::tr1::get<1>(GetParam());
+ expected = std::tr1::get<2>(GetParam());
+ }
+
+ int in; // input
+ int n;
+ ushort16 expected; // expected output
+};
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define ROW(v, p, pv) make_tuple((v), (p), MIN(pv, MAX(v, 0))),
+
+#define ROWS(v, p, pv) ROW(-v, p, 0) ROW(v, p, pv)
+
+#define THREEROWS(v, p) \
+ ROWS(((1 << (v)) - 1), (p), ((1 << (p)) - 1)) \
+ ROWS(((1 << (v)) - 0), (p), ((1 << (p)) - 1)) \
+ ROWS(((1 << (v)) + 1), (p), ((1 << (p)) - 1))
+
+#define MOREROWS(v) \
+ THREEROWS(v, 0) \
+ THREEROWS(v, 1) \
+ THREEROWS(v, 2) \
+ THREEROWS(v, 4) \
+ THREEROWS(v, 8) THREEROWS(v, 16)
+
+#define GENERATE() \
+ MOREROWS(0) \
+ MOREROWS(1) \
+ MOREROWS(2) MOREROWS(4) MOREROWS(8) MOREROWS(16) MOREROWS(24) MOREROWS(30)
+
+static const ClampBitsType ClampBitsValues[] = {
+ make_tuple(0, 0, 0), make_tuple(0, 16, 0),
+ make_tuple(32, 0, 0), make_tuple(32, 16, 32),
+ make_tuple(32, 2, 3), make_tuple(-32, 0, 0),
+ make_tuple(-32, 16, 0), GENERATE()};
+INSTANTIATE_TEST_CASE_P(ClampBitsTest, ClampBitsTest,
+ ::testing::ValuesIn(ClampBitsValues));
+TEST_P(ClampBitsTest, ClampBitsTest) { ASSERT_EQ(clampBits(in, n), expected); }
+TEST(ClampBitsDeathTest, Only16Bit) {
+#ifndef NDEBUG
+ ASSERT_DEATH({ ASSERT_EQ(clampBits(0, 17), 0); }, "n <= 16");
+#endif
+}
+
+using TrimSpacesType = std::tr1::tuple<string, string>;
+class TrimSpacesTest : public ::testing::TestWithParam<TrimSpacesType> {
+protected:
+ TrimSpacesTest() = default;
+ virtual void SetUp() {
+ in = std::tr1::get<0>(GetParam());
+ out = std::tr1::get<1>(GetParam());
+ }
+
+ string in; // input
+ string out; // expected output
+};
+
+static const TrimSpacesType TrimSpacesValues[] = {
+#define STR "fo2o 3,24 b5a#r"
+ make_tuple("foo", "foo"),
+ make_tuple(STR, STR),
+ make_tuple(" " STR, STR),
+ make_tuple("\t" STR, STR),
+ make_tuple(" \t " STR, STR),
+ make_tuple(STR " ", STR),
+ make_tuple(STR "\t", STR),
+ make_tuple(STR " \t ", STR),
+ make_tuple(" " STR " ", STR),
+ make_tuple("\t" STR "\t", STR),
+ make_tuple(" \t " STR " \t ", STR),
+ make_tuple(" ", ""),
+ make_tuple(" \t", ""),
+ make_tuple(" \t ", ""),
+ make_tuple("\t ", ""),
+#undef STR
+};
+INSTANTIATE_TEST_CASE_P(TrimSpacesTest, TrimSpacesTest,
+ ::testing::ValuesIn(TrimSpacesValues));
+TEST_P(TrimSpacesTest, TrimSpacesTest) { ASSERT_EQ(trimSpaces(in), out); }
+
+using splitStringType = std::tr1::tuple<string, char, vector<string>>;
+class SplitStringTest : public ::testing::TestWithParam<splitStringType> {
+protected:
+ SplitStringTest() = default;
+ virtual void SetUp() {
+ in = std::tr1::get<0>(GetParam());
+ sep = std::tr1::get<1>(GetParam());
+ out = std::tr1::get<2>(GetParam());
+ }
+
+ string in; // input
+ char sep; // the separator
+ vector<string> out; // expected output
+};
+static const splitStringType splitStringValues[] = {
+ make_tuple(" ini mi,ni moe ", ' ',
+ vector<string>({"ini", "mi,ni", "moe"})),
+ make_tuple(" 412, 542,732 , ", ',',
+ vector<string>({" 412", " 542", "732 ", " "})),
+
+};
+INSTANTIATE_TEST_CASE_P(SplitStringTest, SplitStringTest,
+ ::testing::ValuesIn(splitStringValues));
+TEST_P(SplitStringTest, SplitStringTest) {
+ auto split = splitString(in, sep);
+ ASSERT_EQ(split.size(), out.size());
+ ASSERT_TRUE(std::equal(split.begin(), split.end(), out.begin()));
+}
+
+TEST(UnrollLoopTest, Test) {
+ ASSERT_NO_THROW({
+ int cnt = 0;
+ unroll_loop<0>([&](int i) { cnt++; });
+ ASSERT_EQ(cnt, 0);
+ });
+
+ ASSERT_NO_THROW({
+ int cnt = 0;
+ unroll_loop<3>([&](int i) { cnt++; });
+ ASSERT_EQ(cnt, 3);
+ });
+}
+
+template <int iterations>
+static void UnrollLoopTestIsMonotonicallyPositiveTest() {
+ static_assert(iterations >= 0, "negative iteration count makes no sense.");
+
+ int invocation = 0;
+
+ std::vector<int> expected;
+ expected.reserve(iterations);
+ invocation = 0;
+ std::generate_n(std::back_inserter(expected), iterations,
+ [&invocation]() -> int { return invocation++; });
+ if (iterations > 0) {
+ ASSERT_EQ(expected.size(), iterations);
+ ASSERT_EQ(expected.front(), 0);
+ ASSERT_EQ(expected.back(), iterations - 1);
+ }
+
+ std::vector<int> data;
+ data.reserve(iterations);
+ invocation = 0;
+ unroll_loop<iterations>([&](int i) {
+ ASSERT_GE(invocation, 0);
+ ASSERT_GE(i, 0);
+ ASSERT_LT(invocation, iterations);
+ ASSERT_LT(i, iterations);
+ ASSERT_EQ(i, invocation);
+
+ data.emplace_back(i);
+ invocation++;
+ });
+
+ ASSERT_EQ(data.size(), expected.size());
+ ASSERT_EQ(data, expected);
+}
+
+TEST(UnrollLoopTest, IsMonotonicallyPositiveTest) {
+ UnrollLoopTestIsMonotonicallyPositiveTest<0>();
+ UnrollLoopTestIsMonotonicallyPositiveTest<1>();
+ UnrollLoopTestIsMonotonicallyPositiveTest<2>();
+ UnrollLoopTestIsMonotonicallyPositiveTest<3>();
+ UnrollLoopTestIsMonotonicallyPositiveTest<4>();
+}
+
+TEST(GetThreadCountTest, Test) {
+ ASSERT_NO_THROW({ ASSERT_GE(getThreadCount(), 1); });
+}
+
+TEST(MakeUniqueTest, Test) {
+ ASSERT_NO_THROW({
+ auto s = std::make_unique<int>(0);
+ ASSERT_EQ(*s, 0);
+ });
+ ASSERT_NO_THROW({
+ auto s = std::make_unique<int>(314);
+ ASSERT_EQ(*s, 314);
+ });
+}
+
+using copyPixelsType = std::tr1::tuple<int, int, int, int>;
+class CopyPixelsTest : public ::testing::TestWithParam<copyPixelsType> {
+protected:
+ CopyPixelsTest() = default;
+ virtual void SetUp() {
+ dstPitch = std::tr1::get<0>(GetParam());
+ srcPitch = std::tr1::get<1>(GetParam());
+ rowSize = min(min(std::tr1::get<2>(GetParam()), srcPitch), dstPitch);
+ height = std::tr1::get<3>(GetParam());
+
+ assert(srcPitch * height < numeric_limits<uchar8>::max());
+ assert(dstPitch * height < numeric_limits<uchar8>::max());
+
+ src.resize((size_t)srcPitch * height);
+ dst.resize((size_t)dstPitch * height);
+
+ fill(src.begin(), src.end(), 0);
+ fill(dst.begin(), dst.end(), -1);
+ }
+ void generate() {
+ uchar8 v = 0;
+
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < rowSize; x++, v++) {
+ src[y * srcPitch + x] = v;
+ }
+ }
+ }
+ void copy() {
+ if (src.empty() || dst.empty())
+ return;
+
+ copyPixels(&(dst[0]), dstPitch, &(src[0]), srcPitch, rowSize, height);
+ }
+ void compare() {
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < rowSize; x++) {
+ ASSERT_EQ(dst[y * dstPitch + x], src[y * srcPitch + x]);
+ }
+ }
+ }
+
+ vector<uchar8> src;
+ vector<uchar8> dst;
+ int dstPitch;
+ int srcPitch;
+ int rowSize;
+ int height;
+};
+INSTANTIATE_TEST_CASE_P(CopyPixelsTest, CopyPixelsTest,
+ testing::Combine(testing::Range(0, 4, 1),
+ testing::Range(0, 4, 1),
+ testing::Range(0, 4, 1),
+ testing::Range(0, 4, 1)));
+TEST_P(CopyPixelsTest, CopyPixelsTest) {
+ generate();
+ copy();
+ compare();
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/common/CpuidTest.cpp b/src/external/rawspeed/test/librawspeed/common/CpuidTest.cpp
new file mode 100644
index 000000000..425fb5ebc
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/common/CpuidTest.cpp
@@ -0,0 +1,49 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; withexpected even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h" // IWYU pragma: keep
+#include "common/Cpuid.h" // for Cpuid
+#include <cstdlib> // for exit
+#include <gtest/gtest.h> // for AssertionResult, DeathTest, Test, AssertHe...
+
+using rawspeed::Cpuid;
+
+namespace rawspeed_test {
+
+// do not care about WITH_SSE2 here.
+TEST(CpuidDeathTest, SSE2Test) {
+#if defined(__SSE2__)
+ ASSERT_EXIT(
+ {
+ ASSERT_TRUE(Cpuid::SSE2());
+ exit(0);
+ },
+ ::testing::ExitedWithCode(0), "");
+#else
+ ASSERT_EXIT(
+ {
+ ASSERT_FALSE(Cpuid::SSE2());
+ exit(0);
+ },
+ ::testing::ExitedWithCode(0), "");
+#endif
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/common/MemoryTest.cpp b/src/external/rawspeed/test/librawspeed/common/MemoryTest.cpp
new file mode 100644
index 000000000..868292ce0
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/common/MemoryTest.cpp
@@ -0,0 +1,276 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; withexpected even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Memory.h" // for alignedMallocArray, alignedFree, alignedM...
+#include "common/Common.h" // for uchar8, int64, int32, short16, uint32
+#include <cstddef> // for size_t
+#include <cstdint> // for SIZE_MAX, uintptr_t
+#include <cstdlib> // for exit
+#include <gtest/gtest.h> // for Message, TestPartResult, TestPartResult::...
+#include <memory> // for unique_ptr
+
+using rawspeed::alignedFree;
+using rawspeed::alignedFreeConstPtr;
+using rawspeed::alignedMalloc;
+using rawspeed::alignedMallocArray;
+using rawspeed::char8;
+using rawspeed::int32;
+using rawspeed::int64;
+using rawspeed::short16;
+using rawspeed::uchar8;
+using rawspeed::uint32;
+using rawspeed::uint64;
+using rawspeed::ushort16;
+using std::unique_ptr;
+
+namespace rawspeed_test {
+
+static constexpr const size_t alloc_alignment = 16;
+
+template <typename T> class AlignedMallocTest : public testing::Test {
+public:
+ static constexpr const size_t alloc_cnt = 16;
+ static constexpr const size_t alloc_sizeof = sizeof(T);
+ static constexpr const size_t alloc_size = alloc_cnt * alloc_sizeof;
+
+ inline void TheTest(T* ptr) {
+ ASSERT_TRUE(((uintptr_t)ptr % alloc_alignment) == 0);
+ ptr[0] = 0;
+ ptr[1] = 8;
+ ptr[2] = 16;
+ ptr[3] = 24;
+ ptr[4] = 32;
+ ptr[5] = 40;
+ ptr[6] = 48;
+ ptr[7] = 56;
+ ptr[8] = 64;
+ ptr[9] = 72;
+ ptr[10] = 80;
+ ptr[11] = 88;
+ ptr[12] = 96;
+ ptr[13] = 104;
+ ptr[14] = 112;
+ ptr[15] = 120;
+
+ ASSERT_EQ((int64)ptr[0] + ptr[1] + ptr[2] + ptr[3] + ptr[4] + ptr[5] +
+ ptr[6] + ptr[7] + ptr[8] + ptr[9] + ptr[10] + ptr[11] +
+ ptr[12] + ptr[13] + ptr[14] + ptr[15],
+ 960UL);
+ }
+};
+
+template <typename T>
+class AlignedMallocDeathTest : public AlignedMallocTest<T> {};
+
+using Classes =
+ testing::Types<int, unsigned int, char8, uchar8, short16, ushort16, int32,
+ uint32, int64, uint64, float, double>;
+
+TYPED_TEST_CASE(AlignedMallocTest, Classes);
+
+TYPED_TEST_CASE(AlignedMallocDeathTest, Classes);
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+TYPED_TEST(AlignedMallocTest, BasicTest) {
+ ASSERT_NO_THROW({
+ TypeParam* ptr =
+ (TypeParam*)alignedMalloc(this->alloc_size, alloc_alignment);
+ this->TheTest(ptr);
+ alignedFree(ptr);
+ });
+ ASSERT_NO_THROW({
+ const TypeParam* forFree = nullptr;
+ {
+ TypeParam* ptr =
+ (TypeParam*)alignedMalloc(this->alloc_size, alloc_alignment);
+ this->TheTest(ptr);
+ forFree = const_cast<const TypeParam*>(ptr);
+ ptr = nullptr;
+ }
+ alignedFreeConstPtr(forFree);
+ });
+}
+
+TYPED_TEST(AlignedMallocTest, UniquePtrTest) {
+ unique_ptr<TypeParam[], decltype(&alignedFree)> ptr(
+ (TypeParam*)alignedMalloc(this->alloc_size, alloc_alignment),
+ alignedFree);
+ this->TheTest(&(ptr[0]));
+}
+
+TYPED_TEST(AlignedMallocDeathTest, AlignedMallocAssertions) {
+#ifndef NDEBUG
+ ASSERT_DEATH(
+ {
+ TypeParam* ptr = (TypeParam*)alignedMalloc(this->alloc_size, 3);
+ this->TheTest(ptr);
+ alignedFree(ptr);
+ },
+ "isPowerOfTwo");
+ ASSERT_DEATH(
+ {
+ TypeParam* ptr =
+ (TypeParam*)alignedMalloc(this->alloc_size, sizeof(void*) / 2);
+ this->TheTest(ptr);
+ alignedFree(ptr);
+ },
+ "isAligned\\(alignment\\, sizeof\\(void\\*\\)\\)");
+ ASSERT_DEATH(
+ {
+ TypeParam* ptr =
+ (TypeParam*)alignedMalloc(1 + alloc_alignment, alloc_alignment);
+ this->TheTest(ptr);
+ alignedFree(ptr);
+ },
+ "isAligned\\(size\\, alignment\\)");
+#endif
+}
+
+#pragma GCC diagnostic pop
+
+TEST(AlignedMallocDeathTest, AlignedFreeHandlesNullptr) {
+ ASSERT_EXIT(
+ {
+ alignedFree(nullptr);
+ exit(0);
+ },
+ ::testing::ExitedWithCode(0), "");
+ ASSERT_EXIT(
+ {
+ alignedFreeConstPtr(nullptr);
+ exit(0);
+ },
+ ::testing::ExitedWithCode(0), "");
+}
+
+TYPED_TEST(AlignedMallocTest, TemplateTest) {
+ ASSERT_NO_THROW({
+ TypeParam* ptr =
+ (alignedMalloc<TypeParam, alloc_alignment>(this->alloc_size));
+ this->TheTest(ptr);
+ alignedFree(ptr);
+ });
+}
+
+TYPED_TEST(AlignedMallocTest, TemplatUniquePtrTest) {
+ unique_ptr<TypeParam[], decltype(&alignedFree)> ptr(
+ alignedMalloc<TypeParam, alloc_alignment>(this->alloc_size), alignedFree);
+ this->TheTest(&(ptr[0]));
+}
+
+TYPED_TEST(AlignedMallocTest, TemplateArrayTest) {
+ ASSERT_NO_THROW({
+ TypeParam* ptr = (alignedMallocArray<TypeParam, alloc_alignment>(
+ this->alloc_cnt, this->alloc_sizeof));
+ this->TheTest(ptr);
+ alignedFree(ptr);
+ });
+}
+
+TYPED_TEST(AlignedMallocTest, TemplateArrayHandlesOverflowTest) {
+ if (this->alloc_sizeof == 1)
+ return;
+ ASSERT_NO_THROW({
+ static const size_t nmemb = 1 + (SIZE_MAX / this->alloc_sizeof);
+ TypeParam* ptr = (alignedMallocArray<TypeParam, alloc_alignment>(
+ nmemb, this->alloc_sizeof));
+ ASSERT_EQ(ptr, nullptr);
+ });
+}
+
+TYPED_TEST(AlignedMallocTest, TemplateUniquePtrArrayTest) {
+ unique_ptr<TypeParam[], decltype(&alignedFree)> ptr(
+ alignedMallocArray<TypeParam, alloc_alignment>(this->alloc_cnt,
+ this->alloc_sizeof),
+ alignedFree);
+ this->TheTest(&(ptr[0]));
+}
+
+TYPED_TEST(AlignedMallocDeathTest, TemplateArrayAssertions) {
+#ifndef NDEBUG
+ // unlike TemplateArrayRoundUp, should fail
+ ASSERT_DEATH(
+ {
+ TypeParam* ptr = (alignedMallocArray<TypeParam, alloc_alignment>(
+ 1, 1 + sizeof(TypeParam)));
+ alignedFree(ptr);
+ },
+ "isAligned\\(size\\, alignment\\)");
+#endif
+}
+
+TYPED_TEST(AlignedMallocTest, TemplateArrayRoundUp) {
+ // unlike TemplateArrayAssertions, should NOT fail
+ ASSERT_NO_THROW({
+ TypeParam* ptr = (alignedMallocArray<TypeParam, alloc_alignment, true>(
+ 1, 1 + sizeof(TypeParam)));
+ alignedFree(ptr);
+ });
+}
+
+TYPED_TEST(AlignedMallocTest, TemplateArraySizeTest) {
+ ASSERT_NO_THROW({
+ TypeParam* ptr = (alignedMallocArray<TypeParam, alloc_alignment, TypeParam>(
+ this->alloc_cnt));
+ this->TheTest(ptr);
+ alignedFree(ptr);
+ });
+}
+
+TYPED_TEST(AlignedMallocTest, TemplateUniquePtrArraySizeTest) {
+ unique_ptr<TypeParam[], decltype(&alignedFree)> ptr(
+ alignedMallocArray<TypeParam, alloc_alignment, TypeParam>(
+ this->alloc_cnt),
+ alignedFree);
+ this->TheTest(&(ptr[0]));
+}
+
+TEST(AlignedMallocDeathTest, TemplateArraySizeAssertions) {
+#ifndef NDEBUG
+ // unlike TemplateArraySizeRoundUp, should fail
+ ASSERT_DEATH(
+ {
+ uchar8* ptr = (alignedMallocArray<uchar8, alloc_alignment, uchar8>(1));
+ alignedFree(ptr);
+ },
+ "isAligned\\(size\\, alignment\\)");
+#endif
+}
+
+TEST(AlignedMallocTest, TemplateArraySizeRoundUp) {
+ // unlike TemplateArraySizeAssertions, should NOT fail
+ ASSERT_NO_THROW({
+ uchar8* ptr =
+ (alignedMallocArray<uchar8, alloc_alignment, uchar8, true>(1));
+ alignedFree(ptr);
+ });
+}
+
+TYPED_TEST(AlignedMallocTest, TemplateArraySizeRoundUpTest) {
+ // unlike TemplateArraySizeAssertions, should NOT fail
+ ASSERT_NO_THROW({
+ TypeParam* ptr =
+ (alignedMallocArray<TypeParam, alloc_alignment, TypeParam, true>(1));
+ alignedFree(ptr);
+ });
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/common/NORangesSetTest.cpp b/src/external/rawspeed/test/librawspeed/common/NORangesSetTest.cpp
new file mode 100644
index 000000000..7a8c76fca
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/common/NORangesSetTest.cpp
@@ -0,0 +1,85 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; withexpected even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/NORangesSet.h" // for NORangesSet
+#include "common/Range.h" // for Range
+#include "common/RangeTest.h" // for RangeDoesntContain, RangeContains
+#include <gtest/gtest.h> // for TEST, ASSERT_EQ, ASSERT_TRUE, ASSERT_F...
+#include <utility> // for pair
+// IWYU pragma: no_forward_declare rawspeed::Range
+
+using rawspeed::NORangesSet;
+using rawspeed::Range;
+
+namespace rawspeed_test {
+
+TEST_P(TwoRangesTest, NORangesSetDataSelfTest) {
+ {
+ NORangesSet<Range<int>> s;
+
+ auto res = s.emplace(r0);
+ ASSERT_TRUE(res.second);
+
+ // can not insert same element twice
+ res = s.emplace(r0);
+ ASSERT_FALSE(res.second);
+ }
+ {
+ NORangesSet<Range<int>> s;
+
+ auto res = s.emplace(r1);
+ ASSERT_TRUE(res.second);
+
+ // can not insert same element twice
+ res = s.emplace(r1);
+ ASSERT_FALSE(res.second);
+ }
+}
+
+TEST_P(TwoRangesTest, NORangesSetDataTest) {
+ {
+ NORangesSet<Range<int>> s;
+ auto res = s.emplace(r0);
+ ASSERT_TRUE(res.second);
+
+ res = s.emplace(r1);
+ // if the ranges overlap, we should fail to insert the second range
+ if (AllOverlapped.find(GetParam()) != AllOverlapped.end()) {
+ ASSERT_FALSE(res.second);
+ } else {
+ ASSERT_TRUE(res.second);
+ }
+ }
+ {
+ NORangesSet<Range<int>> s;
+ auto res = s.emplace(r1);
+ ASSERT_TRUE(res.second);
+
+ res = s.emplace(r0);
+ // if the ranges overlap, we should fail to insert the second range
+ if (AllOverlapped.find(GetParam()) != AllOverlapped.end()) {
+ ASSERT_FALSE(res.second);
+ } else {
+ ASSERT_TRUE(res.second);
+ }
+ }
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/common/PointTest.cpp b/src/external/rawspeed/test/librawspeed/common/PointTest.cpp
new file mode 100644
index 000000000..b510a5d18
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/common/PointTest.cpp
@@ -0,0 +1,787 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; withexpected even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Point.h" // for iPoint2D
+#include <gtest/gtest.h> // for make_tuple, AssertionResult, IsNullLiteral...
+#include <limits> // for numeric_limits
+#include <ostream> // for operator<<, basic_ostream::operator<<, ost...
+#include <utility> // for make_pair, pair, move
+
+using rawspeed::iPoint2D;
+using std::make_pair;
+using std::move;
+using std::numeric_limits;
+using std::pair;
+using std::tuple;
+
+namespace rawspeed {
+
+::std::ostream& operator<<(::std::ostream& os, const iPoint2D p) {
+ return os << "(" << p.x << ", " << p.y << ")";
+}
+
+} // namespace rawspeed
+
+namespace rawspeed_test {
+
+static constexpr iPoint2D::area_type maxVal =
+ numeric_limits<iPoint2D::value_type>::max();
+static constexpr iPoint2D::area_type minVal =
+ numeric_limits<iPoint2D::value_type>::min();
+static constexpr iPoint2D::area_type absMinVal = -minVal;
+static constexpr iPoint2D::area_type maxAreaVal = maxVal * maxVal;
+static constexpr iPoint2D::area_type minAreaVal = absMinVal * absMinVal;
+static constexpr iPoint2D::area_type mixAreaVal = maxVal * absMinVal;
+
+TEST(PointTest, Constructor) {
+ int x = -10, y = 15;
+ ASSERT_NO_THROW({
+ iPoint2D a;
+ ASSERT_EQ(a.x, 0);
+ ASSERT_EQ(a.y, 0);
+ });
+ ASSERT_NO_THROW({
+ iPoint2D a(x, y);
+ ASSERT_EQ(a.x, x);
+ ASSERT_EQ(a.y, y);
+ });
+ ASSERT_NO_THROW({
+ const iPoint2D a(x, y);
+ iPoint2D b(a);
+ ASSERT_EQ(b.x, x);
+ ASSERT_EQ(b.y, y);
+ });
+ ASSERT_NO_THROW({
+ iPoint2D a(x, y);
+ iPoint2D b(a);
+ ASSERT_EQ(b.x, x);
+ ASSERT_EQ(b.y, y);
+ });
+ ASSERT_NO_THROW({
+ const iPoint2D a(x, y);
+ iPoint2D b(move(a));
+ ASSERT_EQ(b.x, x);
+ ASSERT_EQ(b.y, y);
+ });
+ ASSERT_NO_THROW({
+ iPoint2D a(x, y);
+ iPoint2D b(move(a));
+ ASSERT_EQ(b.x, x);
+ ASSERT_EQ(b.y, y);
+ });
+}
+
+TEST(PointTest, AssignmentConstructor) {
+ int x = -10, y = 15;
+ ASSERT_NO_THROW({
+ iPoint2D a(x, y);
+ iPoint2D b(666, 777);
+ b = a;
+ ASSERT_EQ(b.x, x);
+ ASSERT_EQ(b.y, y);
+ });
+ ASSERT_NO_THROW({
+ const iPoint2D a(x, y);
+ iPoint2D b(666, 777);
+ b = a;
+ ASSERT_EQ(b.x, x);
+ ASSERT_EQ(b.y, y);
+ });
+ ASSERT_NO_THROW({
+ iPoint2D a(x, y);
+ iPoint2D b(666, 777);
+ b = move(a);
+ ASSERT_EQ(b.x, x);
+ ASSERT_EQ(b.y, y);
+ });
+ ASSERT_NO_THROW({
+ const iPoint2D a(x, y);
+ iPoint2D b(666, 777);
+ b = move(a);
+ ASSERT_EQ(b.x, x);
+ ASSERT_EQ(b.y, y);
+ });
+}
+
+TEST(PointTest, EqualityOperator) {
+ ASSERT_NO_THROW({
+ const iPoint2D a(18, -12);
+ const iPoint2D b(18, -12);
+ ASSERT_EQ(a, b);
+ ASSERT_EQ(b, a);
+ });
+}
+
+TEST(PointTest, NonEqualityOperator) {
+ ASSERT_NO_THROW({
+ const iPoint2D a(777, 888);
+ const iPoint2D b(888, 777);
+ const iPoint2D c(128, 256);
+ ASSERT_NE(a, b);
+ ASSERT_NE(b, a);
+ ASSERT_NE(a, c);
+ ASSERT_NE(c, a);
+ ASSERT_NE(b, c);
+ ASSERT_NE(c, b);
+ });
+}
+
+using IntPair = pair<int, int>;
+using Six = std::tr1::tuple<IntPair, IntPair, IntPair>;
+class PointTest : public ::testing::TestWithParam<Six> {
+protected:
+ PointTest() = default;
+ virtual void SetUp() {
+ auto p = GetParam();
+
+ auto pair = std::tr1::get<0>(p);
+ a = iPoint2D(pair.first, pair.second);
+
+ pair = std::tr1::get<1>(p);
+ b = iPoint2D(pair.first, pair.second);
+
+ pair = std::tr1::get<2>(p);
+ c = iPoint2D(pair.first, pair.second);
+ }
+
+ iPoint2D a;
+ iPoint2D b;
+ iPoint2D c;
+};
+
+/*
+#!/bin/bash
+for i in -5 0 5;
+do
+ for j in -5 0 5;
+ do
+ for k in -5 0 5;
+ do
+ for q in -5 0 5;
+ do
+ echo "make_tuple(make_pair($i, $j), make_pair($k, $q),
+make_pair($(($i+$k)), $(($j+$q)))),";
+ done;
+ done;
+ done;
+done;
+*/
+static const Six valueSum[]{
+ make_tuple(make_pair(-5, -5), make_pair(-5, -5), make_pair(-10, -10)),
+ make_tuple(make_pair(-5, -5), make_pair(-5, 0), make_pair(-10, -5)),
+ make_tuple(make_pair(-5, -5), make_pair(-5, 5), make_pair(-10, 0)),
+ make_tuple(make_pair(-5, -5), make_pair(0, -5), make_pair(-5, -10)),
+ make_tuple(make_pair(-5, -5), make_pair(0, 0), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, -5), make_pair(0, 5), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, -5), make_pair(5, -5), make_pair(0, -10)),
+ make_tuple(make_pair(-5, -5), make_pair(5, 0), make_pair(0, -5)),
+ make_tuple(make_pair(-5, -5), make_pair(5, 5), make_pair(0, 0)),
+ make_tuple(make_pair(-5, 0), make_pair(-5, -5), make_pair(-10, -5)),
+ make_tuple(make_pair(-5, 0), make_pair(-5, 0), make_pair(-10, 0)),
+ make_tuple(make_pair(-5, 0), make_pair(-5, 5), make_pair(-10, 5)),
+ make_tuple(make_pair(-5, 0), make_pair(0, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, 0), make_pair(0, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, 0), make_pair(0, 5), make_pair(-5, 5)),
+ make_tuple(make_pair(-5, 0), make_pair(5, -5), make_pair(0, -5)),
+ make_tuple(make_pair(-5, 0), make_pair(5, 0), make_pair(0, 0)),
+ make_tuple(make_pair(-5, 0), make_pair(5, 5), make_pair(0, 5)),
+ make_tuple(make_pair(-5, 5), make_pair(-5, -5), make_pair(-10, 0)),
+ make_tuple(make_pair(-5, 5), make_pair(-5, 0), make_pair(-10, 5)),
+ make_tuple(make_pair(-5, 5), make_pair(-5, 5), make_pair(-10, 10)),
+ make_tuple(make_pair(-5, 5), make_pair(0, -5), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, 5), make_pair(0, 0), make_pair(-5, 5)),
+ make_tuple(make_pair(-5, 5), make_pair(0, 5), make_pair(-5, 10)),
+ make_tuple(make_pair(-5, 5), make_pair(5, -5), make_pair(0, 0)),
+ make_tuple(make_pair(-5, 5), make_pair(5, 0), make_pair(0, 5)),
+ make_tuple(make_pair(-5, 5), make_pair(5, 5), make_pair(0, 10)),
+ make_tuple(make_pair(0, -5), make_pair(-5, -5), make_pair(-5, -10)),
+ make_tuple(make_pair(0, -5), make_pair(-5, 0), make_pair(-5, -5)),
+ make_tuple(make_pair(0, -5), make_pair(-5, 5), make_pair(-5, 0)),
+ make_tuple(make_pair(0, -5), make_pair(0, -5), make_pair(0, -10)),
+ make_tuple(make_pair(0, -5), make_pair(0, 0), make_pair(0, -5)),
+ make_tuple(make_pair(0, -5), make_pair(0, 5), make_pair(0, 0)),
+ make_tuple(make_pair(0, -5), make_pair(5, -5), make_pair(5, -10)),
+ make_tuple(make_pair(0, -5), make_pair(5, 0), make_pair(5, -5)),
+ make_tuple(make_pair(0, -5), make_pair(5, 5), make_pair(5, 0)),
+ make_tuple(make_pair(0, 0), make_pair(-5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(0, 0), make_pair(-5, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(0, 0), make_pair(-5, 5), make_pair(-5, 5)),
+ make_tuple(make_pair(0, 0), make_pair(0, -5), make_pair(0, -5)),
+ make_tuple(make_pair(0, 0), make_pair(0, 0), make_pair(0, 0)),
+ make_tuple(make_pair(0, 0), make_pair(0, 5), make_pair(0, 5)),
+ make_tuple(make_pair(0, 0), make_pair(5, -5), make_pair(5, -5)),
+ make_tuple(make_pair(0, 0), make_pair(5, 0), make_pair(5, 0)),
+ make_tuple(make_pair(0, 0), make_pair(5, 5), make_pair(5, 5)),
+ make_tuple(make_pair(0, 5), make_pair(-5, -5), make_pair(-5, 0)),
+ make_tuple(make_pair(0, 5), make_pair(-5, 0), make_pair(-5, 5)),
+ make_tuple(make_pair(0, 5), make_pair(-5, 5), make_pair(-5, 10)),
+ make_tuple(make_pair(0, 5), make_pair(0, -5), make_pair(0, 0)),
+ make_tuple(make_pair(0, 5), make_pair(0, 0), make_pair(0, 5)),
+ make_tuple(make_pair(0, 5), make_pair(0, 5), make_pair(0, 10)),
+ make_tuple(make_pair(0, 5), make_pair(5, -5), make_pair(5, 0)),
+ make_tuple(make_pair(0, 5), make_pair(5, 0), make_pair(5, 5)),
+ make_tuple(make_pair(0, 5), make_pair(5, 5), make_pair(5, 10)),
+ make_tuple(make_pair(5, -5), make_pair(-5, -5), make_pair(0, -10)),
+ make_tuple(make_pair(5, -5), make_pair(-5, 0), make_pair(0, -5)),
+ make_tuple(make_pair(5, -5), make_pair(-5, 5), make_pair(0, 0)),
+ make_tuple(make_pair(5, -5), make_pair(0, -5), make_pair(5, -10)),
+ make_tuple(make_pair(5, -5), make_pair(0, 0), make_pair(5, -5)),
+ make_tuple(make_pair(5, -5), make_pair(0, 5), make_pair(5, 0)),
+ make_tuple(make_pair(5, -5), make_pair(5, -5), make_pair(10, -10)),
+ make_tuple(make_pair(5, -5), make_pair(5, 0), make_pair(10, -5)),
+ make_tuple(make_pair(5, -5), make_pair(5, 5), make_pair(10, 0)),
+ make_tuple(make_pair(5, 0), make_pair(-5, -5), make_pair(0, -5)),
+ make_tuple(make_pair(5, 0), make_pair(-5, 0), make_pair(0, 0)),
+ make_tuple(make_pair(5, 0), make_pair(-5, 5), make_pair(0, 5)),
+ make_tuple(make_pair(5, 0), make_pair(0, -5), make_pair(5, -5)),
+ make_tuple(make_pair(5, 0), make_pair(0, 0), make_pair(5, 0)),
+ make_tuple(make_pair(5, 0), make_pair(0, 5), make_pair(5, 5)),
+ make_tuple(make_pair(5, 0), make_pair(5, -5), make_pair(10, -5)),
+ make_tuple(make_pair(5, 0), make_pair(5, 0), make_pair(10, 0)),
+ make_tuple(make_pair(5, 0), make_pair(5, 5), make_pair(10, 5)),
+ make_tuple(make_pair(5, 5), make_pair(-5, -5), make_pair(0, 0)),
+ make_tuple(make_pair(5, 5), make_pair(-5, 0), make_pair(0, 5)),
+ make_tuple(make_pair(5, 5), make_pair(-5, 5), make_pair(0, 10)),
+ make_tuple(make_pair(5, 5), make_pair(0, -5), make_pair(5, 0)),
+ make_tuple(make_pair(5, 5), make_pair(0, 0), make_pair(5, 5)),
+ make_tuple(make_pair(5, 5), make_pair(0, 5), make_pair(5, 10)),
+ make_tuple(make_pair(5, 5), make_pair(5, -5), make_pair(10, 0)),
+ make_tuple(make_pair(5, 5), make_pair(5, 0), make_pair(10, 5)),
+ make_tuple(make_pair(5, 5), make_pair(5, 5), make_pair(10, 10)),
+};
+
+INSTANTIATE_TEST_CASE_P(SumTest, PointTest, ::testing::ValuesIn(valueSum));
+TEST_P(PointTest, InPlaceAddTest1) {
+ ASSERT_NO_THROW({
+ a += b;
+ ASSERT_EQ(a, c);
+ });
+}
+TEST_P(PointTest, InPlaceAddTest2) {
+ ASSERT_NO_THROW({
+ b += a;
+ ASSERT_EQ(b, c);
+ });
+}
+TEST_P(PointTest, AddTest1) {
+ ASSERT_NO_THROW({
+ iPoint2D d = a + b;
+ ASSERT_EQ(d, c);
+ });
+}
+TEST_P(PointTest, AddTest2) {
+ ASSERT_NO_THROW({
+ iPoint2D d = b + a;
+ ASSERT_EQ(d, c);
+ });
+}
+
+TEST_P(PointTest, InPlaceSubTest1) {
+ ASSERT_NO_THROW({
+ c -= a;
+ ASSERT_EQ(c, b);
+ });
+}
+TEST_P(PointTest, InPlaceSubTest2) {
+ ASSERT_NO_THROW({
+ c -= b;
+ ASSERT_EQ(c, a);
+ });
+}
+TEST_P(PointTest, SubTest1) {
+ ASSERT_NO_THROW({
+ iPoint2D d = c - a;
+ ASSERT_EQ(d, b);
+ });
+}
+TEST_P(PointTest, SubTest2) {
+ ASSERT_NO_THROW({
+ iPoint2D d = c - b;
+ ASSERT_EQ(d, a);
+ });
+}
+
+using areaType = tuple<IntPair, iPoint2D::area_type>;
+class AreaTest : public ::testing::TestWithParam<areaType> {
+protected:
+ AreaTest() = default;
+ virtual void SetUp() {
+ auto param = GetParam();
+
+ auto pair = std::tr1::get<0>(param);
+ p = iPoint2D(pair.first, pair.second);
+
+ a = std::tr1::get<1>(param);
+ }
+
+ iPoint2D p;
+ iPoint2D::area_type a;
+};
+
+/*
+#!/bin/bash
+for i in -5 0 5;
+do
+ for j in -5 0 5;
+ do
+ k=$(($i*$j))
+ if [[ $k -lt 0 ]]
+ then
+ k=$((-$k));
+ fi;
+ echo "make_tuple(make_pair($i, $j), $k),";
+ done;
+done;
+*/
+static const areaType valueArea[]{
+ make_tuple(make_pair(-5, -5), 25),
+ make_tuple(make_pair(-5, 0), 0),
+ make_tuple(make_pair(-5, 5), 25),
+ make_tuple(make_pair(0, -5), 0),
+ make_tuple(make_pair(0, 0), 0),
+ make_tuple(make_pair(0, 5), 0),
+ make_tuple(make_pair(5, -5), 25),
+ make_tuple(make_pair(5, 0), 0),
+ make_tuple(make_pair(5, 5), 25),
+
+ make_tuple(make_pair(minVal, 0), 0),
+ make_tuple(make_pair(maxVal, 0), 0),
+ make_tuple(make_pair(minVal, -1), absMinVal),
+ make_tuple(make_pair(maxVal, -1), maxVal),
+ make_tuple(make_pair(minVal, 1), absMinVal),
+ make_tuple(make_pair(maxVal, 1), maxVal),
+
+ make_tuple(make_pair(0, minVal), 0),
+ make_tuple(make_pair(0, maxVal), 0),
+ make_tuple(make_pair(-1, minVal), absMinVal),
+ make_tuple(make_pair(-1, maxVal), maxVal),
+ make_tuple(make_pair(1, minVal), absMinVal),
+ make_tuple(make_pair(1, maxVal), maxVal),
+
+ make_tuple(make_pair(minVal, minVal), minAreaVal),
+ make_tuple(make_pair(minVal, maxVal), mixAreaVal),
+ make_tuple(make_pair(maxVal, minVal), mixAreaVal),
+ make_tuple(make_pair(maxVal, maxVal), maxAreaVal),
+
+};
+INSTANTIATE_TEST_CASE_P(AreaTest, AreaTest, ::testing::ValuesIn(valueArea));
+TEST_P(AreaTest, AreaTest) {
+ ASSERT_NO_THROW({ ASSERT_EQ(p.area(), a); });
+}
+
+using operatorsType =
+ std::tr1::tuple<IntPair, IntPair, bool, bool, bool, bool, bool>;
+class OperatorsTest : public ::testing::TestWithParam<operatorsType> {
+protected:
+ OperatorsTest() = default;
+ virtual void SetUp() {
+ auto p = GetParam();
+
+ auto pair = std::tr1::get<0>(p);
+ a = iPoint2D(pair.first, pair.second);
+
+ pair = std::tr1::get<1>(p);
+ b = iPoint2D(pair.first, pair.second);
+
+ eq = std::tr1::get<2>(p);
+ lt = std::tr1::get<3>(p);
+ gt = std::tr1::get<4>(p);
+ le = std::tr1::get<5>(p);
+ ge = std::tr1::get<6>(p);
+ }
+
+ iPoint2D a;
+ iPoint2D b;
+ bool eq;
+ bool lt;
+ bool gt;
+ bool le;
+ bool ge;
+};
+
+/*
+#!/bin/bash
+for i in -1 0 1;
+do
+ for j in -1 0 1;
+ do
+ for k in -1 0 1;
+ do
+ for q in -1 0 1;
+ do
+ echo "make_tuple(make_pair($i, $j), make_pair($k, $q), "
+
+ if [ $i -eq $k ] && [ $j -eq $q ]
+ then
+ echo "true, "
+ else
+ echo "false, "
+ fi;
+
+ if [ $i -lt $k ] && [ $j -lt $q ]
+ then
+ echo "true, "
+ else
+ echo "false, "
+ fi;
+
+ if [ $i -gt $k ] && [ $j -gt $q ]
+ then
+ echo "true, "
+ else
+ echo "false, "
+ fi;
+
+ if [ $i -le $k ] && [ $j -le $q ]
+ then
+ echo "true, "
+ else
+ echo "false, "
+ fi;
+
+ if [ $i -ge $k ] && [ $j -ge $q ]
+ then
+ echo "true"
+ else
+ echo "false"
+ fi;
+
+ echo "),";
+ done;
+ done;
+ done;
+done;
+*/
+static const operatorsType operatorsValues[]{
+ make_tuple(make_pair(-1, -1), make_pair(-1, -1), true, false, false, true,
+ true),
+ make_tuple(make_pair(-1, -1), make_pair(-1, 0), false, false, false, true,
+ false),
+ make_tuple(make_pair(-1, -1), make_pair(-1, 1), false, false, false, true,
+ false),
+ make_tuple(make_pair(-1, -1), make_pair(0, -1), false, false, false, true,
+ false),
+ make_tuple(make_pair(-1, -1), make_pair(0, 0), false, true, false, true,
+ false),
+ make_tuple(make_pair(-1, -1), make_pair(0, 1), false, true, false, true,
+ false),
+ make_tuple(make_pair(-1, -1), make_pair(1, -1), false, false, false, true,
+ false),
+ make_tuple(make_pair(-1, -1), make_pair(1, 0), false, true, false, true,
+ false),
+ make_tuple(make_pair(-1, -1), make_pair(1, 1), false, true, false, true,
+ false),
+ make_tuple(make_pair(-1, 0), make_pair(-1, -1), false, false, false, false,
+ true),
+ make_tuple(make_pair(-1, 0), make_pair(-1, 0), true, false, false, true,
+ true),
+ make_tuple(make_pair(-1, 0), make_pair(-1, 1), false, false, false, true,
+ false),
+ make_tuple(make_pair(-1, 0), make_pair(0, -1), false, false, false, false,
+ false),
+ make_tuple(make_pair(-1, 0), make_pair(0, 0), false, false, false, true,
+ false),
+ make_tuple(make_pair(-1, 0), make_pair(0, 1), false, true, false, true,
+ false),
+ make_tuple(make_pair(-1, 0), make_pair(1, -1), false, false, false, false,
+ false),
+ make_tuple(make_pair(-1, 0), make_pair(1, 0), false, false, false, true,
+ false),
+ make_tuple(make_pair(-1, 0), make_pair(1, 1), false, true, false, true,
+ false),
+ make_tuple(make_pair(-1, 1), make_pair(-1, -1), false, false, false, false,
+ true),
+ make_tuple(make_pair(-1, 1), make_pair(-1, 0), false, false, false, false,
+ true),
+ make_tuple(make_pair(-1, 1), make_pair(-1, 1), true, false, false, true,
+ true),
+ make_tuple(make_pair(-1, 1), make_pair(0, -1), false, false, false, false,
+ false),
+ make_tuple(make_pair(-1, 1), make_pair(0, 0), false, false, false, false,
+ false),
+ make_tuple(make_pair(-1, 1), make_pair(0, 1), false, false, false, true,
+ false),
+ make_tuple(make_pair(-1, 1), make_pair(1, -1), false, false, false, false,
+ false),
+ make_tuple(make_pair(-1, 1), make_pair(1, 0), false, false, false, false,
+ false),
+ make_tuple(make_pair(-1, 1), make_pair(1, 1), false, false, false, true,
+ false),
+ make_tuple(make_pair(0, -1), make_pair(-1, -1), false, false, false, false,
+ true),
+ make_tuple(make_pair(0, -1), make_pair(-1, 0), false, false, false, false,
+ false),
+ make_tuple(make_pair(0, -1), make_pair(-1, 1), false, false, false, false,
+ false),
+ make_tuple(make_pair(0, -1), make_pair(0, -1), true, false, false, true,
+ true),
+ make_tuple(make_pair(0, -1), make_pair(0, 0), false, false, false, true,
+ false),
+ make_tuple(make_pair(0, -1), make_pair(0, 1), false, false, false, true,
+ false),
+ make_tuple(make_pair(0, -1), make_pair(1, -1), false, false, false, true,
+ false),
+ make_tuple(make_pair(0, -1), make_pair(1, 0), false, true, false, true,
+ false),
+ make_tuple(make_pair(0, -1), make_pair(1, 1), false, true, false, true,
+ false),
+ make_tuple(make_pair(0, 0), make_pair(-1, -1), false, false, true, false,
+ true),
+ make_tuple(make_pair(0, 0), make_pair(-1, 0), false, false, false, false,
+ true),
+ make_tuple(make_pair(0, 0), make_pair(-1, 1), false, false, false, false,
+ false),
+ make_tuple(make_pair(0, 0), make_pair(0, -1), false, false, false, false,
+ true),
+ make_tuple(make_pair(0, 0), make_pair(0, 0), true, false, false, true,
+ true),
+ make_tuple(make_pair(0, 0), make_pair(0, 1), false, false, false, true,
+ false),
+ make_tuple(make_pair(0, 0), make_pair(1, -1), false, false, false, false,
+ false),
+ make_tuple(make_pair(0, 0), make_pair(1, 0), false, false, false, true,
+ false),
+ make_tuple(make_pair(0, 0), make_pair(1, 1), false, true, false, true,
+ false),
+ make_tuple(make_pair(0, 1), make_pair(-1, -1), false, false, true, false,
+ true),
+ make_tuple(make_pair(0, 1), make_pair(-1, 0), false, false, true, false,
+ true),
+ make_tuple(make_pair(0, 1), make_pair(-1, 1), false, false, false, false,
+ true),
+ make_tuple(make_pair(0, 1), make_pair(0, -1), false, false, false, false,
+ true),
+ make_tuple(make_pair(0, 1), make_pair(0, 0), false, false, false, false,
+ true),
+ make_tuple(make_pair(0, 1), make_pair(0, 1), true, false, false, true,
+ true),
+ make_tuple(make_pair(0, 1), make_pair(1, -1), false, false, false, false,
+ false),
+ make_tuple(make_pair(0, 1), make_pair(1, 0), false, false, false, false,
+ false),
+ make_tuple(make_pair(0, 1), make_pair(1, 1), false, false, false, true,
+ false),
+ make_tuple(make_pair(1, -1), make_pair(-1, -1), false, false, false, false,
+ true),
+ make_tuple(make_pair(1, -1), make_pair(-1, 0), false, false, false, false,
+ false),
+ make_tuple(make_pair(1, -1), make_pair(-1, 1), false, false, false, false,
+ false),
+ make_tuple(make_pair(1, -1), make_pair(0, -1), false, false, false, false,
+ true),
+ make_tuple(make_pair(1, -1), make_pair(0, 0), false, false, false, false,
+ false),
+ make_tuple(make_pair(1, -1), make_pair(0, 1), false, false, false, false,
+ false),
+ make_tuple(make_pair(1, -1), make_pair(1, -1), true, false, false, true,
+ true),
+ make_tuple(make_pair(1, -1), make_pair(1, 0), false, false, false, true,
+ false),
+ make_tuple(make_pair(1, -1), make_pair(1, 1), false, false, false, true,
+ false),
+ make_tuple(make_pair(1, 0), make_pair(-1, -1), false, false, true, false,
+ true),
+ make_tuple(make_pair(1, 0), make_pair(-1, 0), false, false, false, false,
+ true),
+ make_tuple(make_pair(1, 0), make_pair(-1, 1), false, false, false, false,
+ false),
+ make_tuple(make_pair(1, 0), make_pair(0, -1), false, false, true, false,
+ true),
+ make_tuple(make_pair(1, 0), make_pair(0, 0), false, false, false, false,
+ true),
+ make_tuple(make_pair(1, 0), make_pair(0, 1), false, false, false, false,
+ false),
+ make_tuple(make_pair(1, 0), make_pair(1, -1), false, false, false, false,
+ true),
+ make_tuple(make_pair(1, 0), make_pair(1, 0), true, false, false, true,
+ true),
+ make_tuple(make_pair(1, 0), make_pair(1, 1), false, false, false, true,
+ false),
+ make_tuple(make_pair(1, 1), make_pair(-1, -1), false, false, true, false,
+ true),
+ make_tuple(make_pair(1, 1), make_pair(-1, 0), false, false, true, false,
+ true),
+ make_tuple(make_pair(1, 1), make_pair(-1, 1), false, false, false, false,
+ true),
+ make_tuple(make_pair(1, 1), make_pair(0, -1), false, false, true, false,
+ true),
+ make_tuple(make_pair(1, 1), make_pair(0, 0), false, false, true, false,
+ true),
+ make_tuple(make_pair(1, 1), make_pair(0, 1), false, false, false, false,
+ true),
+ make_tuple(make_pair(1, 1), make_pair(1, -1), false, false, false, false,
+ true),
+ make_tuple(make_pair(1, 1), make_pair(1, 0), false, false, false, false,
+ true),
+ make_tuple(make_pair(1, 1), make_pair(1, 1), true, false, false, true,
+ true)};
+
+INSTANTIATE_TEST_CASE_P(OperatorsTests, OperatorsTest,
+ ::testing::ValuesIn(operatorsValues));
+
+TEST_P(OperatorsTest, OperatorEQTest) {
+ ASSERT_NO_THROW({ ASSERT_EQ(a == b, eq); });
+ ASSERT_NO_THROW({ ASSERT_EQ(b == a, eq); });
+}
+TEST_P(OperatorsTest, OperatorNETest) {
+ ASSERT_NO_THROW({ ASSERT_EQ(a != b, !eq); });
+ ASSERT_NO_THROW({ ASSERT_EQ(b != a, !eq); });
+}
+
+TEST_P(OperatorsTest, OperatorLTTest) {
+ ASSERT_NO_THROW({ ASSERT_EQ(a < b, lt); });
+ ASSERT_NO_THROW({ ASSERT_EQ(b > a, lt); });
+}
+TEST_P(OperatorsTest, OperatorGTest) {
+ ASSERT_NO_THROW({ ASSERT_EQ(a > b, gt); });
+ ASSERT_NO_THROW({ ASSERT_EQ(b < a, gt); });
+}
+
+TEST_P(OperatorsTest, OperatorLETest) {
+ ASSERT_NO_THROW({ ASSERT_EQ(a <= b, le); });
+ ASSERT_NO_THROW({ ASSERT_EQ(b >= a, le); });
+}
+TEST_P(OperatorsTest, OperatorGEest) {
+ ASSERT_NO_THROW({ ASSERT_EQ(a >= b, ge); });
+ ASSERT_NO_THROW({ ASSERT_EQ(b <= a, ge); });
+}
+
+TEST_P(OperatorsTest, OperatorsTest) {
+ ASSERT_NO_THROW({ ASSERT_EQ(a.isThisInside(b), le); });
+}
+
+/*
+#!/bin/bash
+for i in -5 0 5;
+do
+ for j in -5 0 5;
+ do
+ for k in -5 0 5;
+ do
+ for q in -5 0 5;
+ do
+ echo "make_tuple(make_pair($i, $j), make_pair($k, $q),
+make_pair($(($i<=$k?$i:$k)), $(($j<=$q?$j:$q)))),";
+ done;
+ done;
+ done;
+done;
+*/
+static const Six smallestValues[]{
+ make_tuple(make_pair(-5, -5), make_pair(-5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, -5), make_pair(-5, 0), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, -5), make_pair(-5, 5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, -5), make_pair(0, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, -5), make_pair(0, 0), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, -5), make_pair(0, 5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, -5), make_pair(5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, -5), make_pair(5, 0), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, -5), make_pair(5, 5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, 0), make_pair(-5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, 0), make_pair(-5, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, 0), make_pair(-5, 5), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, 0), make_pair(0, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, 0), make_pair(0, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, 0), make_pair(0, 5), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, 0), make_pair(5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, 0), make_pair(5, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, 0), make_pair(5, 5), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, 5), make_pair(-5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, 5), make_pair(-5, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, 5), make_pair(-5, 5), make_pair(-5, 5)),
+ make_tuple(make_pair(-5, 5), make_pair(0, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, 5), make_pair(0, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, 5), make_pair(0, 5), make_pair(-5, 5)),
+ make_tuple(make_pair(-5, 5), make_pair(5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(-5, 5), make_pair(5, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(-5, 5), make_pair(5, 5), make_pair(-5, 5)),
+ make_tuple(make_pair(0, -5), make_pair(-5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(0, -5), make_pair(-5, 0), make_pair(-5, -5)),
+ make_tuple(make_pair(0, -5), make_pair(-5, 5), make_pair(-5, -5)),
+ make_tuple(make_pair(0, -5), make_pair(0, -5), make_pair(0, -5)),
+ make_tuple(make_pair(0, -5), make_pair(0, 0), make_pair(0, -5)),
+ make_tuple(make_pair(0, -5), make_pair(0, 5), make_pair(0, -5)),
+ make_tuple(make_pair(0, -5), make_pair(5, -5), make_pair(0, -5)),
+ make_tuple(make_pair(0, -5), make_pair(5, 0), make_pair(0, -5)),
+ make_tuple(make_pair(0, -5), make_pair(5, 5), make_pair(0, -5)),
+ make_tuple(make_pair(0, 0), make_pair(-5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(0, 0), make_pair(-5, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(0, 0), make_pair(-5, 5), make_pair(-5, 0)),
+ make_tuple(make_pair(0, 0), make_pair(0, -5), make_pair(0, -5)),
+ make_tuple(make_pair(0, 0), make_pair(0, 0), make_pair(0, 0)),
+ make_tuple(make_pair(0, 0), make_pair(0, 5), make_pair(0, 0)),
+ make_tuple(make_pair(0, 0), make_pair(5, -5), make_pair(0, -5)),
+ make_tuple(make_pair(0, 0), make_pair(5, 0), make_pair(0, 0)),
+ make_tuple(make_pair(0, 0), make_pair(5, 5), make_pair(0, 0)),
+ make_tuple(make_pair(0, 5), make_pair(-5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(0, 5), make_pair(-5, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(0, 5), make_pair(-5, 5), make_pair(-5, 5)),
+ make_tuple(make_pair(0, 5), make_pair(0, -5), make_pair(0, -5)),
+ make_tuple(make_pair(0, 5), make_pair(0, 0), make_pair(0, 0)),
+ make_tuple(make_pair(0, 5), make_pair(0, 5), make_pair(0, 5)),
+ make_tuple(make_pair(0, 5), make_pair(5, -5), make_pair(0, -5)),
+ make_tuple(make_pair(0, 5), make_pair(5, 0), make_pair(0, 0)),
+ make_tuple(make_pair(0, 5), make_pair(5, 5), make_pair(0, 5)),
+ make_tuple(make_pair(5, -5), make_pair(-5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(5, -5), make_pair(-5, 0), make_pair(-5, -5)),
+ make_tuple(make_pair(5, -5), make_pair(-5, 5), make_pair(-5, -5)),
+ make_tuple(make_pair(5, -5), make_pair(0, -5), make_pair(0, -5)),
+ make_tuple(make_pair(5, -5), make_pair(0, 0), make_pair(0, -5)),
+ make_tuple(make_pair(5, -5), make_pair(0, 5), make_pair(0, -5)),
+ make_tuple(make_pair(5, -5), make_pair(5, -5), make_pair(5, -5)),
+ make_tuple(make_pair(5, -5), make_pair(5, 0), make_pair(5, -5)),
+ make_tuple(make_pair(5, -5), make_pair(5, 5), make_pair(5, -5)),
+ make_tuple(make_pair(5, 0), make_pair(-5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(5, 0), make_pair(-5, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(5, 0), make_pair(-5, 5), make_pair(-5, 0)),
+ make_tuple(make_pair(5, 0), make_pair(0, -5), make_pair(0, -5)),
+ make_tuple(make_pair(5, 0), make_pair(0, 0), make_pair(0, 0)),
+ make_tuple(make_pair(5, 0), make_pair(0, 5), make_pair(0, 0)),
+ make_tuple(make_pair(5, 0), make_pair(5, -5), make_pair(5, -5)),
+ make_tuple(make_pair(5, 0), make_pair(5, 0), make_pair(5, 0)),
+ make_tuple(make_pair(5, 0), make_pair(5, 5), make_pair(5, 0)),
+ make_tuple(make_pair(5, 5), make_pair(-5, -5), make_pair(-5, -5)),
+ make_tuple(make_pair(5, 5), make_pair(-5, 0), make_pair(-5, 0)),
+ make_tuple(make_pair(5, 5), make_pair(-5, 5), make_pair(-5, 5)),
+ make_tuple(make_pair(5, 5), make_pair(0, -5), make_pair(0, -5)),
+ make_tuple(make_pair(5, 5), make_pair(0, 0), make_pair(0, 0)),
+ make_tuple(make_pair(5, 5), make_pair(0, 5), make_pair(0, 5)),
+ make_tuple(make_pair(5, 5), make_pair(5, -5), make_pair(5, -5)),
+ make_tuple(make_pair(5, 5), make_pair(5, 0), make_pair(5, 0)),
+ make_tuple(make_pair(5, 5), make_pair(5, 5), make_pair(5, 5)),
+};
+
+class SmallestTest : public PointTest {};
+
+INSTANTIATE_TEST_CASE_P(GetSmallestTest, SmallestTest,
+ ::testing::ValuesIn(smallestValues));
+TEST_P(SmallestTest, GetSmallestTest) {
+ ASSERT_NO_THROW({
+ ASSERT_EQ(a.getSmallest(b), c);
+ ASSERT_EQ(a.getSmallest(c), c);
+ ASSERT_EQ(b.getSmallest(a), c);
+ ASSERT_EQ(b.getSmallest(c), c);
+ ASSERT_EQ(c.getSmallest(a), c);
+ ASSERT_EQ(c.getSmallest(b), c);
+ ASSERT_EQ(c.getSmallest(c), c);
+ });
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/common/RangeTest.cpp b/src/external/rawspeed/test/librawspeed/common/RangeTest.cpp
new file mode 100644
index 000000000..2cccb73d1
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/common/RangeTest.cpp
@@ -0,0 +1,127 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; withexpected even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Range.h" // for Range
+#include "common/RangeTest.h" // for RangeDoesntContain, RangeContains
+#include <gtest/gtest.h> // for TEST, ASSERT_EQ, ASSERT_TRUE, ASSERT_FALSE
+#include <set> // for set
+
+using rawspeed::Range;
+
+namespace rawspeed_test {
+
+// check the basic - begin/end works
+
+TEST(RangeTest, BasicSignedRangeForTest) {
+ const Range<int> r0(0, 3U);
+ ASSERT_EQ(r0.begin(), 0);
+ ASSERT_EQ(r0.end(), 3);
+
+ const Range<int> r1(-1, 3U);
+ ASSERT_EQ(r1.begin(), -1);
+ ASSERT_EQ(r1.end(), 2);
+}
+
+// check that RangeContains() works properly
+
+TEST(RangeTest, BasicSignedContainsTest) {
+ const Range<int> r0(0, 3U);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, r0.begin());
+
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, -4);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, -3);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, -2);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, -1);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, 0);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, 1);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, 2);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 3);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 4);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 5);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 6);
+}
+
+TEST(RangeTest, BasicSignedCrossoverContainsTest) {
+ const Range<int> r0(-1, 3U);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, r0.begin());
+
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, -5);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, -4);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, -3);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, -2);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, -1);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, 0);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, 1);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 2);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 3);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 4);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 5);
+}
+
+TEST(RangeTest, BasicUnsignedContainsTest) {
+ const Range<unsigned> r0(4, 3U);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, r0.begin());
+
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 0U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 1U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 2U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 3U);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, 4U);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, 5U);
+ ASSERT_PRED_FORMAT2(RangeContains, r0, 6U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 7U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 8U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 9U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 10U);
+}
+
+TEST(RangeTest, SignedZeroSizeContainsTest) {
+ const Range<int> r0(0, 0U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, r0.begin());
+
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, -2);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, -1);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 0);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 1);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 2);
+}
+
+TEST(RangeTest, UnsignedZeroSizeContainsTest) {
+ const Range<unsigned> r0(1, 0U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, r0.begin());
+
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 0U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 1U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 2U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 3U);
+ ASSERT_PRED_FORMAT2(RangeDoesntContain, r0, 4U);
+}
+
+// now let's test overlap. the test is symmetrical.
+
+TEST_P(TwoRangesTest, OverlapDataTest) {
+ if (AllOverlapped.find(GetParam()) != AllOverlapped.end()) {
+ ASSERT_PRED_FORMAT2(RangesOverlap, r0, r1);
+ } else {
+ ASSERT_PRED_FORMAT2(RangesDontOverlap, r0, r1);
+ }
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/common/RangeTest.h b/src/external/rawspeed/test/librawspeed/common/RangeTest.h
new file mode 100644
index 000000000..79fe408ea
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/common/RangeTest.h
@@ -0,0 +1,142 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; withexpected even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Range.h" // for Range
+#include <gtest/gtest.h> // for make_tuple, tuple, ParamIteratorInterface
+#include <ostream> // for basic_ostream::operator<<, operator<<, ost...
+#include <set> // for set
+#include <utility> // for __tuple_element_t
+
+using rawspeed::Range;
+
+namespace rawspeed {
+
+template <typename T>
+::std::ostream& operator<<(::std::ostream& os, const Range<T>& r) {
+ if (r.begin() == r.end())
+ return os << "(" << r.begin() << ".." << r.begin() << ")";
+ return os << "[" << r.begin() << ".." << r.end() - 1 << "]";
+}
+
+} // namespace rawspeed
+
+namespace rawspeed_test {
+
+template <typename T>
+::testing::AssertionResult RangeContains(const char* range_expr,
+ const char* pos_expr,
+ const Range<T>& r, const T& pos) {
+ if (RangeContains(r, r.end()))
+ return ::testing::AssertionFailure() << "Range does contain it's end()!";
+
+ if (RangeContains(r, pos))
+ return ::testing::AssertionSuccess();
+
+ return ::testing::AssertionFailure()
+ << "Range " << range_expr << " " << r << " does not contain "
+ << pos_expr << " (" << pos << ")";
+}
+
+template <typename T>
+::testing::AssertionResult RangeDoesntContain(const char* range_expr,
+ const char* pos_expr,
+ const Range<T>& r, const T& pos) {
+ if (RangeContains(r, r.end()))
+ return ::testing::AssertionFailure() << "Range does contain it's end()!";
+
+ if (!RangeContains(r, pos))
+ return ::testing::AssertionSuccess();
+
+ return ::testing::AssertionFailure()
+ << "Range " << range_expr << " " << r << " contains " << pos_expr
+ << " (" << pos << ")";
+}
+
+template <typename T>
+::testing::AssertionResult RangesOverlap(const char* m_expr, const char* n_expr,
+ const T& lhs, const T& rhs) {
+ if (!RangesOverlap(lhs, lhs) || !RangesOverlap(rhs, rhs))
+ return ::testing::AssertionFailure() << "Ranges don't self-overlap!";
+
+ if (RangesOverlap(lhs, rhs) && RangesOverlap(rhs, lhs))
+ return ::testing::AssertionSuccess();
+
+ return ::testing::AssertionFailure()
+ << "Ranges " << m_expr << " and " << n_expr << " (" << lhs << " and "
+ << rhs << ") do not overlap.";
+}
+
+template <typename T>
+::testing::AssertionResult RangesDontOverlap(const char* m_expr,
+ const char* n_expr, const T& lhs,
+ const T& rhs) {
+ if (!RangesOverlap(lhs, lhs) || !RangesOverlap(rhs, rhs))
+ return ::testing::AssertionFailure() << "Ranges don't self-overlap!";
+
+ if (!RangesOverlap(lhs, rhs) && !RangesOverlap(rhs, lhs))
+ return ::testing::AssertionSuccess();
+
+ return ::testing::AssertionFailure()
+ << "Ranges " << m_expr << " and " << n_expr << " (" << lhs << " and "
+ << rhs << ") do overlap.";
+}
+
+using twoRangesType = std::tr1::tuple<int, unsigned, int, unsigned>;
+class TwoRangesTest : public ::testing::TestWithParam<twoRangesType> {
+protected:
+ TwoRangesTest() = default;
+ virtual void SetUp() {
+ r0 = Range<int>(std::tr1::get<0>(GetParam()), std::tr1::get<1>(GetParam()));
+ r1 = Range<int>(std::tr1::get<2>(GetParam()), std::tr1::get<3>(GetParam()));
+ }
+
+ Range<int> r0;
+ Range<int> r1;
+};
+INSTANTIATE_TEST_CASE_P(Unsigned, TwoRangesTest,
+ testing::Combine(testing::Range(0, 3),
+ testing::Range(0U, 3U),
+ testing::Range(0, 3),
+ testing::Range(0U, 3U)));
+
+static const std::set<twoRangesType> AllOverlapped{
+ std::make_tuple(0, 0, 0, 0), std::make_tuple(0, 0, 0, 1),
+ std::make_tuple(0, 0, 0, 2), std::make_tuple(0, 1, 0, 0),
+ std::make_tuple(0, 1, 0, 1), std::make_tuple(0, 1, 0, 2),
+ std::make_tuple(0, 2, 0, 0), std::make_tuple(0, 2, 0, 1),
+ std::make_tuple(0, 2, 0, 2), std::make_tuple(0, 2, 1, 0),
+ std::make_tuple(0, 2, 1, 1), std::make_tuple(0, 2, 1, 2),
+ std::make_tuple(1, 0, 0, 2), std::make_tuple(1, 0, 1, 0),
+ std::make_tuple(1, 0, 1, 1), std::make_tuple(1, 0, 1, 2),
+ std::make_tuple(1, 1, 0, 2), std::make_tuple(1, 1, 1, 0),
+ std::make_tuple(1, 1, 1, 1), std::make_tuple(1, 1, 1, 2),
+ std::make_tuple(1, 2, 0, 2), std::make_tuple(1, 2, 1, 0),
+ std::make_tuple(1, 2, 1, 1), std::make_tuple(1, 2, 1, 2),
+ std::make_tuple(1, 2, 2, 0), std::make_tuple(1, 2, 2, 1),
+ std::make_tuple(1, 2, 2, 2), std::make_tuple(2, 0, 1, 2),
+ std::make_tuple(2, 0, 2, 0), std::make_tuple(2, 0, 2, 1),
+ std::make_tuple(2, 0, 2, 2), std::make_tuple(2, 1, 1, 2),
+ std::make_tuple(2, 1, 2, 0), std::make_tuple(2, 1, 2, 1),
+ std::make_tuple(2, 1, 2, 2), std::make_tuple(2, 2, 1, 2),
+ std::make_tuple(2, 2, 2, 0), std::make_tuple(2, 2, 2, 1),
+ std::make_tuple(2, 2, 2, 2),
+};
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/common/SplineTest.cpp b/src/external/rawspeed/test/librawspeed/common/SplineTest.cpp
new file mode 100644
index 000000000..2334cc414
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/common/SplineTest.cpp
@@ -0,0 +1,512 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2018 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; withexpected even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Spline.h" // for Spline
+#include <array> // for array
+#include <cmath> // for acos
+#include <gtest/gtest.h> // for AssertionResult, DeathTest, Test, AssertHe...
+#include <type_traits> // for is_same
+
+using rawspeed::Spline;
+using std::make_tuple;
+
+namespace rawspeed {
+
+::std::ostream& operator<<(::std::ostream& os, const iPoint2D p) {
+ return os << "(" << p.x << ", " << p.y << ")";
+}
+
+} // namespace rawspeed
+
+namespace rawspeed_test {
+
+TEST(SplineStaticTest, DefaultIsUshort16) {
+ static_assert(std::is_same<Spline<>::value_type, rawspeed::ushort16>::value,
+ "wrong default type");
+}
+
+#ifndef NDEBUG
+TEST(SplineDeathTest, AtLeastTwoPoints) {
+ ASSERT_DEATH(
+ {
+ Spline<> s({});
+ s.calculateCurve();
+ },
+ "at least two points");
+ ASSERT_DEATH(
+ {
+ Spline<> s({{0, 0}});
+ s.calculateCurve();
+ },
+ "at least two points");
+ ASSERT_EXIT(
+ {
+ Spline<> s({{0, {}}, {65535, {}}});
+ s.calculateCurve();
+ exit(0);
+ },
+ ::testing::ExitedWithCode(0), "");
+}
+
+TEST(SplineDeathTest, XIsFullRange) {
+ ASSERT_DEATH(
+ {
+ Spline<> s({{1, {}}, {65535, {}}});
+ s.calculateCurve();
+ },
+ "front.*0");
+ ASSERT_DEATH(
+ {
+ Spline<> s({{0, {}}, {65534, {}}});
+ s.calculateCurve();
+ },
+ "back.*65535");
+}
+
+TEST(SplineDeathTest, YIsLimited) {
+ ASSERT_DEATH(
+ {
+ Spline<> s({{0, {}}, {32767, -1}, {65535, {}}});
+ s.calculateCurve();
+ },
+ "y >= .*min");
+ ASSERT_DEATH(
+ {
+ Spline<> s({{0, {}}, {32767, 65536}, {65535, {}}});
+ s.calculateCurve();
+ },
+ "y <= .*max");
+}
+
+TEST(SplineDeathTest, XIsStrictlyIncreasing) {
+ ASSERT_DEATH(
+ {
+ Spline<> s({{0, {}}, {0, {}}, {65535, {}}});
+ s.calculateCurve();
+ },
+ "strictly increasing");
+ ASSERT_DEATH(
+ {
+ Spline<> s({{0, {}}, {32767, {}}, {32767, {}}, {65535, {}}});
+ s.calculateCurve();
+ },
+ "strictly increasing");
+ ASSERT_DEATH(
+ {
+ Spline<> s({{0, {}}, {65535, {}}, {65535, {}}});
+ s.calculateCurve();
+ },
+ "strictly increasing");
+ ASSERT_DEATH(
+ {
+ Spline<> s({{0, {}}, {32767, {}}, {32766, {}}, {65535, {}}});
+ s.calculateCurve();
+ },
+ "strictly increasing");
+}
+#endif
+
+TEST(SplineDeathTest, ClampUshort16Min) {
+ ASSERT_EXIT(
+ {
+ Spline<> s({{0, 0},
+ {2, 0},
+ {54, 0},
+ {128, 0},
+ {256, 0},
+ {21504, 0},
+ {32768, 0},
+ {57088, 0},
+ {65535, 65535}});
+ s.calculateCurve();
+ // for x = 484, this used to compute -1.0046832758220527,
+ // which is unrepresentable in ushort16.
+ exit(0);
+ },
+ ::testing::ExitedWithCode(0), "");
+}
+TEST(SplineDeathTest, ClampUshort16Max) {
+ ASSERT_EXIT(
+ {
+ Spline<> s({{0, 0},
+ {2, 0},
+ {56, 0},
+ {128, 0},
+ {256, 0},
+ {21504, 0},
+ {32768, 0},
+ {57088, 0},
+ {65535, 65535}});
+ s.calculateCurve();
+ // for x = 65535, this used to compute 65535.000000000007,
+ // which is unrepresentable in ushort16.
+ exit(0);
+ },
+ ::testing::ExitedWithCode(0), "");
+}
+
+using identityType = std::tuple<std::array<rawspeed::iPoint2D, 2>,
+ std::vector<std::array<double, 4>>>;
+template <typename T>
+class IdentityTest : public ::testing::TestWithParam<identityType> {
+protected:
+ IdentityTest() = default;
+
+ void CheckSegments() const {
+ ASSERT_EQ(gotSegments.size(), expSegments.size());
+ for (auto i = 0U; i < gotSegments.size(); i++) {
+ const auto s0 = gotSegments[i];
+ const auto s1 = expSegments[i];
+ ASSERT_EQ(s0.a, s1[0]);
+ ASSERT_EQ(s0.b, s1[1]);
+ ASSERT_EQ(s0.c, s1[2]);
+ ASSERT_EQ(s0.d, s1[3]);
+ }
+ }
+
+ virtual void SetUp() {
+ const auto p = GetParam();
+ edges = std::get<0>(p);
+ expSegments = std::get<1>(p);
+
+ Spline<T> s({std::begin(edges), std::end(edges)});
+ gotSegments = s.getSegments();
+ interpolated = s.calculateCurve();
+
+ ASSERT_FALSE(interpolated.empty());
+ ASSERT_EQ(interpolated.size(), 65536);
+ }
+
+ std::array<rawspeed::iPoint2D, 2> edges;
+ std::vector<std::array<double, 4>> expSegments;
+ std::vector<typename Spline<T>::Segment> gotSegments;
+ std::vector<T> interpolated;
+};
+static const identityType identityValues[] = {
+ make_tuple(std::array<rawspeed::iPoint2D, 2>{{{0, 0}, {65535, 65535}}},
+ std::vector<std::array<double, 4>>{{{0.0, 1.0, 0.0, 0.0}}}),
+ make_tuple(
+ std::array<rawspeed::iPoint2D, 2>{{{0, 65535}, {65535, 0}}},
+ std::vector<std::array<double, 4>>{{{65535.0, -1.0, 0.0, 0.0}}})};
+
+using IntegerIdentityTest = IdentityTest<rawspeed::ushort16>;
+INSTANTIATE_TEST_CASE_P(IntegerIdentityTest, IntegerIdentityTest,
+ ::testing::ValuesIn(identityValues));
+TEST_P(IntegerIdentityTest, ValuesAreLinearlyInterpolated) {
+ for (auto x = edges.front().y; x < edges.back().y; ++x)
+ ASSERT_EQ(interpolated[x], x);
+}
+TEST_P(IntegerIdentityTest, SegmentCoeffients) { CheckSegments(); }
+
+using DoubleIdentityTest = IdentityTest<double>;
+INSTANTIATE_TEST_CASE_P(DoubleIdentityTest, DoubleIdentityTest,
+ ::testing::ValuesIn(identityValues));
+TEST_P(DoubleIdentityTest, ValuesAreLinearlyInterpolated) {
+ for (auto x = edges.front().y; x < edges.back().y; ++x) {
+ ASSERT_DOUBLE_EQ(interpolated[x], x);
+ ASSERT_EQ(interpolated[x], x);
+ }
+}
+TEST_P(DoubleIdentityTest, SegmentCoeffients) { CheckSegments(); }
+
+template <typename T> T lerp(T v0, T v1, T t) {
+ return (1.0 - t) * v0 + t * v1;
+}
+
+std::vector<int> calculateSteps(int numCp) {
+ std::vector<int> steps;
+
+ const auto ptsTotal = 2U + numCp;
+ steps.reserve(ptsTotal);
+
+ const auto dt = 1.0 / (ptsTotal - 1);
+ double t = 0.0;
+ std::generate_n(std::back_inserter(steps), ptsTotal, [dt, &t]() {
+ const double x = lerp(0.0, 65535.0, t);
+ t += dt;
+ return x + 0.5;
+ });
+
+ assert(ptsTotal == steps.size());
+ return steps;
+}
+TEST(CalculateStepsEdgesTest, IdentityTest) {
+ const int steps = 65534;
+ const auto pts = calculateSteps(steps);
+ for (auto x = 0U; x < pts.size(); x++)
+ ASSERT_EQ(pts[x], x);
+}
+
+class CalculateStepsEdgesTest : public ::testing::TestWithParam<int> {
+protected:
+ CalculateStepsEdgesTest() = default;
+ virtual void SetUp() {
+ extraSteps = GetParam();
+ got = calculateSteps(extraSteps);
+ }
+
+ int extraSteps;
+ std::vector<int> got;
+};
+INSTANTIATE_TEST_CASE_P(CalculateStepsEdgesTest, CalculateStepsEdgesTest,
+ ::testing::Range(0, 254));
+TEST_P(CalculateStepsEdgesTest, Count) {
+ ASSERT_EQ(got.size(), 2 + extraSteps);
+}
+TEST_P(CalculateStepsEdgesTest, EdgesAreProper) {
+ ASSERT_EQ(got.front(), 0);
+ ASSERT_EQ(got.back(), 65535);
+}
+
+using calculateStepsType = std::tuple<int, std::vector<int>>;
+class CalculateStepsTest : public ::testing::TestWithParam<calculateStepsType> {
+protected:
+ CalculateStepsTest() = default;
+ virtual void SetUp() {
+ const auto p = GetParam();
+ extraSteps = std::get<0>(p);
+ expected = std::get<1>(p);
+
+ got = calculateSteps(extraSteps);
+ }
+
+ int extraSteps;
+ std::vector<int> expected;
+ std::vector<int> got;
+};
+static const calculateStepsType calculateStepsValues[] = {
+ // clang-format off
+ make_tuple(0, std::vector<int>{0, 65535}),
+ make_tuple(1, std::vector<int>{0, 32768, 65535}),
+ make_tuple(2, std::vector<int>{0, 21845, 43690, 65535}),
+ make_tuple(3, std::vector<int>{0, 16384, 32768, 49151, 65535}),
+ make_tuple(4, std::vector<int>{0, 13107, 26214, 39321, 52428, 65535}),
+ make_tuple(5, std::vector<int>{0, 10923, 21845, 32768, 43690, 54612, 65535}),
+ make_tuple(6, std::vector<int>{0, 9362, 18724, 28086, 37449, 46811, 56173, 65535}),
+ make_tuple(7, std::vector<int>{0, 8192, 16384, 24576, 32768, 40959, 49151, 57343, 65535}),
+ make_tuple(8, std::vector<int>{0, 7282, 14563, 21845, 29127, 36408, 43690, 50972, 58253, 65535}),
+ // clang-format on
+};
+
+INSTANTIATE_TEST_CASE_P(CalculateStepsTest, CalculateStepsTest,
+ ::testing::ValuesIn(calculateStepsValues));
+TEST_P(CalculateStepsTest, Count) {
+ ASSERT_EQ(expected.size(), got.size());
+ ASSERT_EQ(got.size(), 2 + extraSteps);
+}
+TEST_P(CalculateStepsTest, GotExpectedOutput) { ASSERT_EQ(got, expected); }
+
+using constantType = std::tuple<int, int>;
+template <typename T>
+class ConstantTest : public ::testing::TestWithParam<constantType> {
+protected:
+ ConstantTest() = default;
+
+ void calculateEdges() {
+ const auto steps = calculateSteps(numCp);
+ edges.reserve(steps.size());
+
+ for (const int step : steps)
+ edges.emplace_back(step, constant);
+
+ assert(steps.size() == edges.size());
+ }
+
+ void CheckSegments() const {
+ for (auto i = 0U; i < gotSegments.size(); i++) {
+ const auto s0 = gotSegments[i];
+ ASSERT_EQ(s0.a, constant);
+ ASSERT_EQ(s0.b, 0);
+ ASSERT_EQ(s0.c, 0);
+ ASSERT_EQ(s0.d, 0);
+ }
+ }
+
+ virtual void SetUp() {
+ auto p = GetParam();
+
+ constant = std::get<0>(p);
+ numCp = std::get<1>(p);
+
+ calculateEdges();
+
+ // EXPECT_TRUE(false) << ::testing::PrintToString((edges));
+
+ Spline<T> s({std::begin(edges), std::end(edges)});
+ gotSegments = s.getSegments();
+ interpolated = s.calculateCurve();
+
+ ASSERT_FALSE(interpolated.empty());
+ ASSERT_EQ(interpolated.size(), 65536);
+ }
+
+ int constant;
+ int numCp;
+
+ std::vector<rawspeed::iPoint2D> edges;
+ std::vector<typename Spline<T>::Segment> gotSegments;
+ std::vector<T> interpolated;
+};
+
+constexpr auto NumExtraSteps = 3;
+static const auto constantValues =
+ ::testing::Combine(::testing::ValuesIn(calculateSteps(NumExtraSteps)),
+ ::testing::Range(0, 1 + NumExtraSteps));
+
+using IntegerConstantTest = ConstantTest<rawspeed::ushort16>;
+INSTANTIATE_TEST_CASE_P(IntegerConstantTest, IntegerConstantTest,
+ constantValues);
+TEST_P(IntegerConstantTest, AllValuesAreEqual) {
+ for (const auto value : interpolated)
+ ASSERT_EQ(value, constant);
+}
+TEST_P(IntegerConstantTest, SegmentCoeffients) { CheckSegments(); }
+
+using DoubleConstantTest = ConstantTest<double>;
+INSTANTIATE_TEST_CASE_P(DoubleConstantTest, DoubleConstantTest, constantValues);
+TEST_P(DoubleConstantTest, AllValuesAreEqual) {
+ for (const auto value : interpolated) {
+ ASSERT_DOUBLE_EQ(value, constant);
+ ASSERT_EQ(value, constant);
+ }
+}
+TEST_P(DoubleConstantTest, SegmentCoeffients) { CheckSegments(); }
+
+class AbstractReferenceTest {
+public:
+ using T = long double;
+
+ const T xMax = 65535;
+ const T yMax = std::numeric_limits<rawspeed::iPoint2D::value_type>::max();
+
+ virtual T calculateRefVal(int x) const = 0;
+
+ virtual ~AbstractReferenceTest() = default;
+};
+
+template <int mul, int div>
+class SinReferenceTest : public AbstractReferenceTest {
+public:
+ T calculateRefVal(int x) const final {
+ const T pi = std::acos(T(-1));
+ const T x2arg = T(mul) * pi / (div * xMax);
+
+ return yMax * std::sin(x2arg * T(x));
+ }
+
+ virtual ~SinReferenceTest() = default;
+};
+
+using referenceType = std::tuple<int, long double>;
+
+template <typename Tb>
+class ReferenceTest : public Tb,
+ public ::testing::TestWithParam<referenceType> {
+protected:
+ using T = AbstractReferenceTest::T;
+
+ ReferenceTest() = default;
+
+ void calculateReference() {
+ const auto xPoints = calculateSteps(numPts);
+
+ reference.reserve(xPoints.size());
+ for (const auto xPoint : xPoints)
+ reference.emplace_back(xPoint, this->calculateRefVal(xPoint));
+
+ assert(reference.size() == xPoints.size());
+ }
+
+ virtual void SetUp() {
+ const auto p = GetParam();
+
+ numPts = std::get<0>(p);
+ absError = std::get<1>(p);
+
+ calculateReference();
+
+ Spline<T> s(reference);
+ interpolated = s.calculateCurve();
+ ASSERT_FALSE(interpolated.empty());
+ ASSERT_EQ(interpolated.size(), AbstractReferenceTest::xMax + 1);
+ }
+
+ void check() const {
+ for (auto x = reference.front().x; x < reference.back().x; ++x) {
+ const T referen = this->calculateRefVal(x) / this->yMax;
+ const T interpo = T(interpolated[x]) / this->yMax;
+ ASSERT_NEAR(interpo, referen, absError);
+ }
+ }
+
+ int numPts;
+ long double absError;
+
+ std::vector<rawspeed::iPoint2D> reference;
+ std::vector<T> interpolated;
+};
+
+using Sin2PiRefTest = ReferenceTest<SinReferenceTest<2, 1>>;
+static const referenceType sin2PiRefValues[] = {
+ // clang-format off
+ make_tuple(0, 1.0E-00),
+ make_tuple(1, 1.0E+01), // FIXME: should be 1.0E-00
+ make_tuple(2, 1.0E-00),
+ make_tuple(3, 1.0E-01),
+ make_tuple(4, 1.0E-02),
+ make_tuple(5, 1.0E-02),
+ make_tuple(6, 1.0E-02),
+ make_tuple(7, 1.0E-02),
+ make_tuple(8, 1.0E-03),
+ make_tuple(9, 1.0E-03),
+ make_tuple(10, 1.0E-03),
+ make_tuple(11, 1.0E-03),
+ make_tuple(12, 1.0E-03),
+ make_tuple(13, 1.0E-03),
+ make_tuple(14, 1.0E-04),
+ // clang-format on
+};
+INSTANTIATE_TEST_CASE_P(Sin2Pi, Sin2PiRefTest,
+ ::testing::ValuesIn(sin2PiRefValues));
+TEST_P(Sin2PiRefTest, NearlyMatchesReference) { check(); }
+
+using SinPiRefTest = ReferenceTest<SinReferenceTest<1, 1>>;
+static const referenceType sinPiRefValues[] = {
+ // clang-format off
+ make_tuple(0, 1.0E-00),
+ make_tuple(1, 1.0E-01),
+ make_tuple(2, 1.0E-02),
+ make_tuple(3, 1.0E-02),
+ make_tuple(4, 1.0E-03),
+ make_tuple(5, 1.0E-03),
+ make_tuple(6, 1.0E-03),
+ make_tuple(7, 1.0E-04),
+ make_tuple(8, 1.0E-04),
+ make_tuple(9, 1.0E-04),
+ make_tuple(10, 1.0E-04),
+ make_tuple(11, 1.0E-04),
+ make_tuple(12, 1.0E-05),
+ // clang-format on
+};
+INSTANTIATE_TEST_CASE_P(SinPi, SinPiRefTest,
+ ::testing::ValuesIn(sinPiRefValues));
+TEST_P(SinPiRefTest, NearlyMatchesReference) { check(); }
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/common/ThreadingTest.cpp b/src/external/rawspeed/test/librawspeed/common/ThreadingTest.cpp
new file mode 100644
index 000000000..091cb631f
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/common/ThreadingTest.cpp
@@ -0,0 +1,157 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; withexpected even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Threading.h" // for sliceUp
+#include <algorithm> // for min
+#include <array> // for array
+#include <cassert> // for assert
+#include <gtest/gtest.h> // for make_tuple, tuple, ParamIteratorInterface
+#include <map> // for _Rb_tree_const_iterator, map, map<>::c...
+#include <numeric> // for accumulate
+#include <utility> // for pair
+#include <vector> // for vector
+
+using rawspeed::sliceUp;
+
+namespace rawspeed_test {
+
+// reference implementation, which is readable.
+inline std::vector<unsigned> sliceUp_dumb(unsigned bucketsNum,
+ unsigned pieces) {
+ std::vector<unsigned> buckets;
+
+ if (!bucketsNum || !pieces)
+ return buckets;
+
+ buckets.resize(std::min(bucketsNum, pieces), 0U);
+
+ // split all the pieces between all the threads 'evenly'
+ unsigned piecesLeft = pieces;
+ while (piecesLeft > 0U) {
+ for (auto& bucket : buckets) {
+ --piecesLeft;
+ ++bucket;
+ if (0U == piecesLeft)
+ break;
+ }
+ }
+ assert(piecesLeft == 0U);
+ assert(std::accumulate(buckets.begin(), buckets.end(), 0UL) == pieces);
+
+ return buckets;
+}
+
+using twoValsType = std::tr1::tuple<unsigned, unsigned>;
+
+static const std::map<twoValsType, std::array<unsigned, 4>> Expected{
+ {std::make_tuple(0U, 0U), {{}}},
+ {std::make_tuple(0U, 1U), {{}}},
+ {std::make_tuple(0U, 2U), {{}}},
+ {std::make_tuple(0U, 3U), {{}}},
+ {std::make_tuple(0U, 4U), {{}}},
+ {std::make_tuple(0U, 5U), {{}}},
+ {std::make_tuple(0U, 6U), {{}}},
+ {std::make_tuple(1U, 0U), {{}}},
+ {std::make_tuple(1U, 1U), {{1U}}},
+ {std::make_tuple(1U, 2U), {{2U}}},
+ {std::make_tuple(1U, 3U), {{3U}}},
+ {std::make_tuple(1U, 4U), {{4U}}},
+ {std::make_tuple(1U, 5U), {{5U}}},
+ {std::make_tuple(1U, 6U), {{6U}}},
+ {std::make_tuple(2U, 0U), {{}}},
+ {std::make_tuple(2U, 1U), {{1U}}},
+ {std::make_tuple(2U, 2U), {{1U, 1U}}},
+ {std::make_tuple(2U, 3U), {{2U, 1U}}},
+ {std::make_tuple(2U, 4U), {{2U, 2U}}},
+ {std::make_tuple(2U, 5U), {{3U, 2U}}},
+ {std::make_tuple(2U, 6U), {{3U, 3U}}},
+ {std::make_tuple(3U, 0U), {{}}},
+ {std::make_tuple(3U, 1U), {{1U}}},
+ {std::make_tuple(3U, 2U), {{1U, 1U}}},
+ {std::make_tuple(3U, 3U), {{1U, 1U, 1U}}},
+ {std::make_tuple(3U, 4U), {{2U, 1U, 1U}}},
+ {std::make_tuple(3U, 5U), {{2U, 2U, 1U}}},
+ {std::make_tuple(3U, 6U), {{2U, 2U, 2U}}},
+ {std::make_tuple(4U, 0U), {{}}},
+ {std::make_tuple(4U, 1U), {{1U}}},
+ {std::make_tuple(4U, 2U), {{1U, 1U}}},
+ {std::make_tuple(4U, 3U), {{1U, 1U, 1U}}},
+ {std::make_tuple(4U, 4U), {{1U, 1U, 1U, 1U}}},
+ {std::make_tuple(4U, 5U), {{2U, 1U, 1U, 1U}}},
+ {std::make_tuple(4U, 6U), {{2U, 2U, 1U, 1U}}},
+
+};
+
+class SliceUpTest : public ::testing::TestWithParam<twoValsType> {
+protected:
+ SliceUpTest() = default;
+ virtual void SetUp() {
+ threads = std::tr1::get<0>(GetParam());
+ pieces = std::tr1::get<1>(GetParam());
+
+ expected = Expected.find(GetParam());
+ ASSERT_NE(expected, Expected.end());
+
+ if (threads != 0) {
+ ASSERT_EQ(
+ std::accumulate(expected->second.begin(), expected->second.end(), 0U),
+ pieces);
+ }
+ }
+
+ void Check(std::vector<unsigned> got) {
+ for (unsigned i = 0; i < 1; i++) {
+ if (got.size() <= i)
+ ASSERT_EQ(expected->second[i], 0);
+ else
+ ASSERT_EQ(got[i], expected->second[i]);
+ }
+ }
+
+ unsigned threads;
+ unsigned pieces;
+ decltype(Expected)::const_iterator expected;
+};
+INSTANTIATE_TEST_CASE_P(SaneValues, SliceUpTest,
+ testing::Combine(testing::Range(0U, 5U),
+ testing::Range(0U, 7U)));
+
+TEST_P(SliceUpTest, ReferenceTest) { Check(sliceUp_dumb(threads, pieces)); }
+TEST_P(SliceUpTest, Test) { Check(sliceUp(threads, pieces)); }
+
+class SliceUpTortureTest : public ::testing::TestWithParam<twoValsType> {
+protected:
+ SliceUpTortureTest() = default;
+ virtual void SetUp() {
+ threads = std::tr1::get<0>(GetParam());
+ pieces = std::tr1::get<1>(GetParam());
+ }
+
+ unsigned threads;
+ unsigned pieces;
+};
+INSTANTIATE_TEST_CASE_P(ManyValues, SliceUpTortureTest,
+ testing::Combine(testing::Range(0U, 17U),
+ testing::Range(0U, 63U)));
+TEST_P(SliceUpTortureTest, BruteForceTest) {
+ ASSERT_EQ(sliceUp(threads, pieces), sliceUp_dumb(threads, pieces));
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/io/CMakeLists.txt b/src/external/rawspeed/test/librawspeed/io/CMakeLists.txt
new file mode 100644
index 000000000..cc6ccfea9
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/io/CMakeLists.txt
@@ -0,0 +1,7 @@
+FILE(GLOB RAWSPEED_TEST_SOURCES
+ "EndiannessTest.cpp"
+)
+
+foreach(IN ${RAWSPEED_TEST_SOURCES})
+ add_rs_test(${IN})
+endforeach()
diff --git a/src/external/rawspeed/test/librawspeed/io/EndiannessTest.cpp b/src/external/rawspeed/test/librawspeed/io/EndiannessTest.cpp
new file mode 100644
index 000000000..94302e1d9
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/io/EndiannessTest.cpp
@@ -0,0 +1,372 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "EndiannessTest.h"
+#include "common/Common.h" // for int32, short16, uint32, uint64, ushort16
+#include "io/Endianness.h" // for getHostEndianness, Endianness::big, Endia...
+#include <cstring> // for memcpy, memcmp
+#include <gtest/gtest.h> // for Message, AssertionResult, ASSERT_PRED_FOR...
+#include <iomanip> // for _Setw, setfill, setw, _Setfill
+#include <iostream> // for hex, endl, ostream
+#include <utility> // for get
+
+using rawspeed::Endianness;
+using rawspeed::getBE;
+using rawspeed::getByteSwapped;
+using rawspeed::getHostEndianness;
+using rawspeed::getHostEndiannessRuntime;
+using rawspeed::getLE;
+using rawspeed::getU16BE;
+using rawspeed::getU16LE;
+using rawspeed::getU32BE;
+using rawspeed::getU32LE;
+using rawspeed::int32;
+using rawspeed::short16;
+using std::setfill;
+using std::setw;
+
+namespace rawspeed_test {
+
+TEST(EndiannessTest, getHostEndiannessTests) {
+#if defined(__BYTE_ORDER__)
+ ASSERT_EQ(getHostEndiannessRuntime(), getHostEndianness());
+#endif
+}
+
+/*
+#!/bin/bash
+d=16 # squared, how many samples
+# B=2 # sizeof, bytes
+b=x # print format
+p="0x" # print prefix
+function proc {
+ echo "$1" | od -A n --endian="$2" -t $3$B -N $B -w$B | tr -d ''
+}
+function pp {
+ v=$(proc "$1" "$2" "$b")
+ echo $p$v
+}
+for i in $(seq $d)
+do
+ for j in $(seq $d);
+ do
+ v=$(dd if=/dev/urandom bs=$B conv=sparse count=1 status=none)
+ x=$(pp "$v" little);
+ y=$(pp "$v" big);
+ echo "{$x, $y},";
+ done;
+done;
+*/
+
+#define setupHex setfill('0') << setw(2 * sizeof(T)) << std::hex
+
+template <typename T>
+::std::ostream& operator<<(::std::ostream& os, const intPair<T>& p) {
+ ::testing::Message msg;
+ msg << "(0x" << setupHex << p.first << ", 0x" << setupHex << p.second << ")";
+
+ return os << msg;
+}
+
+// no polymorphic lambda till c++14
+struct HexEquals {
+ template <typename T>
+ ::testing::AssertionResult operator()(const char* darg1, const char* darg2,
+ const T& arg1, const T& arg2) {
+ if (memcmp(&arg1, &arg2, sizeof(T)) == 0)
+ return ::testing::AssertionSuccess();
+
+ ::testing::Message msg;
+ msg << " Expected: " << darg1 << std::endl;
+ msg << " Which is: " << setupHex << arg1 << std::endl;
+ msg << "To be equal to: " << darg2 << std::endl;
+ msg << " Which is: " << setupHex << arg2;
+
+ return ::testing::AssertionFailure() << msg;
+ }
+};
+
+#undef setupHex
+
+template <class T1, class T2>
+class AbstractGetByteSwappedTest : public ::testing::TestWithParam<T1> {
+protected:
+ AbstractGetByteSwappedTest() = default;
+ virtual void SetUp() {
+ auto p = this->GetParam();
+ auto v = std::tr1::get<0>(p);
+
+ // swap them around? the test is symmetrical
+ if (std::tr1::get<1>(p)) {
+ memcpy(&in, &(v.first), sizeof(T2));
+ memcpy(&expected, &(v.second), sizeof(T2));
+ } else {
+ memcpy(&in, &(v.second), sizeof(T2));
+ memcpy(&expected, &(v.first), sizeof(T2));
+ }
+ }
+ T2 getByteSwappedT(const void* data, bool bswap) {
+ return getByteSwapped<T2>(data, bswap);
+ }
+ T2 getBEt(const void* data) { return getBE<T2>(data); }
+ T2 getLEt(const void* data) { return getLE<T2>(data); }
+
+ T2 in; // input
+ T2 expected; // expected output
+};
+
+/*
+B=2 # sizeof, bytes
+*/
+class ushort16Test
+ : public AbstractGetByteSwappedTest<ushort16TType, ushort16> {};
+INSTANTIATE_TEST_CASE_P(ushort16Test, ushort16Test,
+ ::testing::Combine(::testing::ValuesIn(ushort16Values),
+ ::testing::Bool()));
+TEST_P(ushort16Test, swap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
+}
+TEST_P(ushort16Test, NOP) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
+}
+TEST_P(ushort16Test, typedSwap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
+}
+TEST_P(ushort16Test, get) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
+ }
+}
+TEST_P(ushort16Test, getNOP) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
+ }
+}
+
+TEST_P(ushort16Test, getU16) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getU16BE(&in), expected);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getU16LE(&in), expected);
+ }
+}
+TEST_P(ushort16Test, getU16NOP) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getU16LE(&in), in);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getU16BE(&in), in);
+ }
+}
+
+class short16Test : public AbstractGetByteSwappedTest<ushort16TType, short16> {
+};
+INSTANTIATE_TEST_CASE_P(short16Test, short16Test,
+ ::testing::Combine(::testing::ValuesIn(ushort16Values),
+ ::testing::Bool()));
+TEST_P(short16Test, swap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
+}
+TEST_P(short16Test, NOP) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
+}
+TEST_P(short16Test, typedSwap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
+}
+TEST_P(short16Test, get) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
+ }
+}
+TEST_P(short16Test, getNOP) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
+ }
+}
+
+/*
+B=4 # sizeof, bytes
+*/
+class uint32Test : public AbstractGetByteSwappedTest<uint32TType, uint32> {};
+INSTANTIATE_TEST_CASE_P(uint32Test, uint32Test,
+ ::testing::Combine(::testing::ValuesIn(uint32Values),
+ ::testing::Bool()));
+TEST_P(uint32Test, swap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
+}
+TEST_P(uint32Test, NOP) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
+}
+TEST_P(uint32Test, typedSwap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
+}
+TEST_P(uint32Test, get) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
+ }
+}
+TEST_P(uint32Test, getNOP) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
+ }
+}
+
+TEST_P(uint32Test, getU32) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getU32BE(&in), expected);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getU32LE(&in), expected);
+ }
+}
+TEST_P(uint32Test, getU32NOP) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getU32LE(&in), in);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getU32BE(&in), in);
+ }
+}
+
+class int32Test : public AbstractGetByteSwappedTest<uint32TType, int32> {};
+INSTANTIATE_TEST_CASE_P(int32Test, int32Test,
+ ::testing::Combine(::testing::ValuesIn(uint32Values),
+ ::testing::Bool()));
+TEST_P(int32Test, swap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
+}
+TEST_P(int32Test, NOP) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
+}
+TEST_P(int32Test, typedSwap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
+}
+TEST_P(int32Test, get) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
+ }
+}
+TEST_P(int32Test, getNOP) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
+ }
+}
+
+/*
+B=8 # sizeof, bytes
+*/
+class uint64Test : public AbstractGetByteSwappedTest<uint64TType, uint64> {};
+INSTANTIATE_TEST_CASE_P(uint64Test, uint64Test,
+ ::testing::Combine(::testing::ValuesIn(uint64Values),
+ ::testing::Bool()));
+TEST_P(uint64Test, swap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
+}
+TEST_P(uint64Test, NOP) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
+}
+TEST_P(uint64Test, typedSwap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
+}
+TEST_P(uint64Test, get) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
+ }
+}
+TEST_P(uint64Test, getNOP) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
+ }
+}
+
+class floatTest : public AbstractGetByteSwappedTest<uint32TType, float> {};
+INSTANTIATE_TEST_CASE_P(floatTest, floatTest,
+ ::testing::Combine(::testing::ValuesIn(uint32Values),
+ ::testing::Bool()));
+TEST_P(floatTest, swap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
+}
+TEST_P(floatTest, NOP) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
+}
+TEST_P(floatTest, typedSwap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
+}
+TEST_P(floatTest, get) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
+ }
+}
+TEST_P(floatTest, getNOP) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
+ }
+}
+
+class doubleTest : public AbstractGetByteSwappedTest<uint64TType, double> {};
+INSTANTIATE_TEST_CASE_P(doubleTest, doubleTest,
+ ::testing::Combine(::testing::ValuesIn(uint64Values),
+ ::testing::Bool()));
+TEST_P(doubleTest, swap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwapped(in), expected);
+}
+TEST_P(doubleTest, NOP) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, false), in);
+}
+TEST_P(doubleTest, typedSwap) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getByteSwappedT(&in, true), expected);
+}
+TEST_P(doubleTest, get) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), expected);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), expected);
+ }
+}
+TEST_P(doubleTest, getNOP) {
+ if (getHostEndianness() == Endianness::little) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getLEt(&in), in);
+ } else if (getHostEndianness() == Endianness::big) {
+ ASSERT_PRED_FORMAT2(HexEquals{}, getBEt(&in), in);
+ }
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/io/EndiannessTest.h b/src/external/rawspeed/test/librawspeed/io/EndiannessTest.h
new file mode 100644
index 000000000..9a47ba949
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/io/EndiannessTest.h
@@ -0,0 +1,500 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#pragma once
+
+#include "common/Common.h" // for int32, short16, uint32, uint64, ushort16
+#include <gmock/gmock.h> // for make_tuple, tuple
+
+using rawspeed::uint32;
+using rawspeed::uint64;
+using rawspeed::ushort16;
+
+namespace rawspeed_test {
+
+template <typename T> struct intPair {
+ T first;
+ T second;
+};
+
+using ushort16Type = intPair<ushort16>;
+using ushort16TType = std::tr1::tuple<ushort16Type, bool>;
+static const ushort16Type ushort16Values[] = {
+ {0x01cd, 0xcd01}, {0x024e, 0x4e02}, {0x0726, 0x2607}, {0x07e3, 0xe307},
+ {0x0857, 0x5708}, {0x0a0c, 0x0c0a}, {0x0a3c, 0x3c0a}, {0x0a5a, 0x5a0a},
+ {0x0aac, 0xac0a}, {0x0bbb, 0xbb0b}, {0x0cf3, 0xf30c}, {0x0d13, 0x130d},
+ {0x0d6f, 0x6f0d}, {0x0d7f, 0x7f0d}, {0x0ed6, 0xd60e}, {0x0f8c, 0x8c0f},
+ {0x0f9f, 0x9f0f}, {0x103c, 0x3c10}, {0x10bc, 0xbc10}, {0x11c1, 0xc111},
+ {0x1351, 0x5113}, {0x148a, 0x8a14}, {0x15a4, 0xa415}, {0x17f6, 0xf617},
+ {0x1886, 0x8618}, {0x19b8, 0xb819}, {0x19e8, 0xe819}, {0x1a5e, 0x5e1a},
+ {0x1b26, 0x261b}, {0x1c84, 0x841c}, {0x1c97, 0x971c}, {0x1f0b, 0x0b1f},
+ {0x1f69, 0x691f}, {0x1f9c, 0x9c1f}, {0x2170, 0x7021}, {0x21a2, 0xa221},
+ {0x230c, 0x0c23}, {0x233f, 0x3f23}, {0x2382, 0x8223}, {0x240e, 0x0e24},
+ {0x24ae, 0xae24}, {0x2686, 0x8626}, {0x26cc, 0xcc26}, {0x276a, 0x6a27},
+ {0x29f1, 0xf129}, {0x2a34, 0x342a}, {0x2a37, 0x372a}, {0x2b05, 0x052b},
+ {0x2b80, 0x802b}, {0x2e02, 0x022e}, {0x2f35, 0x352f}, {0x301e, 0x1e30},
+ {0x3081, 0x8130}, {0x3395, 0x9533}, {0x342f, 0x2f34}, {0x34f4, 0xf434},
+ {0x3644, 0x4436}, {0x37f7, 0xf737}, {0x38e0, 0xe038}, {0x3bac, 0xac3b},
+ {0x3c1d, 0x1d3c}, {0x3c31, 0x313c}, {0x3cef, 0xef3c}, {0x3d99, 0x993d},
+ {0x3e11, 0x113e}, {0x3e90, 0x903e}, {0x3e9f, 0x9f3e}, {0x3fe1, 0xe13f},
+ {0x40a6, 0xa640}, {0x41b1, 0xb141}, {0x44bc, 0xbc44}, {0x456f, 0x6f45},
+ {0x49cb, 0xcb49}, {0x4a07, 0x074a}, {0x4a20, 0x204a}, {0x4b76, 0x764b},
+ {0x4d71, 0x714d}, {0x4e50, 0x504e}, {0x4e8d, 0x8d4e}, {0x4eda, 0xda4e},
+ {0x5089, 0x8950}, {0x5125, 0x2551}, {0x5177, 0x7751}, {0x5416, 0x1654},
+ {0x5438, 0x3854}, {0x5490, 0x9054}, {0x5596, 0x9655}, {0x5599, 0x9955},
+ {0x569b, 0x9b56}, {0x57ef, 0xef57}, {0x584c, 0x4c58}, {0x59a0, 0xa059},
+ {0x5ba9, 0xa95b}, {0x5be3, 0xe35b}, {0x5c2c, 0x2c5c}, {0x5c83, 0x835c},
+ {0x5db2, 0xb25d}, {0x5dc9, 0xc95d}, {0x5e11, 0x115e}, {0x5f65, 0x655f},
+ {0x6043, 0x4360}, {0x60d7, 0xd760}, {0x65eb, 0xeb65}, {0x6635, 0x3566},
+ {0x666c, 0x6c66}, {0x6735, 0x3567}, {0x6a99, 0x996a}, {0x6b31, 0x316b},
+ {0x6bb4, 0xb46b}, {0x6dd4, 0xd46d}, {0x6e40, 0x406e}, {0x7117, 0x1771},
+ {0x711d, 0x1d71}, {0x7134, 0x3471}, {0x713c, 0x3c71}, {0x7162, 0x6271},
+ {0x7602, 0x0276}, {0x76c5, 0xc576}, {0x78ab, 0xab78}, {0x793f, 0x3f79},
+ {0x7945, 0x4579}, {0x7955, 0x5579}, {0x7c1d, 0x1d7c}, {0x7e01, 0x017e},
+ {0x7e74, 0x747e}, {0x7f95, 0x957f}, {0x7fa8, 0xa87f}, {0x7fbd, 0xbd7f},
+ {0x8123, 0x2381}, {0x816d, 0x6d81}, {0x82b1, 0xb182}, {0x847c, 0x7c84},
+ {0x8555, 0x5585}, {0x8626, 0x2686}, {0x8641, 0x4186}, {0x86e9, 0xe986},
+ {0x87ec, 0xec87}, {0x8860, 0x6088}, {0x8884, 0x8488}, {0x88ea, 0xea88},
+ {0x89bc, 0xbc89}, {0x8a42, 0x428a}, {0x8b55, 0x558b}, {0x8dde, 0xde8d},
+ {0x8df1, 0xf18d}, {0x8e2f, 0x2f8e}, {0x8f3b, 0x3b8f}, {0x91ed, 0xed91},
+ {0x9265, 0x6592}, {0x9287, 0x8792}, {0x9407, 0x0794}, {0x96c6, 0xc696},
+ {0x975d, 0x5d97}, {0x987d, 0x7d98}, {0x9918, 0x1899}, {0x9935, 0x3599},
+ {0x9969, 0x6999}, {0x9a4a, 0x4a9a}, {0xa04f, 0x4fa0}, {0xa06a, 0x6aa0},
+ {0xa258, 0x58a2}, {0xa357, 0x57a3}, {0xa88a, 0x8aa8}, {0xaa27, 0x27aa},
+ {0xac3d, 0x3dac}, {0xada1, 0xa1ad}, {0xaf2c, 0x2caf}, {0xaf6e, 0x6eaf},
+ {0xb0a3, 0xa3b0}, {0xb0ec, 0xecb0}, {0xb34a, 0x4ab3}, {0xb4d3, 0xd3b4},
+ {0xb632, 0x32b6}, {0xb7ec, 0xecb7}, {0xb91d, 0x1db9}, {0xb9f6, 0xf6b9},
+ {0xba9b, 0x9bba}, {0xbab6, 0xb6ba}, {0xbc3c, 0x3cbc}, {0xbdc5, 0xc5bd},
+ {0xbff8, 0xf8bf}, {0xc04f, 0x4fc0}, {0xc06b, 0x6bc0}, {0xc189, 0x89c1},
+ {0xc2e3, 0xe3c2}, {0xc2fb, 0xfbc2}, {0xc344, 0x44c3}, {0xc380, 0x80c3},
+ {0xc3d8, 0xd8c3}, {0xc3fe, 0xfec3}, {0xc431, 0x31c4}, {0xc584, 0x84c5},
+ {0xc67e, 0x7ec6}, {0xc683, 0x83c6}, {0xc7a1, 0xa1c7}, {0xc8db, 0xdbc8},
+ {0xca27, 0x27ca}, {0xca43, 0x43ca}, {0xcc59, 0x59cc}, {0xcd3a, 0x3acd},
+ {0xcee1, 0xe1ce}, {0xd05c, 0x5cd0}, {0xd149, 0x49d1}, {0xd1cd, 0xcdd1},
+ {0xd1d6, 0xd6d1}, {0xd280, 0x80d2}, {0xd3fd, 0xfdd3}, {0xd4a3, 0xa3d4},
+ {0xd532, 0x32d5}, {0xd61c, 0x1cd6}, {0xd6ff, 0xffd6}, {0xd703, 0x03d7},
+ {0xd844, 0x44d8}, {0xd8b7, 0xb7d8}, {0xdd71, 0x71dd}, {0xdeca, 0xcade},
+ {0xdfff, 0xffdf}, {0xe069, 0x69e0}, {0xe0b5, 0xb5e0}, {0xe12c, 0x2ce1},
+ {0xe1f9, 0xf9e1}, {0xe3da, 0xdae3}, {0xe489, 0x89e4}, {0xe564, 0x64e5},
+ {0xe61e, 0x1ee6}, {0xe73a, 0x3ae7}, {0xe7c9, 0xc9e7}, {0xe86a, 0x6ae8},
+ {0xe8b4, 0xb4e8}, {0xe8c0, 0xc0e8}, {0xe932, 0x32e9}, {0xe94c, 0x4ce9},
+ {0xe985, 0x85e9}, {0xebe0, 0xe0eb}, {0xed8f, 0x8fed}, {0xedea, 0xeaed},
+ {0xeee1, 0xe1ee}, {0xf09f, 0x9ff0}, {0xf136, 0x36f1}, {0xf18a, 0x8af1},
+ {0xf26d, 0x6df2}, {0xf2b6, 0xb6f2}, {0xf345, 0x45f3}, {0xf34b, 0x4bf3},
+ {0xf461, 0x61f4}, {0xf57d, 0x7df5}, {0xf640, 0x40f6}, {0xf6cc, 0xccf6},
+ {0xf78b, 0x8bf7}, {0xf7fa, 0xfaf7}, {0xf80a, 0x0af8}, {0xf85a, 0x5af8},
+ {0xf9d1, 0xd1f9}, {0xfbbf, 0xbffb}, {0xfd7d, 0x7dfd}, {0xffd4, 0xd4ff},
+};
+
+using uint32Type = intPair<uint32>;
+using uint32TType = std::tr1::tuple<uint32Type, bool>;
+static const uint32Type uint32Values[] = {
+ {0x017c2230, 0x30227c01}, {0x03b26f3a, 0x3a6fb203},
+ {0x03e67a66, 0x667ae603}, {0x073bac8d, 0x8dac3b07},
+ {0x083548ff, 0xff483508}, {0x086d9c35, 0x359c6d08},
+ {0x0a0c7e14, 0x147e0c0a}, {0x0a43bd7f, 0x7fbd430a},
+ {0x0a4aa774, 0x74a74a0a}, {0x0a4ca277, 0x77a24c0a},
+ {0x0a4f5e46, 0x465e4f0a}, {0x0a56b2bd, 0xbdb2560a},
+ {0x0a585294, 0x9452580a}, {0x0a7b114f, 0x4f117b0a},
+ {0x0ad63f3f, 0x3f3fd60a}, {0x0afd75ae, 0xae75fd0a},
+ {0x0b50fb02, 0x02fb500b}, {0x0bd9cbb9, 0xb9cbd90b},
+ {0x0e12d601, 0x01d6120e}, {0x0ed6c038, 0x38c0d60e},
+ {0x0f02fa25, 0x25fa020f}, {0x0f80c62f, 0x2fc6800f},
+ {0x0f9bbe2a, 0x2abe9b0f}, {0x14b2b4f5, 0xf5b4b214},
+ {0x1523f71d, 0x1df72315}, {0x15684694, 0x94466815},
+ {0x194b997a, 0x7a994b19}, {0x1af3979e, 0x9e97f31a},
+ {0x1bfd7894, 0x9478fd1b}, {0x1c9611ae, 0xae11961c},
+ {0x1cd1785f, 0x5f78d11c}, {0x1d3ee80d, 0x0de83e1d},
+ {0x1da86c0b, 0x0b6ca81d}, {0x1fae3cb9, 0xb93cae1f},
+ {0x20df5efe, 0xfe5edf20}, {0x210997be, 0xbe970921},
+ {0x21cd7ae3, 0xe37acd21}, {0x21fb9775, 0x7597fb21},
+ {0x22dc2cd5, 0xd52cdc22}, {0x23e9e0a8, 0xa8e0e923},
+ {0x24e8669f, 0x9f66e824}, {0x282699c0, 0xc0992628},
+ {0x28e94546, 0x4645e928}, {0x2948ef2a, 0x2aef4829},
+ {0x2c9f2f17, 0x172f9f2c}, {0x2db88075, 0x7580b82d},
+ {0x30042359, 0x59230430}, {0x30a2f205, 0x05f2a230},
+ {0x31c7ee2b, 0x2beec731}, {0x329655bf, 0xbf559632},
+ {0x33304931, 0x31493033}, {0x34cccad7, 0xd7cacc34},
+ {0x357c34b2, 0xb2347c35}, {0x35a818d0, 0xd018a835},
+ {0x36f5c876, 0x76c8f536}, {0x37b630b6, 0xb630b637},
+ {0x37e5826d, 0x6d82e537}, {0x383af2f6, 0xf6f23a38},
+ {0x38471a89, 0x891a4738}, {0x38904dc6, 0xc64d9038},
+ {0x389b69ea, 0xea699b38}, {0x390a6483, 0x83640a39},
+ {0x390fa869, 0x69a80f39}, {0x39f85247, 0x4752f839},
+ {0x3b80e806, 0x06e8803b}, {0x3b92c347, 0x47c3923b},
+ {0x3be3cde2, 0xe2cde33b}, {0x3e7dadc2, 0xc2ad7d3e},
+ {0x40ac7fd8, 0xd87fac40}, {0x41245c52, 0x525c2441},
+ {0x412eb2a8, 0xa8b22e41}, {0x4147f184, 0x84f14741},
+ {0x41c70f0b, 0x0b0fc741}, {0x431d514a, 0x4a511d43},
+ {0x43a90da7, 0xa70da943}, {0x44096ae3, 0xe36a0944},
+ {0x463bd3fc, 0xfcd33b46}, {0x46ab0a92, 0x920aab46},
+ {0x4a0e73c2, 0xc2730e4a}, {0x4c3b01ce, 0xce013b4c},
+ {0x4d693eb5, 0xb53e694d}, {0x4d7feb28, 0x28eb7f4d},
+ {0x4da2bb30, 0x30bba24d}, {0x5092108b, 0x8b109250},
+ {0x5096b0c1, 0xc1b09650}, {0x50fe72cd, 0xcd72fe50},
+ {0x5224ad0b, 0x0bad2452}, {0x5270dbcb, 0xcbdb7052},
+ {0x52e82320, 0x2023e852}, {0x5315201d, 0x1d201553},
+ {0x531ae986, 0x86e91a53}, {0x53343945, 0x45393453},
+ {0x544b3903, 0x03394b54}, {0x545de210, 0x10e25d54},
+ {0x55905815, 0x15589055}, {0x55f983c0, 0xc083f955},
+ {0x560bfbad, 0xadfb0b56}, {0x5753da1f, 0x1fda5357},
+ {0x58b49a62, 0x629ab458}, {0x59c6f3ca, 0xcaf3c659},
+ {0x59ee2efe, 0xfe2eee59}, {0x5bcf7914, 0x1479cf5b},
+ {0x5c52d99e, 0x9ed9525c}, {0x5da3f634, 0x34f6a35d},
+ {0x5e10e9bc, 0xbce9105e}, {0x60607a86, 0x867a6060},
+ {0x612cd5d4, 0xd4d52c61}, {0x62aacaa7, 0xa7caaa62},
+ {0x660ccfa8, 0xa8cf0c66}, {0x67f47060, 0x6070f467},
+ {0x698b6c45, 0x456c8b69}, {0x6aef7c64, 0x647cef6a},
+ {0x6b453152, 0x5231456b}, {0x6b94bb91, 0x91bb946b},
+ {0x6bc47aac, 0xac7ac46b}, {0x6bceed6e, 0x6eedce6b},
+ {0x6c694728, 0x2847696c}, {0x6d778b40, 0x408b776d},
+ {0x6ded96da, 0xda96ed6d}, {0x6f79de03, 0x03de796f},
+ {0x71f6a1d0, 0xd0a1f671}, {0x73f9b3c0, 0xc0b3f973},
+ {0x74815816, 0x16588174}, {0x753f575d, 0x5d573f75},
+ {0x757b6137, 0x37617b75}, {0x77fd0a83, 0x830afd77},
+ {0x785b9401, 0x01945b78}, {0x787089a8, 0xa8897078},
+ {0x79be0e43, 0x430ebe79}, {0x7b917413, 0x1374917b},
+ {0x7bf18b58, 0x588bf17b}, {0x7dcdb302, 0x02b3cd7d},
+ {0x82ec5a87, 0x875aec82}, {0x83926954, 0x54699283},
+ {0x857a6ad5, 0xd56a7a85}, {0x85a0799d, 0x9d79a085},
+ {0x879db719, 0x19b79d87}, {0x8820a4a1, 0xa1a42088},
+ {0x88b74b21, 0x214bb788}, {0x8974811d, 0x1d817489},
+ {0x8aeb269c, 0x9c26eb8a}, {0x8b42f405, 0x05f4428b},
+ {0x8d506ac8, 0xc86a508d}, {0x8dcbfb6a, 0x6afbcb8d},
+ {0x8e647efa, 0xfa7e648e}, {0x8ec93b70, 0x703bc98e},
+ {0x9118764d, 0x4d761891}, {0x92475d45, 0x455d4792},
+ {0x93437ae3, 0xe37a4393}, {0x94b20e98, 0x980eb294},
+ {0x954d0227, 0x27024d95}, {0x95dc8a43, 0x438adc95},
+ {0x9655fb2a, 0x2afb5596}, {0x96c5b4fa, 0xfab4c596},
+ {0x96f487ed, 0xed87f496}, {0x982fe648, 0x48e62f98},
+ {0x98930651, 0x51069398}, {0x9ada9dc0, 0xc09dda9a},
+ {0x9b8c6319, 0x19638c9b}, {0x9e657cec, 0xec7c659e},
+ {0x9ec3dbb1, 0xb1dbc39e}, {0xa3083a73, 0x733a08a3},
+ {0xa32487a6, 0xa68724a3}, {0xa40da0bf, 0xbfa00da4},
+ {0xa4233c3b, 0x3b3c23a4}, {0xa7646a93, 0x936a64a7},
+ {0xa8568730, 0x308756a8}, {0xa9b030f2, 0xf230b0a9},
+ {0xa9f660c1, 0xc160f6a9}, {0xab0119a2, 0xa21901ab},
+ {0xac91d6c2, 0xc2d691ac}, {0xacb789d7, 0xd789b7ac},
+ {0xade3879f, 0x9f87e3ad}, {0xaf086606, 0x066608af},
+ {0xb14ef437, 0x37f44eb1}, {0xb1cb60b9, 0xb960cbb1},
+ {0xb48fe4a6, 0xa6e48fb4}, {0xb6799f4d, 0x4d9f79b6},
+ {0xb71d495a, 0x5a491db7}, {0xb77fe5eb, 0xebe57fb7},
+ {0xb79a6598, 0x98659ab7}, {0xb7c37103, 0x0371c3b7},
+ {0xb80c8b41, 0x418b0cb8}, {0xb9590146, 0x460159b9},
+ {0xb95ecaf9, 0xf9ca5eb9}, {0xbab967d8, 0xd867b9ba},
+ {0xbbbf70d9, 0xd970bfbb}, {0xbbcfa479, 0x79a4cfbb},
+ {0xbca2cfcc, 0xcccfa2bc}, {0xbcf738f5, 0xf538f7bc},
+ {0xbd96a958, 0x58a996bd}, {0xbddab31d, 0x1db3dabd},
+ {0xbe132bc8, 0xc82b13be}, {0xbfd7af81, 0x81afd7bf},
+ {0xbff480a9, 0xa980f4bf}, {0xc24b8277, 0x77824bc2},
+ {0xc3072fb8, 0xb82f07c3}, {0xc4483055, 0x553048c4},
+ {0xc5fd7c36, 0x367cfdc5}, {0xc6525163, 0x635152c6},
+ {0xc68ce3f9, 0xf9e38cc6}, {0xc6c38770, 0x7087c3c6},
+ {0xc7572f65, 0x652f57c7}, {0xc7a4f3b0, 0xb0f3a4c7},
+ {0xc7d8ab0f, 0x0fabd8c7}, {0xc8caa3f0, 0xf0a3cac8},
+ {0xca132aaf, 0xaf2a13ca}, {0xca693620, 0x203669ca},
+ {0xcb26d1f9, 0xf9d126cb}, {0xcc6624e8, 0xe82466cc},
+ {0xccf295dd, 0xdd95f2cc}, {0xcd0ed03c, 0x3cd00ecd},
+ {0xce6396a5, 0xa59663ce}, {0xcef2dcdc, 0xdcdcf2ce},
+ {0xd0666c0f, 0x0f6c66d0}, {0xd0a8ef77, 0x77efa8d0},
+ {0xd0e18005, 0x0580e1d0}, {0xd1131227, 0x271213d1},
+ {0xd1539fad, 0xad9f53d1}, {0xd2c5e71a, 0x1ae7c5d2},
+ {0xd3206255, 0x556220d3}, {0xd4afdc18, 0x18dcafd4},
+ {0xd4c15245, 0x4552c1d4}, {0xd5724944, 0x444972d5},
+ {0xd89e31b1, 0xb1319ed8}, {0xdad8f6d4, 0xd4f6d8da},
+ {0xdb9ce5e0, 0xe0e59cdb}, {0xdd0121ad, 0xad2101dd},
+ {0xdd4f57f2, 0xf2574fdd}, {0xde8e0c28, 0x280c8ede},
+ {0xe1f064ff, 0xff64f0e1}, {0xe3d26afe, 0xfe6ad2e3},
+ {0xe72a08a7, 0xa7082ae7}, {0xe922073f, 0x3f0722e9},
+ {0xeb6927a8, 0xa82769eb}, {0xebab7af8, 0xf87aabeb},
+ {0xedbda9d8, 0xd8a9bded}, {0xedc2a9bc, 0xbca9c2ed},
+ {0xede3584a, 0x4a58e3ed}, {0xf0d51878, 0x7818d5f0},
+ {0xf3787c22, 0x227c78f3}, {0xf59dc09f, 0x9fc09df5},
+ {0xf60b1c66, 0x661c0bf6}, {0xf610e365, 0x65e310f6},
+ {0xf6322ad1, 0xd12a32f6}, {0xf8bda761, 0x61a7bdf8},
+ {0xf8e6c9b6, 0xb6c9e6f8}, {0xf9630954, 0x540963f9},
+ {0xfac766ba, 0xba66c7fa}, {0xfb1b54ea, 0xea541bfb},
+ {0xfcb7e7d9, 0xd9e7b7fc}, {0xfccf71b3, 0xb371cffc},
+ {0xfcfcb475, 0x75b4fcfc}, {0xfd77d7ae, 0xaed777fd},
+ {0xfdb0eefe, 0xfeeeb0fd}, {0xff3ebb92, 0x92bb3eff},
+};
+
+using uint64Type = intPair<uint64>;
+using uint64TType = std::tr1::tuple<uint64Type, bool>;
+static const uint64Type uint64Values[] = {
+ {0x01a4f185910d9936, 0x36990d9185f1a401},
+ {0x030d4fdc9f4011b5, 0xb511409fdc4f0d03},
+ {0x034e6547a3d92e80, 0x802ed9a347654e03},
+ {0x0394651ebf164685, 0x854616bf1e659403},
+ {0x03dd4b0f9fc1ca71, 0x71cac19f0f4bdd03},
+ {0x03e9d20de39c5216, 0x16529ce30dd2e903},
+ {0x05ca6deedc38af4d, 0x4daf38dcee6dca05},
+ {0x061f91b0303314c5, 0xc5143330b0911f06},
+ {0x062b940f39764ae7, 0xe74a76390f942b06},
+ {0x0799815f9f363603, 0x0336369f5f819907},
+ {0x08188686d111449f, 0x9f4411d186861808},
+ {0x09d030d4db9ac970, 0x70c99adbd430d009},
+ {0x0a827ba534d1d59e, 0x9ed5d134a57b820a},
+ {0x0aa45120668481ef, 0xef8184662051a40a},
+ {0x0ab4f0f468892ece, 0xce2e8968f4f0b40a},
+ {0x0abbbbad7c590d31, 0x310d597cadbbbb0a},
+ {0x0abe2e66d9ea4544, 0x4445ead9662ebe0a},
+ {0x0ad4d44b5bf40237, 0x3702f45b4bd4d40a},
+ {0x0af7e02fcc3e02be, 0xbe023ecc2fe0f70a},
+ {0x0e4ff7b88d440627, 0x2706448db8f74f0e},
+ {0x0f69c1be2bb832ad, 0xad32b82bbec1690f},
+ {0x10016a95e40bf44b, 0x4bf40be4956a0110},
+ {0x1039cea9e9a83f0c, 0x0c3fa8e9a9ce3910},
+ {0x10beb91781ab0ce9, 0xe90cab8117b9be10},
+ {0x112d5dd48c03087f, 0x7f08038cd45d2d11},
+ {0x1189e054cb2482d2, 0xd28224cb54e08911},
+ {0x11f9318d04b95e6a, 0x6a5eb9048d31f911},
+ {0x13509dc1f31494d0, 0xd09414f3c19d5013},
+ {0x1459afd791a7e268, 0x68e2a791d7af5914},
+ {0x175f335b1017ea4d, 0x4dea17105b335f17},
+ {0x17691949526ca9e6, 0xe6a96c5249196917},
+ {0x18e124ec2093f320, 0x20f39320ec24e118},
+ {0x18ff1397e7e6986c, 0x6c98e6e79713ff18},
+ {0x1bbf3f4f5a577c52, 0x527c575a4f3fbf1b},
+ {0x1c9e1b8fa60b87e9, 0xe9870ba68f1b9e1c},
+ {0x1d7c915583bfbc78, 0x78bcbf8355917c1d},
+ {0x1e99cdb0b48d9980, 0x80998db4b0cd991e},
+ {0x1ea5c01b8f8b7816, 0x16788b8f1bc0a51e},
+ {0x1f6107b4548a673d, 0x3d678a54b407611f},
+ {0x20c50d08c7a6684f, 0x4f68a6c7080dc520},
+ {0x21392da064c68572, 0x7285c664a02d3921},
+ {0x2156f617524a061f, 0x1f064a5217f65621},
+ {0x21cb064a80b51ba5, 0xa51bb5804a06cb21},
+ {0x22fb2a22d8c2a0b0, 0xb0a0c2d8222afb22},
+ {0x24fa5c234ee38825, 0x2588e34e235cfa24},
+ {0x2566ca0de3330fad, 0xad0f33e30dca6625},
+ {0x262151de31842542, 0x42258431de512126},
+ {0x27b8f319a1286b16, 0x166b28a119f3b827},
+ {0x2809a2238c21b256, 0x56b2218c23a20928},
+ {0x281ffcb764b36097, 0x9760b364b7fc1f28},
+ {0x294b39df178cfc8f, 0x8ffc8c17df394b29},
+ {0x2ab9ff5fef04c11b, 0x1bc104ef5fffb92a},
+ {0x2de95889ee1d7cd9, 0xd97c1dee8958e92d},
+ {0x2ec9e30e8b2c9476, 0x76942c8b0ee3c92e},
+ {0x30138061f3afea92, 0x92eaaff361801330},
+ {0x3027b57c55016086, 0x866001557cb52730},
+ {0x3086abfc090e4a6b, 0x6b4a0e09fcab8630},
+ {0x309c614a4bac1694, 0x9416ac4b4a619c30},
+ {0x3313cb7e5c394f77, 0x774f395c7ecb1333},
+ {0x3365363758f35f17, 0x175ff35837366533},
+ {0x3399a7d4f02dde1f, 0x1fde2df0d4a79933},
+ {0x34951ad3ae5d377e, 0x7e375daed31a9534},
+ {0x356aa6f7bdff1fe6, 0xe61fffbdf7a66a35},
+ {0x3664912267c29f8e, 0x8e9fc26722916436},
+ {0x368411576e9172c7, 0xc772916e57118436},
+ {0x36ed7c9df3a3239f, 0x9f23a3f39d7ced36},
+ {0x3801a8e5e7ea73f5, 0xf573eae7e5a80138},
+ {0x3a8864f4923d3694, 0x94363d92f464883a},
+ {0x3ad7fff2f55cdec4, 0xc4de5cf5f2ffd73a},
+ {0x3b23fd0271a906c7, 0xc706a97102fd233b},
+ {0x3bb711498749f9e3, 0xe3f949874911b73b},
+ {0x3bffc35ce2ec236a, 0x6a23ece25cc3ff3b},
+ {0x3dcf6b55f48ec31e, 0x1ec38ef4556bcf3d},
+ {0x3f31b3fe732ce6d6, 0xd6e62c73feb3313f},
+ {0x401f685d6cb0a81a, 0x1aa8b06c5d681f40},
+ {0x407c780b3d4649d5, 0xd549463d0b787c40},
+ {0x40b1c2c975f040f9, 0xf940f075c9c2b140},
+ {0x4133e1fbe7d0aacf, 0xcfaad0e7fbe13341},
+ {0x435ebefc10138f3c, 0x3c8f1310fcbe5e43},
+ {0x43b6a5d764f3c692, 0x92c6f364d7a5b643},
+ {0x445698823bd49d53, 0x539dd43b82985644},
+ {0x490bf9bee1d4ade2, 0xe2add4e1bef90b49},
+ {0x4e8e78c6df14c97b, 0x7bc914dfc6788e4e},
+ {0x4ea96ddb55e85773, 0x7357e855db6da94e},
+ {0x4f4acba83590dc66, 0x66dc9035a8cb4a4f},
+ {0x4fb7494da864de4c, 0x4cde64a84d49b74f},
+ {0x4fce70ded4f83547, 0x4735f8d4de70ce4f},
+ {0x516bcc4cada8ef72, 0x72efa8ad4ccc6b51},
+ {0x5170b4536616aecf, 0xcfae166653b47051},
+ {0x51d4a5524239fa22, 0x22fa394252a5d451},
+ {0x534b039d23592020, 0x202059239d034b53},
+ {0x54a013b5eff937fe, 0xfe37f9efb513a054},
+ {0x564374747f5e9320, 0x20935e7f74744356},
+ {0x59f6257c4db99297, 0x9792b94d7c25f659},
+ {0x5b12226b7a7923f5, 0xf523797a6b22125b},
+ {0x5c645a3be8826925, 0x256982e83b5a645c},
+ {0x5e25a5b75eaa8c14, 0x148caa5eb7a5255e},
+ {0x5e65baefbaa0be2e, 0x2ebea0baefba655e},
+ {0x5e7139ab7cb8941d, 0x1d94b87cab39715e},
+ {0x5f58c6ed964a233e, 0x3e234a96edc6585f},
+ {0x6191c8a34b25a307, 0x07a3254ba3c89161},
+ {0x628653515914237d, 0x7d23145951538662},
+ {0x632d4b1c0e4b2bb9, 0xb92b4b0e1c4b2d63},
+ {0x635cee4d9e9a6577, 0x77659a9e4dee5c63},
+ {0x63622d88676f121e, 0x1e126f67882d6263},
+ {0x6488ed06874bd952, 0x52d94b8706ed8864},
+ {0x64bc3f236c19adcf, 0xcfad196c233fbc64},
+ {0x6530377ab7f2b733, 0x33b7f2b77a373065},
+ {0x659f41fc7754836e, 0x6e835477fc419f65},
+ {0x65aca81f1137b061, 0x61b037111fa8ac65},
+ {0x65f5429ab2cf2abd, 0xbd2acfb29a42f565},
+ {0x66b93c7aefba4763, 0x6347baef7a3cb966},
+ {0x690d9cb2484801cc, 0xcc014848b29c0d69},
+ {0x6943c26898b294e0, 0xe094b29868c24369},
+ {0x69e10b813696470b, 0x0b479636810be169},
+ {0x6ac87e6ff2526d31, 0x316d52f26f7ec86a},
+ {0x70d8c7b4205eaddd, 0xddad5e20b4c7d870},
+ {0x717193d6a6f1bc60, 0x60bcf1a6d6937171},
+ {0x721312134a9909ca, 0xca09994a13121372},
+ {0x725968e20260763c, 0x3c766002e2685972},
+ {0x7280418cd340ed7d, 0x7ded40d38c418072},
+ {0x7308f61a392c80b5, 0xb5802c391af60873},
+ {0x73d47a554321a570, 0x70a52143557ad473},
+ {0x744f93d8ff4c5bf6, 0xf65b4cffd8934f74},
+ {0x7461a306465e21bc, 0xbc215e4606a36174},
+ {0x754d57934c4babc0, 0xc0ab4b4c93574d75},
+ {0x762c38e1f7601fc3, 0xc31f60f7e1382c76},
+ {0x766d79e3448049b0, 0xb0498044e3796d76},
+ {0x76d0892bb81e870e, 0x0e871eb82b89d076},
+ {0x76ea263020f68db5, 0xb58df6203026ea76},
+ {0x77290b31f3932d28, 0x282d93f3310b2977},
+ {0x7879068099a8621d, 0x1d62a89980067978},
+ {0x79b7faadcbcd0349, 0x4903cdcbadfab779},
+ {0x7aa9ac4bef789b39, 0x399b78ef4baca97a},
+ {0x7ae44b36f053ffcd, 0xcdff53f0364be47a},
+ {0x7b825441cabc1f0d, 0x0d1fbcca4154827b},
+ {0x7bf70945622778dd, 0xdd7827624509f77b},
+ {0x7df834b00e227255, 0x5572220eb034f87d},
+ {0x7f264136067c698f, 0x8f697c063641267f},
+ {0x7fab0c5dc52772f8, 0xf87227c55d0cab7f},
+ {0x8346e40cb537d8da, 0xdad837b50ce44683},
+ {0x84d903ade1d56a57, 0x576ad5e1ad03d984},
+ {0x84ec0390c64b56c1, 0xc1564bc69003ec84},
+ {0x86ce4376b9aebbd6, 0xd6bbaeb97643ce86},
+ {0x883d8810953e1fa7, 0xa71f3e9510883d88},
+ {0x894f7e35bea2b771, 0x71b7a2be357e4f89},
+ {0x8975c06401449774, 0x7497440164c07589},
+ {0x8a18edc9fb01ff90, 0x90ff01fbc9ed188a},
+ {0x8a3dec4bbf6bda6d, 0x6dda6bbf4bec3d8a},
+ {0x8bb395de4a1f9b86, 0x869b1f4ade95b38b},
+ {0x8c0d60ee5fff18da, 0xda18ff5fee600d8c},
+ {0x8c550cf7622902a6, 0xa6022962f70c558c},
+ {0x8cc8194debe66f75, 0x756fe6eb4d19c88c},
+ {0x8e1b92c42361a254, 0x54a26123c4921b8e},
+ {0x8f8de52345ee3d21, 0x213dee4523e58d8f},
+ {0x8fbffecb6270af6b, 0x6baf7062cbfebf8f},
+ {0x90ea0823b62e880f, 0x0f882eb62308ea90},
+ {0x92662f468962f29c, 0x9cf26289462f6692},
+ {0x926901d0f7ed1fce, 0xce1fedf7d0016992},
+ {0x9315e749fe28a515, 0x15a528fe49e71593},
+ {0x939606f40438d640, 0x40d63804f4069693},
+ {0x948f46956357b440, 0x40b4576395468f94},
+ {0x9536c301a0bdec91, 0x91ecbda001c33695},
+ {0x95f0294242e26fad, 0xad6fe2424229f095},
+ {0x970313f37c9ce0fa, 0xfae09c7cf3130397},
+ {0x989228fc85ded9c1, 0xc1d9de85fc289298},
+ {0x998163bda5fcf0ae, 0xaef0fca5bd638199},
+ {0x9caac79b53bb8417, 0x1784bb539bc7aa9c},
+ {0x9d323942c1beade1, 0xe1adbec14239329d},
+ {0x9e7c9a16e12250f3, 0xf35022e1169a7c9e},
+ {0x9ebf7dbead11d95c, 0x5cd911adbe7dbf9e},
+ {0x9fababe0e0b6c8b0, 0xb0c8b6e0e0abab9f},
+ {0x9ff1a9c69196e082, 0x82e09691c6a9f19f},
+ {0xa007730aaa876cb7, 0xb76c87aa0a7307a0},
+ {0xa2cb459b5ab592f8, 0xf892b55a9b45cba2},
+ {0xa2f73480fb85402e, 0x2e4085fb8034f7a2},
+ {0xa30d1a453b6b77e5, 0xe5776b3b451a0da3},
+ {0xa401d416f27f6784, 0x84677ff216d401a4},
+ {0xa429308776e2b253, 0x53b2e276873029a4},
+ {0xa4d803a7d07f2b2f, 0x2f2b7fd0a703d8a4},
+ {0xa54d53b018fc21c8, 0xc821fc18b0534da5},
+ {0xa63d56580a2a72c7, 0xc7722a0a58563da6},
+ {0xaad06a347609e497, 0x97e40976346ad0aa},
+ {0xab06de977342760d, 0x0d76427397de06ab},
+ {0xab3bb77752b628a0, 0xa028b65277b73bab},
+ {0xacdf898a38b460a7, 0xa760b4388a89dfac},
+ {0xade7cc5f5fe5a0c8, 0xc8a0e55f5fcce7ad},
+ {0xb14b0d504edb3f8c, 0x8c3fdb4e500d4bb1},
+ {0xb232f7ee5c528f45, 0x458f525ceef732b2},
+ {0xb29637a20e7e3f81, 0x813f7e0ea23796b2},
+ {0xb38c6e3cdf9ba152, 0x52a19bdf3c6e8cb3},
+ {0xb3c4acd895f12b75, 0x752bf195d8acc4b3},
+ {0xb45dd693e679afcd, 0xcdaf79e693d65db4},
+ {0xb5bd1db701b042b0, 0xb042b001b71dbdb5},
+ {0xb7ffb94cbaea0ef6, 0xf60eeaba4cb9ffb7},
+ {0xb8ddd9a40f4efbdf, 0xdffb4e0fa4d9ddb8},
+ {0xb926e8b8305fec2e, 0x2eec5f30b8e826b9},
+ {0xbdcfe40f78253b24, 0x243b25780fe4cfbd},
+ {0xbe40f3bcf40bf171, 0x71f10bf4bcf340be},
+ {0xbf4e2a36e2d46283, 0x8362d4e2362a4ebf},
+ {0xbf9e21521b9b43c2, 0xc2439b1b52219ebf},
+ {0xbfcc7ced3487e368, 0x68e38734ed7cccbf},
+ {0xc0133885bd296b9a, 0x9a6b29bd853813c0},
+ {0xc0197e36b07e7145, 0x45717eb0367e19c0},
+ {0xc19ed11ea3cffb6c, 0x6cfbcfa31ed19ec1},
+ {0xc1ed5cc50cef774a, 0x4a77ef0cc55cedc1},
+ {0xc27efde16bdde140, 0x40e1dd6be1fd7ec2},
+ {0xc2aa6b042ee4cded, 0xedcde42e046baac2},
+ {0xc2e3eba06e144f23, 0x234f146ea0ebe3c2},
+ {0xc30d5d2b67b158c0, 0xc058b1672b5d0dc3},
+ {0xc456ce9b1532239a, 0x9a2332159bce56c4},
+ {0xc92318a13cc869ed, 0xed69c83ca11823c9},
+ {0xcd03c29b85ac0f51, 0x510fac859bc203cd},
+ {0xcd4935b4d1f19823, 0x2398f1d1b43549cd},
+ {0xcd6a0bcc1ddc68bc, 0xbc68dc1dcc0b6acd},
+ {0xd3df6eae2cb71b0f, 0x0f1bb72cae6edfd3},
+ {0xd959c11f9b6e1786, 0x86176e9b1fc159d9},
+ {0xd9b6129539584836, 0x364858399512b6d9},
+ {0xdaead34f9651d94d, 0x4dd951964fd3eada},
+ {0xdba30f72797dae40, 0x40ae7d79720fa3db},
+ {0xdd26cf916d9ed027, 0x27d09e6d91cf26dd},
+ {0xdd49602f244ab833, 0x33b84a242f6049dd},
+ {0xdd6f6fc311660caf, 0xaf0c6611c36f6fdd},
+ {0xdf71698f5ff67735, 0x3577f65f8f6971df},
+ {0xdfef90e381731cc2, 0xc21c7381e390efdf},
+ {0xe076fbdea35a9215, 0x15925aa3defb76e0},
+ {0xe0c44511b6717d8e, 0x8e7d71b61145c4e0},
+ {0xe14f9d6f913cb3d9, 0xd9b33c916f9d4fe1},
+ {0xe39f9f95fd7e0707, 0x07077efd959f9fe3},
+ {0xe45f2c9e27dc3a11, 0x113adc279e2c5fe4},
+ {0xe55bae3a898e9e19, 0x199e8e893aae5be5},
+ {0xe6cdf556fca755e8, 0xe855a7fc56f5cde6},
+ {0xe6dd5a9baa49d3aa, 0xaad349aa9b5adde6},
+ {0xe98fe0160a8ce894, 0x94e88c0a16e08fe9},
+ {0xe9dd4fb7fd255204, 0x045225fdb74fdde9},
+ {0xeaf1abf8bb2fa6c3, 0xc3a62fbbf8abf1ea},
+ {0xebab04ef72681416, 0x16146872ef04abeb},
+ {0xebdcbbd249fe49ed, 0xed49fe49d2bbdceb},
+ {0xecac354fc5677c11, 0x117c67c54f35acec},
+ {0xee76789b082ef12c, 0x2cf12e089b7876ee},
+ {0xeebc2d1760e11cb6, 0xb61ce160172dbcee},
+ {0xeed834dc595bd60b, 0x0bd65b59dc34d8ee},
+ {0xef7b81db37575495, 0x95545737db817bef},
+ {0xef9482206a4a5a75, 0x755a4a6a208294ef},
+ {0xf11261a29cda20a4, 0xa420da9ca26112f1},
+ {0xf1779ea083d21789, 0x8917d283a09e77f1},
+ {0xf266952c773053dc, 0xdc5330772c9566f2},
+ {0xf41c9d6e916f2551, 0x51256f916e9d1cf4},
+ {0xf4a478e553d71be6, 0xe61bd753e578a4f4},
+ {0xf4b123aabaa79823, 0x2398a7baaa23b1f4},
+ {0xf66b6522552d7936, 0x36792d5522656bf6},
+ {0xf89456378f4817a1, 0xa117488f375694f8},
+ {0xf97d21e5ea0470ef, 0xef7004eae5217df9},
+ {0xf9c8bddb1667ee10, 0x10ee6716dbbdc8f9},
+ {0xfb4ee3defb5f3a2b, 0x2b3a5ffbdee34efb},
+ {0xfe7280e85ee3f665, 0x65f6e35ee88072fe},
+};
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/metadata/BlackAreaTest.cpp b/src/external/rawspeed/test/librawspeed/metadata/BlackAreaTest.cpp
new file mode 100644
index 000000000..3b5be0df2
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/metadata/BlackAreaTest.cpp
@@ -0,0 +1,204 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2016 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "metadata/BlackArea.h" // for BlackArea
+#include <gtest/gtest.h> // for IsNullLiteralHelper, AssertionResult, gtest_ar
+#include <memory> // for unique_ptr
+
+using rawspeed::BlackArea;
+using std::unique_ptr;
+
+namespace rawspeed_test {
+
+class BlackAreaTest
+ : public ::testing::TestWithParam<std::tr1::tuple<int, int, bool>> {
+protected:
+ BlackAreaTest() = default;
+ virtual void SetUp() override {
+ offset = std::tr1::get<0>(GetParam());
+ size = std::tr1::get<1>(GetParam());
+ isVertical = std::tr1::get<2>(GetParam());
+ }
+
+ void checkHelper(const BlackArea& a) {
+ ASSERT_EQ(a.offset, offset);
+ ASSERT_EQ(a.size, size);
+ ASSERT_EQ(a.isVertical, isVertical);
+ }
+
+ void checkHelper(const BlackArea& a, const BlackArea& b) {
+ ASSERT_EQ(a.offset, b.offset);
+ ASSERT_EQ(a.size, b.size);
+ ASSERT_EQ(a.isVertical, b.isVertical);
+ }
+
+ int offset{0}; // Offset in bayer pixels.
+ int size{0}; // Size in bayer pixels.
+ bool isVertical{false}; // Otherwise horizontal
+};
+
+INSTANTIATE_TEST_CASE_P(BlackAreas, BlackAreaTest,
+ testing::Combine(testing::Range(0, 1000, 250), // offset
+ testing::Range(0, 1000, 250), // size
+ testing::Bool() // isVertical
+ ));
+
+TEST_P(BlackAreaTest, Constructor) {
+ ASSERT_NO_THROW({ BlackArea Area(offset, size, isVertical); });
+
+ ASSERT_NO_THROW(
+ { unique_ptr<BlackArea> Area(new BlackArea(offset, size, isVertical)); });
+}
+
+TEST_P(BlackAreaTest, Getters) {
+ {
+ const BlackArea Area(offset, size, isVertical);
+
+ checkHelper(Area);
+ }
+
+ {
+ const unique_ptr<const BlackArea> Area(
+ new BlackArea(offset, size, isVertical));
+
+ checkHelper(*Area);
+ }
+}
+
+TEST_P(BlackAreaTest, AssignmentConstructor) {
+ ASSERT_NO_THROW({
+ const BlackArea AreaOrig(offset, size, isVertical);
+ BlackArea Area(AreaOrig); // NOLINT trying to test the copy
+ checkHelper(AreaOrig);
+ checkHelper(Area);
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const BlackArea> AreaOrig(
+ new BlackArea(offset, size, isVertical));
+ unique_ptr<BlackArea> Area(new BlackArea(*AreaOrig));
+ checkHelper(*AreaOrig);
+ checkHelper(*Area);
+ });
+
+ ASSERT_NO_THROW({
+ const BlackArea AreaOrig(offset, size, isVertical);
+ unique_ptr<BlackArea> Area(new BlackArea(AreaOrig));
+ checkHelper(AreaOrig);
+ checkHelper(*Area);
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const BlackArea> AreaOrig(
+ new BlackArea(offset, size, isVertical));
+ BlackArea Area(*AreaOrig);
+ checkHelper(*AreaOrig);
+ checkHelper(Area);
+ });
+}
+
+TEST_P(BlackAreaTest, AssignmentConstructorGetters) {
+ {
+ const BlackArea AreaOrig(offset, size, isVertical);
+ BlackArea Area(AreaOrig);
+
+ checkHelper(Area);
+ checkHelper(Area, AreaOrig);
+ }
+}
+
+TEST_P(BlackAreaTest, Assignment) {
+ ASSERT_NO_THROW({
+ const BlackArea AreaOrig(offset, size, isVertical);
+ BlackArea Area(0, 0, false);
+
+ Area = AreaOrig;
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const BlackArea> AreaOrig(
+ new BlackArea(offset, size, isVertical));
+ unique_ptr<BlackArea> Area(new BlackArea(0, 0, false));
+
+ *Area = *AreaOrig;
+ });
+
+ ASSERT_NO_THROW({
+ const BlackArea AreaOrig(offset, size, isVertical);
+ unique_ptr<BlackArea> Area(new BlackArea(0, 0, false));
+
+ *Area = AreaOrig;
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const BlackArea> AreaOrig(
+ new BlackArea(offset, size, isVertical));
+ BlackArea Area(0, 0, false);
+
+ Area = *AreaOrig;
+ });
+}
+
+TEST_P(BlackAreaTest, AssignmentGetters) {
+ ASSERT_NO_THROW({
+ const BlackArea AreaOrig(offset, size, isVertical);
+ BlackArea Area(0, 0, false);
+
+ Area = AreaOrig;
+
+ checkHelper(Area);
+ checkHelper(Area, AreaOrig);
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const BlackArea> AreaOrig(
+ new BlackArea(offset, size, isVertical));
+ unique_ptr<BlackArea> Area(new BlackArea(0, 0, false));
+
+ *Area = *AreaOrig;
+
+ checkHelper(*Area);
+ checkHelper(*Area, *AreaOrig);
+ });
+
+ ASSERT_NO_THROW({
+ const BlackArea AreaOrig(offset, size, isVertical);
+ unique_ptr<BlackArea> Area(new BlackArea(0, 0, false));
+
+ *Area = AreaOrig;
+
+ checkHelper(*Area);
+ checkHelper(*Area, AreaOrig);
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const BlackArea> AreaOrig(
+ new BlackArea(offset, size, isVertical));
+ BlackArea Area(0, 0, false);
+
+ Area = *AreaOrig;
+
+ checkHelper(Area);
+ checkHelper(Area, *AreaOrig);
+ });
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/metadata/CMakeLists.txt b/src/external/rawspeed/test/librawspeed/metadata/CMakeLists.txt
new file mode 100644
index 000000000..7895ad08d
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/metadata/CMakeLists.txt
@@ -0,0 +1,11 @@
+FILE(GLOB RAWSPEED_TEST_SOURCES
+ "BlackAreaTest.cpp"
+ "CameraMetaDataTest.cpp"
+ "CameraSensorInfoTest.cpp"
+ "CameraTest.cpp"
+ "ColorFilterArrayTest.cpp"
+)
+
+foreach(IN ${RAWSPEED_TEST_SOURCES})
+ add_rs_test(${IN})
+endforeach()
diff --git a/src/external/rawspeed/test/librawspeed/metadata/CameraMetaDataTest.cpp b/src/external/rawspeed/test/librawspeed/metadata/CameraMetaDataTest.cpp
new file mode 100644
index 000000000..076fcca2e
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/metadata/CameraMetaDataTest.cpp
@@ -0,0 +1,83 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2016 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "rawspeedconfig.h" // for CMAKE_SOURCE_DIR
+
+#include "metadata/Camera.h" // for Camera
+#include "metadata/CameraMetaData.h" // for CameraMetaData
+#include <gtest/gtest.h> // for Test, ASSERT_NO_THROW, GetTestTypeId
+#include <memory> // for unique_ptr
+#include <string> // for string
+
+using rawspeed::CameraMetaData;
+using std::unique_ptr;
+
+namespace rawspeed_test {
+
+#ifdef HAVE_PUGIXML
+
+static const std::string camfile(CMAKE_SOURCE_DIR "/data/cameras.xml");
+
+TEST(CameraMetaDataTest, CamerasXml) {
+ ASSERT_NO_THROW({ CameraMetaData Data(camfile.c_str()); });
+
+ ASSERT_NO_THROW({
+ unique_ptr<CameraMetaData> Data(new CameraMetaData(camfile.c_str()));
+ });
+}
+
+TEST(CameraMetaDataTest, PrefixSearch) {
+ ASSERT_NO_THROW({
+ CameraMetaData Data(camfile.c_str());
+
+ const auto* d3 =
+ Data.getCamera("NIKON CORPORATION", "NIKON D3", "14bit-compressed");
+ ASSERT_NE(nullptr, d3);
+ ASSERT_EQ("D3", d3->canonical_model);
+
+ ASSERT_EQ(nullptr,
+ Data.getCamera("NIKON CORPORATION", "NIKON D3",
+ "14bit-compressed-with-some-bogus-prefix"));
+ ASSERT_EQ(nullptr, Data.getCamera("NIKON CORPORATION",
+ "NIKON D3-with-some-bogus-prefix",
+ "14bit-compressed"));
+ ASSERT_EQ(nullptr,
+ Data.getCamera("NIKON CORPORATION-with-some-bogus-prefix",
+ "NIKON D3", "14bit-compressed"));
+
+ d3 = Data.getCamera("NIKON CORPORATION", "NIKON D3");
+ ASSERT_NE(nullptr, d3);
+ ASSERT_EQ("D3", d3->canonical_model);
+
+ ASSERT_EQ(nullptr, Data.getCamera("NIKON CORPORATION",
+ "NIKON D3-with-some-bogus-prefix"));
+ ASSERT_EQ(
+ nullptr,
+ Data.getCamera("NIKON CORPORATION-with-some-bogus-prefix", "NIKON D3"));
+ ASSERT_EQ(nullptr,
+ Data.getCamera("NIKON CORPORATION-with-some-bogus-prefix",
+ "NIKON D3-with-some-bogus-prefix"));
+ });
+}
+
+#endif
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/metadata/CameraSensorInfoTest.cpp b/src/external/rawspeed/test/librawspeed/metadata/CameraSensorInfoTest.cpp
new file mode 100644
index 000000000..2a7de669f
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/metadata/CameraSensorInfoTest.cpp
@@ -0,0 +1,320 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2016 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "metadata/CameraSensorInfo.h" // for CameraSensorInfo
+#include <algorithm> // for generate
+#include <cstdlib> // for rand, srand
+#include <gmock/gmock.h> // for get, InitGoogleMock, tuple
+#include <gtest/gtest.h> // for IsNullLiteralHelper, AssertionResult
+#include <iostream> // for operator<<, basic_ostream::operator<<
+#include <limits> // for numeric_limits
+#include <memory> // for unique_ptr
+#include <vector> // for vector, allocator
+
+using rawspeed::CameraSensorInfo;
+using std::unique_ptr;
+
+namespace rawspeed_test {
+
+std::vector<int> ISOList(6);
+
+class CameraSensorInfoTestDumb
+ : public ::testing::TestWithParam<std::tr1::tuple<int, int>> {
+protected:
+ CameraSensorInfoTestDumb()
+ : mBlackLevel(std::rand()), // NOLINT do not need crypto-level randomness
+ mWhiteLevel(std::rand()), // NOLINT do not need crypto-level randomness
+ mBlackLevelSeparate({
+ std::rand(), // NOLINT do not need crypto-level randomness
+ std::rand(), // NOLINT do not need crypto-level randomness
+ std::rand(), // NOLINT do not need crypto-level randomness
+ std::rand() // NOLINT do not need crypto-level randomness
+ }) {}
+ virtual void SetUp() override {
+ mMinIso = std::tr1::get<0>(GetParam());
+ mMaxIso = std::tr1::get<1>(GetParam());
+ }
+
+ void checkHelper(const CameraSensorInfo& csi) {
+ ASSERT_EQ(csi.mBlackLevel, mBlackLevel);
+ ASSERT_EQ(csi.mWhiteLevel, mWhiteLevel);
+ ASSERT_EQ(csi.mMinIso, mMinIso);
+ ASSERT_EQ(csi.mMaxIso, mMaxIso);
+ ASSERT_EQ(csi.mBlackLevelSeparate, mBlackLevelSeparate);
+ }
+
+ void checkHelper(const CameraSensorInfo& a, const CameraSensorInfo& b) {
+ ASSERT_EQ(a.mBlackLevel, b.mBlackLevel);
+ ASSERT_EQ(a.mWhiteLevel, b.mWhiteLevel);
+ ASSERT_EQ(a.mMinIso, b.mMinIso);
+ ASSERT_EQ(a.mMaxIso, b.mMaxIso);
+ ASSERT_EQ(a.mBlackLevelSeparate, b.mBlackLevelSeparate);
+ }
+
+ int mBlackLevel;
+ int mWhiteLevel;
+ int mMinIso{-1};
+ int mMaxIso{-1};
+ std::vector<int> mBlackLevelSeparate;
+};
+
+INSTANTIATE_TEST_CASE_P(MinMax, CameraSensorInfoTestDumb,
+ testing::Combine(testing::ValuesIn(ISOList), // min iso
+ testing::ValuesIn(ISOList) // max iso
+ ));
+
+TEST_P(CameraSensorInfoTestDumb, Constructor) {
+ ASSERT_NO_THROW({
+ CameraSensorInfo Info(mBlackLevel, mWhiteLevel, mMinIso, mMaxIso,
+ mBlackLevelSeparate);
+ });
+
+ ASSERT_NO_THROW({
+ unique_ptr<CameraSensorInfo> Info(new CameraSensorInfo(
+ mBlackLevel, mWhiteLevel, mMinIso, mMaxIso, mBlackLevelSeparate));
+ });
+}
+
+TEST_P(CameraSensorInfoTestDumb, Getters) {
+ {
+ const CameraSensorInfo Info(mBlackLevel, mWhiteLevel, mMinIso, mMaxIso,
+ mBlackLevelSeparate);
+
+ checkHelper(Info);
+ }
+
+ {
+ const unique_ptr<const CameraSensorInfo> Info(new CameraSensorInfo(
+ mBlackLevel, mWhiteLevel, mMinIso, mMaxIso, mBlackLevelSeparate));
+
+ checkHelper(*Info);
+ }
+}
+
+TEST_P(CameraSensorInfoTestDumb, AssignmentConstructor) {
+ ASSERT_NO_THROW({
+ const CameraSensorInfo InfoOrig(mBlackLevel, mWhiteLevel, mMinIso, mMaxIso,
+ mBlackLevelSeparate);
+ CameraSensorInfo Info(InfoOrig); // NOLINT trying to test the copy
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const CameraSensorInfo> InfoOrig(new CameraSensorInfo(
+ mBlackLevel, mWhiteLevel, mMinIso, mMaxIso, mBlackLevelSeparate));
+ unique_ptr<CameraSensorInfo> Info(new CameraSensorInfo(*InfoOrig));
+ });
+
+ ASSERT_NO_THROW({
+ const CameraSensorInfo InfoOrig(mBlackLevel, mWhiteLevel, mMinIso, mMaxIso,
+ mBlackLevelSeparate);
+ unique_ptr<CameraSensorInfo> Info(new CameraSensorInfo(InfoOrig));
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const CameraSensorInfo> InfoOrig(new CameraSensorInfo(
+ mBlackLevel, mWhiteLevel, mMinIso, mMaxIso, mBlackLevelSeparate));
+ CameraSensorInfo Info(*InfoOrig);
+ });
+}
+
+TEST_P(CameraSensorInfoTestDumb, AssignmentConstructorGetters) {
+ {
+ const CameraSensorInfo InfoOrig(mBlackLevel, mWhiteLevel, mMinIso, mMaxIso,
+ mBlackLevelSeparate);
+ CameraSensorInfo Info(InfoOrig); // NOLINT
+
+ checkHelper(Info);
+ checkHelper(Info, InfoOrig);
+ }
+
+ {
+ const unique_ptr<const CameraSensorInfo> InfoOrig(new CameraSensorInfo(
+ mBlackLevel, mWhiteLevel, mMinIso, mMaxIso, mBlackLevelSeparate));
+ unique_ptr<CameraSensorInfo> Info(new CameraSensorInfo(*InfoOrig));
+
+ checkHelper(*Info);
+ checkHelper(*Info, *InfoOrig);
+ }
+
+ {
+ const CameraSensorInfo InfoOrig(mBlackLevel, mWhiteLevel, mMinIso, mMaxIso,
+ mBlackLevelSeparate);
+ unique_ptr<CameraSensorInfo> Info(new CameraSensorInfo(InfoOrig));
+
+ checkHelper(*Info);
+ checkHelper(*Info, InfoOrig);
+ }
+
+ {
+ const unique_ptr<const CameraSensorInfo> InfoOrig(new CameraSensorInfo(
+ mBlackLevel, mWhiteLevel, mMinIso, mMaxIso, mBlackLevelSeparate));
+ CameraSensorInfo Info(*InfoOrig);
+
+ checkHelper(Info);
+ checkHelper(Info, *InfoOrig);
+ }
+}
+
+TEST_P(CameraSensorInfoTestDumb, Assignment) {
+ ASSERT_NO_THROW({
+ const CameraSensorInfo InfoOrig(mBlackLevel, mWhiteLevel, mMinIso, mMaxIso,
+ mBlackLevelSeparate);
+ CameraSensorInfo Info(0, 0, 0, 0, {0});
+
+ Info = InfoOrig;
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const CameraSensorInfo> InfoOrig(new CameraSensorInfo(
+ mBlackLevel, mWhiteLevel, mMinIso, mMaxIso, mBlackLevelSeparate));
+ unique_ptr<CameraSensorInfo> Info(new CameraSensorInfo(0, 0, 0, 0, {0}));
+
+ *Info = *InfoOrig;
+ });
+
+ ASSERT_NO_THROW({
+ const CameraSensorInfo InfoOrig(mBlackLevel, mWhiteLevel, mMinIso, mMaxIso,
+ mBlackLevelSeparate);
+ unique_ptr<CameraSensorInfo> Info(new CameraSensorInfo(0, 0, 0, 0, {0}));
+
+ *Info = InfoOrig;
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const CameraSensorInfo> InfoOrig(new CameraSensorInfo(
+ mBlackLevel, mWhiteLevel, mMinIso, mMaxIso, mBlackLevelSeparate));
+ CameraSensorInfo Info(0, 0, 0, 0, {0});
+
+ Info = *InfoOrig;
+ });
+}
+
+TEST_P(CameraSensorInfoTestDumb, AssignmentGetters) {
+ ASSERT_NO_THROW({
+ const CameraSensorInfo InfoOrig(mBlackLevel, mWhiteLevel, mMinIso, mMaxIso,
+ mBlackLevelSeparate);
+ CameraSensorInfo Info(0, 0, 0, 0, {0});
+
+ Info = InfoOrig;
+
+ checkHelper(Info);
+ checkHelper(Info, InfoOrig);
+ });
+}
+
+// --------------------------------------------------------
+
+struct IsoExpectationsT {
+ int mMinIso;
+ int Iso;
+ int mMaxIso;
+ bool isIsoWithin;
+ bool isDefault;
+
+ friend std::ostream& operator<<(std::ostream& os,
+ const IsoExpectationsT& obj) {
+ return os << "min ISO: " << obj.mMinIso << "; test iso: " << obj.Iso
+ << ", max ISO: " << obj.mMaxIso
+ << "; is iso within: " << obj.isIsoWithin
+ << "; is default: " << obj.isDefault;
+ }
+};
+
+static const struct IsoExpectationsT CameraSensorIsoInfos[] = {
+ IsoExpectationsT{0, 0, 0, true, true},
+
+ IsoExpectationsT{100, 0, 200, false, false},
+ IsoExpectationsT{100, 99, 200, false, false},
+ IsoExpectationsT{100, 100, 200, true, false},
+ IsoExpectationsT{100, 160, 200, true, false},
+ IsoExpectationsT{100, 200, 200, true, false},
+ IsoExpectationsT{100, 201, 200, false, false},
+ IsoExpectationsT{100, std::numeric_limits<int>::max(), 200, false, false},
+
+ // if max iso == 0, every iso which is >= min iso is within.
+ IsoExpectationsT{100, 0, 0, false, false},
+ IsoExpectationsT{100, 99, 0, false, false},
+ IsoExpectationsT{100, 100, 0, true, false},
+ IsoExpectationsT{100, std::numeric_limits<int>::max(), 0, true, false},
+};
+
+class CameraSensorInfoTest : public ::testing::TestWithParam<IsoExpectationsT> {
+protected:
+ CameraSensorInfoTest()
+ : data(IsoExpectationsT{-1, -1, -1, false, false}),
+ mBlackLevel(std::rand()), // NOLINT do not need crypto-level randomness
+ mWhiteLevel(std::rand()), // NOLINT do not need crypto-level randomness
+ mBlackLevelSeparate({
+ std::rand(), // NOLINT do not need crypto-level randomness
+ std::rand(), // NOLINT do not need crypto-level randomness
+ std::rand(), // NOLINT do not need crypto-level randomness
+ std::rand() // NOLINT do not need crypto-level randomness
+ }) {}
+ virtual void SetUp() override { data = GetParam(); }
+
+ IsoExpectationsT data;
+
+ int mBlackLevel;
+ int mWhiteLevel;
+ std::vector<int> mBlackLevelSeparate;
+};
+
+INSTANTIATE_TEST_CASE_P(Expectations, CameraSensorInfoTest,
+ testing::ValuesIn(CameraSensorIsoInfos));
+
+TEST_P(CameraSensorInfoTest, IsDefault) {
+ CameraSensorInfo Info(mBlackLevel, mWhiteLevel, data.mMinIso, data.mMaxIso,
+ mBlackLevelSeparate);
+
+ ASSERT_NO_THROW({
+ if (data.isDefault)
+ ASSERT_TRUE(Info.isDefault());
+ else
+ ASSERT_FALSE(Info.isDefault());
+ });
+}
+
+TEST_P(CameraSensorInfoTest, isIsoWithin) {
+ CameraSensorInfo Info(mBlackLevel, mWhiteLevel, data.mMinIso, data.mMaxIso,
+ mBlackLevelSeparate);
+
+ ASSERT_NO_THROW({
+ if (data.isIsoWithin)
+ ASSERT_TRUE(Info.isIsoWithin(data.Iso));
+ else
+ ASSERT_FALSE(Info.isIsoWithin(data.Iso));
+ });
+}
+
+} // namespace rawspeed_test
+
+int main(int argc, char** argv) {
+ rawspeed_test::ISOList.push_back(0);
+
+ int n = {25};
+ std::generate(rawspeed_test::ISOList.begin() + 1,
+ rawspeed_test::ISOList.end(), [&n] { return n *= 4; });
+
+ std::srand(2016122923);
+
+ testing::InitGoogleMock(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/src/external/rawspeed/test/librawspeed/metadata/CameraTest.cpp b/src/external/rawspeed/test/librawspeed/metadata/CameraTest.cpp
new file mode 100644
index 000000000..1a9adfaed
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/metadata/CameraTest.cpp
@@ -0,0 +1,157 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "metadata/Camera.h" // for Hints
+#include <gtest/gtest.h> // for AssertionResult, GetBoolAssertionFailur...
+#include <string> // for basic_string, string
+
+using rawspeed::Hints;
+using std::string;
+using std::to_string;
+
+namespace rawspeed_test {
+
+TEST(CameraTest, HintsEmpty) {
+ Hints hints;
+ ASSERT_FALSE(hints.has("something"));
+}
+
+TEST(CameraTest, HintsGetDefault) {
+ Hints hints;
+ ASSERT_FALSE(hints.get("something", false));
+ ASSERT_TRUE(hints.get("something", true));
+ ASSERT_EQ(hints.get("something", string("the default value")),
+ "the default value");
+ ASSERT_EQ(hints.get("something", 42), 42);
+ ASSERT_EQ(hints.get("something", -84), -84);
+ ASSERT_EQ(hints.get("something", 3.14f), 3.14f);
+ ASSERT_EQ(hints.get("something", 2.71), 2.71);
+}
+
+TEST(CameraTest, HintsAssignmentConstructor) {
+ const string key("something");
+
+ Hints hints;
+ ASSERT_FALSE(hints.has(key));
+
+ hints.add(key, "indeed");
+ ASSERT_TRUE(hints.has(key));
+
+ const Hints hints2(hints);
+ ASSERT_TRUE(hints2.has(key));
+
+ const Hints hints3(hints2);
+ ASSERT_TRUE(hints3.has(key));
+}
+
+TEST(CameraTest, HintsAssignment) {
+ const string key("something");
+
+ Hints hints;
+
+ ASSERT_FALSE(hints.has(key));
+ hints.add(key, "indeed");
+ ASSERT_TRUE(hints.has(key));
+
+ const Hints hints2 = hints;
+ ASSERT_TRUE(hints2.has(key));
+
+ const Hints hints3 = hints2;
+ ASSERT_TRUE(hints3.has(key));
+}
+
+TEST(CameraTest, HintsAdd) {
+ Hints hints;
+ const string key("something"), value("whocares");
+ ASSERT_FALSE(hints.has(key));
+ hints.add(key, value);
+ ASSERT_TRUE(hints.has(key));
+ ASSERT_EQ(hints.get(key, string()), value);
+}
+
+TEST(CameraTest, HintsInt) {
+ Hints hints;
+ const int val = -42;
+ const string key("thenum"), value(to_string(val));
+ ASSERT_FALSE(hints.has(key));
+ hints.add(key, value);
+ ASSERT_TRUE(hints.has(key));
+ ASSERT_EQ(hints.get(key, 0), val);
+}
+
+TEST(CameraTest, HintsUInt) {
+ Hints hints;
+ const unsigned int val = 84;
+ const string key("thenum"), value(to_string(val));
+ ASSERT_FALSE(hints.has(key));
+ hints.add(key, value);
+ ASSERT_TRUE(hints.has(key));
+ ASSERT_EQ(hints.get(key, 0U), val);
+}
+
+TEST(CameraTest, HintsFloat) {
+ Hints hints;
+ const float val = 3.14f;
+ const string key("theflt"), value(to_string(val));
+ ASSERT_FALSE(hints.has(key));
+ hints.add(key, value);
+ ASSERT_TRUE(hints.has(key));
+ ASSERT_EQ(hints.get(key, 0.0F), val);
+}
+
+TEST(CameraTest, HintsDouble) {
+ Hints hints;
+ const double val = 2.71;
+ const string key("thedbl"), value(to_string(val));
+ ASSERT_FALSE(hints.has(key));
+ hints.add(key, value);
+ ASSERT_TRUE(hints.has(key));
+ ASSERT_EQ(hints.get(key, 0.0), val);
+}
+
+TEST(BoolHintTest, HintsBoolTrue) {
+ Hints hints;
+
+ const string key("key1");
+ ASSERT_FALSE(hints.has(key));
+ hints.add(key, "true");
+ ASSERT_TRUE(hints.has(key));
+ ASSERT_TRUE(hints.get(key, false));
+}
+
+class BoolHintTest : public ::testing::TestWithParam<std::tr1::tuple<string>> {
+protected:
+ virtual void SetUp() override { notTrue = std::tr1::get<0>(GetParam()); }
+ string notTrue;
+};
+INSTANTIATE_TEST_CASE_P(NotTrue, BoolHintTest,
+ ::testing::Values("True", "false", "False", "", "_"));
+
+TEST_P(BoolHintTest, HintsBool) {
+ Hints hints;
+
+ const string key("key");
+ ASSERT_FALSE(hints.has(key));
+ hints.add(key, notTrue);
+ ASSERT_TRUE(hints.has(key));
+ ASSERT_FALSE(hints.get(key, true));
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/metadata/ColorFilterArrayTest.cpp b/src/external/rawspeed/test/librawspeed/metadata/ColorFilterArrayTest.cpp
new file mode 100644
index 000000000..5fecf66c6
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/metadata/ColorFilterArrayTest.cpp
@@ -0,0 +1,309 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2009-2014 Klaus Post
+ Copyright (C) 2016 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "metadata/ColorFilterArray.h" // for ColorFilterArray, CFAColor
+#include "common/Common.h" // for uint32
+#include "common/Point.h" // for iPoint2D
+#include <gtest/gtest.h> // for AssertionResult, IsNullLitera...
+#include <iosfwd> // for ostream
+#include <string> // for string, operator<<
+
+using rawspeed::CFAColor;
+using rawspeed::CFA_BLUE;
+using rawspeed::CFA_CYAN;
+using rawspeed::CFA_FUJI_GREEN;
+using rawspeed::CFA_GREEN;
+using rawspeed::CFA_MAGENTA;
+using rawspeed::CFA_RED;
+using rawspeed::CFA_YELLOW;
+using rawspeed::ColorFilterArray;
+using rawspeed::iPoint2D;
+using rawspeed::uint32;
+using std::string;
+
+namespace rawspeed {
+
+::std::ostream& operator<<(::std::ostream& os, const CFAColor c) {
+ return os << ColorFilterArray::colorToString(c);
+}
+
+} // namespace rawspeed
+
+namespace rawspeed_test {
+
+using Bayer2x2 = std::tr1::tuple<CFAColor, CFAColor, CFAColor, CFAColor>;
+
+static const iPoint2D square(2, 2);
+
+TEST(ColorFilterArrayTestBasic, Constructor) {
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa(square);
+ ASSERT_EQ(cfa.getSize().area(), square.area());
+ });
+}
+
+TEST(ColorFilterArrayTestBasic, SetSize) {
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa;
+ cfa.setSize(square);
+ ASSERT_EQ(cfa.getSize().area(), square.area());
+ });
+
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa(iPoint2D(1, 1));
+ cfa.setSize(square);
+ ASSERT_EQ(cfa.getSize().area(), square.area());
+ });
+}
+
+// FIXME: breaks, but only in msys2, with clang compiler
+TEST(ColorFilterArrayTestBasic, DISABLED_SetTooBigSize) {
+ ASSERT_ANY_THROW({
+ ColorFilterArray cfa(iPoint2D(1, 1));
+ cfa.setSize({6, 8});
+ });
+};
+
+TEST(ColorFilterArrayTestBasic, ToDcraw) {
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa;
+ ASSERT_EQ(cfa.getDcrawFilter(), 1);
+ });
+
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa(iPoint2D(4, 8));
+ ASSERT_EQ(cfa.getDcrawFilter(), 1);
+ });
+
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa(iPoint2D(2, 10));
+ ASSERT_EQ(cfa.getDcrawFilter(), 1);
+ });
+
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa(iPoint2D(2, 10));
+ ASSERT_EQ(cfa.getDcrawFilter(), 1);
+ });
+
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa(iPoint2D(2, 7));
+ ASSERT_EQ(cfa.getDcrawFilter(), 1);
+ });
+
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa(iPoint2D(6, 6));
+ ASSERT_EQ(cfa.getDcrawFilter(), 9); // xtrans magic
+ });
+}
+
+TEST(ColorFilterArrayTestBasic, HandlesEmptyCFA) {
+ ColorFilterArray cfa;
+
+ ASSERT_ANY_THROW({ cfa.getColorAt(0, 0); });
+
+ ASSERT_ANY_THROW({ cfa.shiftLeft(0); });
+
+ ASSERT_ANY_THROW({ cfa.shiftDown(0); });
+}
+
+TEST(ColorFilterArrayTestBasic, HandlesOutOfBounds) {
+ ColorFilterArray cfa(square);
+
+ ASSERT_ANY_THROW({ cfa.setColorAt({0, -1}, CFA_RED); });
+
+ ASSERT_ANY_THROW({ cfa.setColorAt({-1, 0}, CFA_RED); });
+
+ ASSERT_ANY_THROW({ cfa.setColorAt({-1, -1}, CFA_RED); });
+
+ ASSERT_ANY_THROW({ cfa.setColorAt({0, 2}, CFA_RED); });
+
+ ASSERT_ANY_THROW({ cfa.setColorAt({2, 0}, CFA_RED); });
+
+ ASSERT_ANY_THROW({ cfa.setColorAt({2, 2}, CFA_RED); });
+
+ // ASSERT_ANY_THROW({ ColorFilterArray::colorToString((CFAColor)-1); });
+
+ ASSERT_ANY_THROW({ cfa.getDcrawFilter(); });
+}
+
+class ColorFilterArrayTest : public ::testing::TestWithParam<Bayer2x2> {
+protected:
+ ColorFilterArrayTest() = default;
+ virtual void SetUp() { param = GetParam(); }
+
+ Bayer2x2 param;
+};
+
+static const auto Bayer_RGB = ::testing::Values(CFA_RED, CFA_GREEN, CFA_BLUE);
+static const auto Bayer_CYGM =
+ ::testing::Values(CFA_CYAN, CFA_MAGENTA, CFA_YELLOW, CFA_FUJI_GREEN);
+
+INSTANTIATE_TEST_CASE_P(RGGB, ColorFilterArrayTest,
+ testing::Combine(Bayer_RGB, Bayer_RGB, Bayer_RGB,
+ Bayer_RGB));
+
+INSTANTIATE_TEST_CASE_P(CYGM, ColorFilterArrayTest,
+ testing::Combine(Bayer_CYGM, Bayer_CYGM, Bayer_CYGM,
+ Bayer_CYGM));
+
+static void setHelper(ColorFilterArray* cfa, Bayer2x2 param) {
+ cfa->setCFA(square, std::tr1::get<0>(param), std::tr1::get<1>(param),
+ std::tr1::get<2>(param), std::tr1::get<3>(param));
+}
+
+static void check(ColorFilterArray* cfa, Bayer2x2 param) {
+ ASSERT_EQ(cfa->getColorAt(0, 0), std::tr1::get<0>(param));
+ ASSERT_EQ(cfa->getColorAt(1, 0), std::tr1::get<1>(param));
+ ASSERT_EQ(cfa->getColorAt(0, 1), std::tr1::get<2>(param));
+ ASSERT_EQ(cfa->getColorAt(1, 1), std::tr1::get<3>(param));
+}
+
+TEST_P(ColorFilterArrayTest, Constructor) {
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa;
+ setHelper(&cfa, param);
+ check(&cfa, param);
+ });
+}
+
+TEST_P(ColorFilterArrayTest, AssignmentConstructor) {
+ ASSERT_NO_THROW({
+ ColorFilterArray cfaOrig;
+ setHelper(&cfaOrig, param);
+ check(&cfaOrig, param);
+
+ ColorFilterArray cfa(cfaOrig);
+ check(&cfa, param);
+ });
+
+ ASSERT_NO_THROW({
+ ColorFilterArray cfaOrig;
+ setHelper(&cfaOrig, param);
+ check(&cfaOrig, param);
+
+ ColorFilterArray cfa;
+ cfa = cfaOrig;
+ check(&cfa, param);
+ });
+}
+
+TEST_P(ColorFilterArrayTest, SetColorAt) {
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa({2, 2});
+ cfa.setColorAt({0, 0}, std::tr1::get<0>(param));
+ cfa.setColorAt({1, 0}, std::tr1::get<1>(param));
+ cfa.setColorAt({0, 1}, std::tr1::get<2>(param));
+ cfa.setColorAt({1, 1}, std::tr1::get<3>(param));
+ check(&cfa, param);
+ });
+}
+
+TEST_P(ColorFilterArrayTest, ToDcraw) {
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa;
+ setHelper(&cfa, param);
+ cfa.getDcrawFilter();
+ });
+}
+
+TEST_P(ColorFilterArrayTest, AsString) {
+ ASSERT_NO_THROW({
+ ColorFilterArray cfa;
+ setHelper(&cfa, param);
+ string dsc = cfa.asString();
+
+ ASSERT_GT(dsc.size(), 15);
+ ASSERT_LE(dsc.size(), 40);
+ });
+}
+
+class ColorFilterArrayShiftTest
+ : public ::testing::TestWithParam<
+ std::tr1::tuple<CFAColor, CFAColor, CFAColor, CFAColor, int, int>> {
+protected:
+ ColorFilterArrayShiftTest() = default;
+ virtual void SetUp() {
+ auto param = GetParam();
+ mat = std::make_tuple(std::tr1::get<0>(param), std::tr1::get<1>(param),
+ std::tr1::get<2>(param), std::tr1::get<3>(param));
+ x = std::tr1::get<4>(param);
+ y = std::tr1::get<5>(param);
+ }
+
+ Bayer2x2 mat;
+ int x;
+ int y;
+};
+
+INSTANTIATE_TEST_CASE_P(RGGB, ColorFilterArrayShiftTest,
+ testing::Combine(Bayer_RGB, Bayer_RGB, Bayer_RGB,
+ Bayer_RGB, testing::Range(-2, 2),
+ testing::Range(-2, 2)));
+
+INSTANTIATE_TEST_CASE_P(CYGM, ColorFilterArrayShiftTest,
+ testing::Combine(Bayer_CYGM, Bayer_CYGM, Bayer_CYGM,
+ Bayer_CYGM, testing::Range(-2, 2),
+ testing::Range(-2, 2)));
+
+TEST(ColorFilterArrayTestBasic, shiftDcrawFilter) {
+ uint32 bggr = 0x16161616;
+ uint32 grbg = 0x61616161;
+ uint32 gbrg = 0x49494949;
+ uint32 rggb = 0x94949494;
+ ASSERT_NO_THROW({
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, 0, 0), rggb);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, 1, 0), grbg);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, 0, 1), gbrg);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, 1, 1), bggr);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, 2, 0), rggb);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, 0, 2), rggb);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, 2, 2), rggb);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, -1, 0), grbg);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, 0, -1), gbrg);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, -1, -1), bggr);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, -2, 0), rggb);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, 0, -2), rggb);
+ ASSERT_EQ(ColorFilterArray::shiftDcrawFilter(rggb, -2, -2), rggb);
+ });
+}
+
+TEST_P(ColorFilterArrayShiftTest, shiftEqualityTest) {
+ ASSERT_NO_THROW({
+ ColorFilterArray cfaOrig;
+ setHelper(&cfaOrig, mat);
+ uint32 fo = cfaOrig.getDcrawFilter();
+
+ ColorFilterArray cfa = cfaOrig;
+ cfa.shiftLeft(x);
+ cfa.shiftDown(y);
+ uint32 f = cfa.getDcrawFilter();
+ ASSERT_EQ(f, ColorFilterArray::shiftDcrawFilter(fo, x, y));
+
+ cfa = cfaOrig;
+ iPoint2D p(x, y);
+ cfa.shiftLeft(p.x);
+ cfa.shiftDown(p.y);
+ f = cfa.getDcrawFilter();
+ ASSERT_EQ(f, ColorFilterArray::shiftDcrawFilter(fo, x, y));
+ });
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/test/CMakeLists.txt b/src/external/rawspeed/test/librawspeed/test/CMakeLists.txt
new file mode 100644
index 000000000..ae0af0fd0
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/test/CMakeLists.txt
@@ -0,0 +1,15 @@
+FILE(GLOB RAWSPEED_TEST_SOURCES
+ "RawSpeed.cpp"
+)
+
+target_sources(rawspeed_test PRIVATE
+ ${RAWSPEED_TEST_SOURCES}
+)
+
+FILE(GLOB RAWSPEED_TESTS_SOURCES
+ "ExceptionsTest.cpp"
+)
+
+foreach(IN ${RAWSPEED_TESTS_SOURCES})
+ add_rs_test(${IN})
+endforeach()
diff --git a/src/external/rawspeed/test/librawspeed/test/ExceptionsTest.cpp b/src/external/rawspeed/test/librawspeed/test/ExceptionsTest.cpp
new file mode 100644
index 000000000..645680eaf
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/test/ExceptionsTest.cpp
@@ -0,0 +1,209 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2016-2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/RawspeedException.h" // for RawspeedException
+#include "decoders/RawDecoderException.h" // for RawDecoderException (p...
+#include "io/FileIOException.h" // for FileIOException (ptr o...
+#include "io/IOException.h" // for IOException (ptr only)
+#include "metadata/CameraMetadataException.h" // for CameraMetadataExceptio...
+#include "parsers/CiffParserException.h" // for CiffParserException (p...
+#include "parsers/FiffParserException.h" // for FiffParserException (p...
+#include "parsers/RawParserException.h" // for ThrowRPE, RawParserEx...
+#include "parsers/TiffParserException.h" // for ThrowTPE, TiffParserEx...
+#include <exception> // IWYU pragma: keep
+#include <gmock/gmock.h> // for MakePredicateFormatter...
+#include <gtest/gtest.h> // for Message, TestPartResult
+#include <memory> // for unique_ptr
+#include <stdexcept> // for runtime_error
+#include <string> // for string
+// IWYU pragma: no_include <bits/exception.h>
+
+using rawspeed::CameraMetadataException;
+using rawspeed::CiffParserException;
+using rawspeed::FiffParserException;
+using rawspeed::FileIOException;
+using rawspeed::IOException;
+using rawspeed::RawDecoderException;
+using rawspeed::RawParserException;
+using rawspeed::RawspeedException;
+using rawspeed::TiffParserException;
+using std::unique_ptr;
+
+namespace rawspeed_test {
+
+static const std::string msg("my very Smart error Message #1 !");
+
+#define FMT "%s"
+
+template <typename T> static void* MetaHelper(const char* str) {
+ ADD_FAILURE() << "non-specialzer was called";
+ return nullptr;
+}
+
+template <> void* MetaHelper<RawspeedException>(const char* str) {
+ ThrowRSE(FMT, str);
+}
+
+template <> void* MetaHelper<CameraMetadataException>(const char* str) {
+ ThrowCME(FMT, str);
+}
+
+template <> void* MetaHelper<CiffParserException>(const char* str) {
+ ThrowCPE(FMT, str);
+}
+
+template <> void* MetaHelper<FileIOException>(const char* str) {
+ ThrowFIE(FMT, str);
+}
+
+template <> void* MetaHelper<IOException>(const char* str) {
+ ThrowIOE(FMT, str);
+}
+
+template <> void* MetaHelper<RawDecoderException>(const char* str) {
+ ThrowRDE(FMT, str);
+}
+
+template <> void* MetaHelper<RawParserException>(const char* str) {
+ ThrowRPE(FMT, str);
+}
+
+template <> void* MetaHelper<TiffParserException>(const char* str) {
+ ThrowTPE(FMT, str);
+}
+
+template <> void* MetaHelper<FiffParserException>(const char* str) {
+ ThrowFPE(FMT, str);
+}
+
+template <class T> class ExceptionsTest : public testing::Test {};
+
+using Classes =
+ testing::Types<RawspeedException, CameraMetadataException,
+ CiffParserException, FileIOException, IOException,
+ RawDecoderException, TiffParserException,
+ FiffParserException, RawParserException>;
+
+TYPED_TEST_CASE(ExceptionsTest, Classes);
+
+TYPED_TEST(ExceptionsTest, Constructor) {
+ ASSERT_NO_THROW({ TypeParam Exception(msg); });
+ ASSERT_NO_THROW({ unique_ptr<TypeParam> Exception(new TypeParam(msg)); });
+}
+
+TYPED_TEST(ExceptionsTest, AssignmentConstructor) {
+ ASSERT_NO_THROW({
+ const TypeParam ExceptionOne(msg);
+ TypeParam ExceptionTwo(ExceptionOne); // NOLINT trying to test the copy
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const TypeParam> ExceptionOne(new TypeParam(msg));
+ unique_ptr<TypeParam> ExceptionTwo(new TypeParam(*ExceptionOne));
+ });
+
+ ASSERT_NO_THROW({
+ const TypeParam ExceptionOne(msg);
+ unique_ptr<TypeParam> ExceptionTwo(new TypeParam(ExceptionOne));
+ });
+
+ ASSERT_NO_THROW({
+ const unique_ptr<const TypeParam> ExceptionOne(new TypeParam(msg));
+ TypeParam ExceptionTwo(*ExceptionOne);
+ });
+}
+
+TYPED_TEST(ExceptionsTest, Throw) {
+ ASSERT_ANY_THROW(throw TypeParam(msg));
+ EXPECT_THROW(throw TypeParam(msg), TypeParam);
+ EXPECT_THROW(throw TypeParam(msg), RawspeedException);
+ EXPECT_THROW(throw TypeParam(msg), std::runtime_error);
+
+ ASSERT_ANY_THROW({
+ std::unique_ptr<TypeParam> Exception(new TypeParam(msg));
+ throw *Exception.get();
+ });
+ EXPECT_THROW(
+ {
+ std::unique_ptr<TypeParam> Exception(new TypeParam(msg));
+ throw *Exception.get();
+ },
+ std::runtime_error);
+ EXPECT_THROW(
+ {
+ std::unique_ptr<TypeParam> Exception(new TypeParam(msg));
+ throw *Exception.get();
+ },
+ RawspeedException);
+ EXPECT_THROW(
+ {
+ std::unique_ptr<TypeParam> Exception(new TypeParam(msg));
+ throw *Exception.get();
+ },
+ TypeParam);
+}
+
+TYPED_TEST(ExceptionsTest, ThrowMessage) {
+ try {
+ throw TypeParam(msg);
+ } catch (std::exception& ex) {
+ ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
+ }
+
+ try {
+ std::unique_ptr<TypeParam> Exception(new TypeParam(msg));
+ throw *Exception.get();
+ } catch (std::exception& ex) {
+ ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
+ }
+
+ try {
+ std::unique_ptr<TypeParam> ExceptionOne(new TypeParam(msg));
+ const std::unique_ptr<const TypeParam> ExceptionTwo(new TypeParam(msg));
+ throw *ExceptionTwo.get();
+ } catch (std::exception& ex) {
+ ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
+ }
+
+ try {
+ const TypeParam ExceptionOne(msg);
+ std::unique_ptr<TypeParam> ExceptionTwo(new TypeParam(msg));
+ throw *ExceptionTwo.get();
+ } catch (std::exception& ex) {
+ ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
+ }
+}
+
+TYPED_TEST(ExceptionsTest, ThrowHelperTest) {
+ ASSERT_ANY_THROW(MetaHelper<TypeParam>(msg.c_str()));
+ EXPECT_THROW(MetaHelper<TypeParam>(msg.c_str()), std::runtime_error);
+ EXPECT_THROW(MetaHelper<TypeParam>(msg.c_str()), RawspeedException);
+ EXPECT_THROW(MetaHelper<TypeParam>(msg.c_str()), TypeParam);
+}
+
+TYPED_TEST(ExceptionsTest, ThrowHelperTestMessage) {
+ try {
+ MetaHelper<TypeParam>(msg.c_str());
+ } catch (std::exception& ex) {
+ ASSERT_THAT(ex.what(), testing::HasSubstr(msg));
+ }
+}
+
+} // namespace rawspeed_test
diff --git a/src/external/rawspeed/test/librawspeed/test/RawSpeed.cpp b/src/external/rawspeed/test/librawspeed/test/RawSpeed.cpp
new file mode 100644
index 000000000..e743a58fa
--- /dev/null
+++ b/src/external/rawspeed/test/librawspeed/test/RawSpeed.cpp
@@ -0,0 +1,36 @@
+/*
+ RawSpeed - RAW file decoder.
+
+ Copyright (C) 2016-2017 Roman Lebedev
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "common/Common.h" // IWYU pragma: keep
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+// define this function, it is only declared in rawspeed:
+#ifdef _OPENMP
+extern "C" int rawspeed_get_number_of_processor_cores() {
+ return omp_get_num_procs();
+}
+#else
+extern "C" int __attribute__((const)) rawspeed_get_number_of_processor_cores() {
+ return 1;
+}
+#endif
diff --git a/src/version_gen.c b/src/version_gen.c
index e1697f970..5eecd572f 100644
--- a/src/version_gen.c
+++ b/src/version_gen.c
@@ -2,13 +2,13 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
- const char darktable_package_version[] = "2.4.0";
- const char darktable_package_string[] = PACKAGE_NAME " 2.4.0";
- const char darktable_last_commit_year[] = "2017";
+ const char darktable_package_version[] = "2.4.1";
+ const char darktable_package_string[] = PACKAGE_NAME " 2.4.1";
+ const char darktable_last_commit_year[] = "2018";
#else
#define DT_MAJOR 2
#define DT_MINOR 4
- #define DT_PATCH 0
+ #define DT_PATCH 1
#define DT_N_COMMITS 0
- #define LAST_COMMIT_YEAR "2017"
+ #define LAST_COMMIT_YEAR "2018"
#endif