Index: src/codec/SkExrCodec.cpp |
diff --git a/src/codec/SkExrCodec.cpp b/src/codec/SkExrCodec.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..bea9a63d274216c4afe2443510a2ac40e7727684 |
--- /dev/null |
+++ b/src/codec/SkExrCodec.cpp |
@@ -0,0 +1,113 @@ |
+/* |
+ * Copyright 2016 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "SkExrCodec.h" |
+ |
+//#define TINYEXR_IMPLEMENTATION |
+#include "tinyexr.h" |
+ |
+bool SkExrCodec::IsExr(const void* buffer, size_t bytes) { |
+ static constexpr uint8_t kExrSig[] = { 0x76, 0x2f, 0x31, 0x01, }; |
+ return bytes >= 4 && 0 == memcmp(buffer, kExrSig, 4); |
+} |
+ |
+SkCodec* SkExrCodec::NewFromStream(SkStream* stream) { |
+ sk_sp<SkData> data = ((SkMemoryStream*) stream)->asData(); |
+ |
+ EXRVersion version; |
+ int result = ParseEXRVersionFromMemory(&version, data->bytes(), data->size()); |
+ if (result != TINYEXR_SUCCESS) { |
+ return nullptr; |
+ } |
+ |
+ EXRHeader header; |
+ InitEXRHeader(&header); |
+ result = ParseEXRHeaderFromMemory(&header, &version, data->bytes(), data->size(), nullptr); |
+ if (TINYEXR_SUCCESS != result) { |
+ return nullptr; |
+ } |
+ |
+ int width = header.data_window[2] - header.data_window[0] + 1; |
+ int height = header.data_window[3] - header.data_window[1] + 1; |
+ SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color, |
+ SkEncodedInfo::kOpaque_Alpha, 8); |
+ return new SkExrCodec(width, height, info, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named), |
+ stream, data); |
+} |
+ |
+SkCodec::Result SkExrCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t rowBytes, |
+ const Options& options, SkPMColor*, int*, |
+ int* rowsDecodedPtr) { |
+ EXRVersion exr_version; |
+ EXRImage exr_image; |
+ EXRHeader exr_header; |
+ |
+ InitEXRHeader(&exr_header); |
+ |
+ int ret = ParseEXRVersionFromMemory(&exr_version, fData->bytes(), fData->size()); |
+ if (ret != TINYEXR_SUCCESS) { |
+ return kInvalidInput; |
+ } |
+ |
+ ret = ParseEXRHeaderFromMemory(&exr_header, &exr_version, fData->bytes(), fData->size(), nullptr); |
+ if (ret != TINYEXR_SUCCESS) { |
+ return kInvalidInput; |
+ } |
+ |
+ int pixelTypes[] = { |
+ TINYEXR_PIXELTYPE_FLOAT, |
+ TINYEXR_PIXELTYPE_FLOAT, |
+ TINYEXR_PIXELTYPE_FLOAT, |
+ TINYEXR_PIXELTYPE_FLOAT, |
+ }; |
+ exr_header.requested_pixel_types = pixelTypes; |
+ |
+ InitEXRImage(&exr_image); |
+ ret = LoadEXRImageFromMemory(&exr_image, &exr_header, fData->bytes(), nullptr); |
+ if (ret != TINYEXR_SUCCESS) { |
+ return kInvalidInput; |
+ } |
+ |
+ // RGBA |
+ int idxR = -1; |
+ int idxG = -1; |
+ int idxB = -1; |
+ for (int c = 0; c < exr_header.num_channels; c++) { |
+ if (strcmp(exr_header.channels[c].name, "R") == 0) { |
+ idxR = c; |
+ } else if (strcmp(exr_header.channels[c].name, "G") == 0) { |
+ idxG = c; |
+ } else if (strcmp(exr_header.channels[c].name, "B") == 0) { |
+ idxB = c; |
+ } |
+ } |
+ |
+ if (idxR == -1 || idxG == -1 || idxB == -1) { |
+ return kInvalidInput; |
+ } |
+ |
+ // Assume `out_rgba` have enough memory allocated. |
+ uint32_t* dst32 = (uint32_t*) dst; |
+ for (int i = 0; i < exr_image.width * exr_image.height; i++) { |
+ SkColor4f rgba; |
+ rgba.fR = reinterpret_cast<float **>(exr_image.images)[idxR][i]; |
+ rgba.fG = reinterpret_cast<float **>(exr_image.images)[idxG][i]; |
+ rgba.fB = reinterpret_cast<float **>(exr_image.images)[idxB][i]; |
+ rgba.fA = 1.0; |
+ //SkDebugf("%g %g %g %g\n", rgba.fR, rgba.fG, rgba.fB, rgba.fA); |
+ SkColor color = rgba.toSkColor(); |
+ dst32[i] = color; |
+ } |
+ |
+ return kSuccess; |
+} |
+ |
+SkExrCodec::SkExrCodec(int width, int height, const SkEncodedInfo& info, |
+ sk_sp<SkColorSpace> colorSpace, SkStream* stream, sk_sp<SkData> data) |
+ : INHERITED(width, height, info, stream, std::move(colorSpace)) |
+ , fData(data) |
+{} |