| Index: src/images/SkEXRImageEncoder.cpp
|
| diff --git a/src/images/SkEXRImageEncoder.cpp b/src/images/SkEXRImageEncoder.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..416e1322fd7c5683bf35b2ce23e4e05f20dd37d8
|
| --- /dev/null
|
| +++ b/src/images/SkEXRImageEncoder.cpp
|
| @@ -0,0 +1,134 @@
|
| +/*
|
| + * 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 "SkBitmap.h"
|
| +#include "SkImageEncoder.h"
|
| +#include "SkHalf.h"
|
| +#include "SkStream.h"
|
| +#include "SkTemplates.h"
|
| +
|
| +#define TINYEXR_IMPLEMENTATION
|
| +#include "tinyexr.h"
|
| +
|
| +class SkEXRImageEncoder : public SkImageEncoder {
|
| +protected:
|
| + bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override;
|
| +private:
|
| + typedef SkImageEncoder INHERITED;
|
| +};
|
| +
|
| +static inline bool encode_f16(SkWStream* stream, const SkBitmap& bitmap) {
|
| + bool isOpaque = bitmap.isOpaque();
|
| +
|
| + EXRHeader header;
|
| + InitEXRHeader(&header);
|
| + header.compression_type = TINYEXR_COMPRESSIONTYPE_PIZ;
|
| +
|
| + EXRChannelInfo channels[4];
|
| + sk_bzero(channels, 4 * sizeof(EXRChannelInfo));
|
| + header.channels = channels;
|
| +
|
| + // EXR viewers expect BGR(A).
|
| + if (isOpaque) {
|
| + header.num_channels = 3;
|
| + header.channels[0].name[0] = 'B';
|
| + header.channels[1].name[0] = 'G';
|
| + header.channels[2].name[0] = 'R';
|
| + } else {
|
| + header.num_channels = 4;
|
| + header.channels[0].name[0] = 'B';
|
| + header.channels[1].name[0] = 'G';
|
| + header.channels[2].name[0] = 'R';
|
| + header.channels[3].name[0] = 'A';
|
| + }
|
| +
|
| + int pixelTypes[] = {
|
| + TINYEXR_PIXELTYPE_HALF,
|
| + TINYEXR_PIXELTYPE_HALF,
|
| + TINYEXR_PIXELTYPE_HALF,
|
| + TINYEXR_PIXELTYPE_HALF,
|
| + };
|
| +
|
| + header.pixel_types = pixelTypes;
|
| + header.requested_pixel_types = pixelTypes;
|
| +
|
| + EXRImage image;
|
| + InitEXRImage(&image);
|
| +
|
| + image.num_channels = header.num_channels;
|
| +
|
| + int width = bitmap.width();
|
| + int height = bitmap.height();
|
| + SkAutoTMalloc<SkHalf> storage(image.num_channels * width * height);
|
| + SkHalf* planes[4];
|
| + for (int i = 0; i < image.num_channels; i++) {
|
| + planes[i] = storage.get() + i * width * height;
|
| + }
|
| +
|
| + for (int y = 0; y < height; y++) {
|
| + for (int x = 0; x < width; x++) {
|
| + uint64_t pixel = *((uint64_t*) bitmap.getAddr(x, y));
|
| + planes[0][y * width + x] = (pixel >> 32) & 0xFFFF;
|
| + planes[1][y * width + x] = (pixel >> 16) & 0xFFFF;
|
| + planes[2][y * width + x] = (pixel >> 0) & 0xFFFF;
|
| + if (4 == image.num_channels) {
|
| + planes[3][y * width + x] = (pixel >> 48) & 0xFFFF;
|
| + }
|
| + }
|
| + }
|
| +
|
| + image.images = (uint8_t**) planes;
|
| + image.width = width;
|
| + image.height = height;
|
| +
|
| + const char* error;
|
| + uint8_t* memory;
|
| + size_t bytes = SaveEXRImageToMemory(&image, &header, &memory, &error);
|
| + if (0 == bytes) {
|
| + SkDebugf("EXR Error: %s\n", error);
|
| + return false;
|
| + }
|
| +
|
| + stream->write(memory, bytes);
|
| + free(memory);
|
| + return true;
|
| +}
|
| +
|
| +bool SkEXRImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap, int) {
|
| + const SkColorType colorType = bitmap.colorType();
|
| + const SkAlphaType alphaType = bitmap.alphaType();
|
| + switch (colorType) {
|
| + case kAlpha_8_SkColorType:
|
| + if (kPremul_SkAlphaType != alphaType && kUnpremul_SkAlphaType != alphaType) {
|
| + return false;
|
| + }
|
| + break;
|
| + case kRGBA_F16_SkColorType:
|
| + if (kUnpremul_SkAlphaType == alphaType) {
|
| + // OpenEXR expect premultiplied alpha.
|
| + // FIXME (msarett):
|
| + // Do the premultiply, then encode.
|
| + return false;
|
| + }
|
| +
|
| + return encode_f16(stream, bitmap);
|
| + default:
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////////////////////////
|
| +
|
| +DEFINE_ENCODER_CREATOR(EXRImageEncoder);
|
| +
|
| +SkImageEncoder* sk_exr_efactory(SkImageEncoder::Type t) {
|
| + return (SkImageEncoder::kEXR_Type == t) ? new SkEXRImageEncoder : nullptr;
|
| +}
|
| +
|
| +static SkImageEncoder_EncodeReg gEReg(sk_exr_efactory);
|
|
|