Chromium Code Reviews| Index: dm/DMSrcSink.cpp |
| diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp |
| index f99afe48597247dd015f8c69d3aa1192a5ea39a4..ee833f833567ecd106a0a2f1a95d7ebc4f713b79 100644 |
| --- a/dm/DMSrcSink.cpp |
| +++ b/dm/DMSrcSink.cpp |
| @@ -9,10 +9,12 @@ |
| #include "SkAndroidCodec.h" |
| #include "SkCodec.h" |
| #include "SkCodecImageGenerator.h" |
| +#include "SkColorSpaceXform.h" |
| #include "SkCommonFlags.h" |
| #include "SkData.h" |
| #include "SkDocument.h" |
| #include "SkError.h" |
| +#include "SkHalf.h" |
| #include "SkImageGenerator.h" |
| #include "SkImageGeneratorCG.h" |
| #include "SkImageGeneratorWIC.h" |
| @@ -942,6 +944,17 @@ bool ColorCodecSrc::veto(SinkFlags flags) const { |
| return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; |
| } |
| +static uint8_t clampFloatToByte(float v) { |
| + v = v * 255.0f; |
| + if (v > 255.0f) { |
| + return 255; |
| + } else if (v < 0.0f) { |
| + return 0; |
| + } else { |
| + return (uint8_t) (v + 0.5f); |
| + } |
| +} |
| + |
| Error ColorCodecSrc::draw(SkCanvas* canvas) const { |
| if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) { |
| return Error::Nonfatal("No need to test color correction to 565 backend."); |
| @@ -957,24 +970,106 @@ Error ColorCodecSrc::draw(SkCanvas* canvas) const { |
| return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); |
| } |
| - SkImageInfo decodeInfo = codec->getInfo().makeColorType(kN32_SkColorType); |
| + SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); |
| + uint32_t width = info.width(); |
| + uint32_t height = info.height(); |
| SkBitmap bitmap; |
| - if (!bitmap.tryAllocPixels(decodeInfo)) { |
| + if (!bitmap.tryAllocPixels(info)) { |
| return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(), |
| - decodeInfo.width(), decodeInfo.height()); |
| + info.width(), info.height()); |
| + } |
| + |
| + SkImageInfo decodeInfo = info; |
| + if (kBaseline_Mode != fMode) { |
| + decodeInfo = decodeInfo.makeColorType(kRGBA_8888_SkColorType); |
| + } |
| + |
| + SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes()); |
| + switch (r) { |
|
herb_g
2016/05/05 14:44:50
Should be an if statement.
msarett
2016/05/05 15:49:05
Yes! SGTM :)
|
| + case SkCodec::kSuccess: |
| + break; |
| + default: |
| + // Everything else is considered a failure. |
| + return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r); |
| } |
| switch (fMode) { |
| case kBaseline_Mode: |
| - switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowBytes())) { |
| - case SkCodec::kSuccess: |
| - break; |
| - default: |
| - // Everything else is considered a failure. |
| - return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); |
| + canvas->drawBitmap(bitmap, 0, 0); |
| + break; |
| + case kSrcToLinear_Mode: { |
| + sk_sp<SkColorSpace> srcSpace = sk_ref_sp(codec->getColorSpace()); |
| + if (!srcSpace) { |
| + return SkStringPrintf("Cannot test color correction without a src profile."); |
| + } |
| + |
| + SkAutoTDelete<SkColorSpaceXform> xform(SkColorSpaceXform::New(srcSpace, nullptr, |
| + SkColorSpaceXform::kSrcToLinear_Op)); |
| + if (!xform) { |
| + return Error::Nonfatal("Xform is not implemented yet."); |
| } |
| + |
| + // Create a F16 destination buffer for the output of color conversion. |
| + size_t rowBytes = width * SkColorTypeBytesPerPixel(kRGBA_F16_SkColorType); |
| + SkAutoMalloc pixels(rowBytes * height); |
| + |
| + // Apply the conversion to linear F16 pixels. |
| + SkISize size = SkISize::Make(width, height); |
| + xform->apply(pixels.get(), bitmap.getPixels(), size, rowBytes, bitmap.rowBytes()); |
| + |
| + // Converting to a linear color space is useful because most post-decode operations |
| + // assume linear pixels (ex: scaling, premultiplying, etc). However, we will want |
| + // to be in a non-linear dst color space when we write the pixels to the screen. |
| + // In order to test, we will assume that the dst wants sRGB pixels and convert the |
| + // linear intermediate to sRGB. This will make the output images look normal (or |
| + // prettier than normal) if there are no bugs in our conversions. |
|
Brian Osman
2016/05/05 13:29:44
Thanks for the better comment here. Like Leon, I w
msarett
2016/05/05 15:49:05
Acknowledged.
|
| + uint64_t* rowPtr = (uint64_t*) pixels.get(); |
| + for (uint32_t y = 0; y < height; y++) { |
| + for (uint32_t x = 0; x < width; x++) { |
| + // Extract floats. |
| + uint64_t pixel = rowPtr[x]; |
| + float linearR = SkHalfToFloat((pixel >> 0) & 0xFFFF); |
| + float linearG = SkHalfToFloat((pixel >> 16) & 0xFFFF); |
| + float linearB = SkHalfToFloat((pixel >> 32) & 0xFFFF); |
| + float linearA = SkHalfToFloat((pixel >> 48) & 0xFFFF); |
| + |
| + // Currently we only support decodes to F16 when the encoded image has |
| + // a color space. |
| + SkColorSpace* colorSpace = codec->getColorSpace(); |
| + SkASSERT(colorSpace); |
| + |
| + // Convert to XYZ gamut. |
| + const SkMatrix44& toXYZ = colorSpace->xyz(); |
| + float xyzR = linearR*toXYZ.getFloat(0, 0) + linearG*toXYZ.getFloat(1, 0) + |
| + linearB*toXYZ.getFloat(2, 0) + toXYZ.getFloat(3, 0); |
| + float xyzG = linearR*toXYZ.getFloat(0, 1) + linearG*toXYZ.getFloat(1, 1) + |
| + linearB*toXYZ.getFloat(2, 1) + toXYZ.getFloat(3, 1); |
| + float xyzB = linearR*toXYZ.getFloat(0, 2) + linearG*toXYZ.getFloat(1, 2) + |
| + linearB*toXYZ.getFloat(2, 2) + toXYZ.getFloat(3, 2); |
| + |
| + // Convert to sRGB gamut, using inverse sRGB matrix. |
| + float dstR = xyzR*3.13651f + xyzG*-1.61902f + xyzB*-0.490837f; |
| + float dstG = xyzR*-0.978981f + xyzG*1.91625f + xyzB*0.0334349f; |
| + float dstB = xyzR*0.072085f + xyzG*-0.229113f + xyzB*1.40577f; |
| + |
| + // Convert to sRGB gamma. |
| + float curveR = pow(dstR, 1.0f/2.2f); |
| + float curveG = pow(dstG, 1.0f/2.2f); |
| + float curveB = pow(dstB, 1.0f/2.2f); |
| + |
| + uint32_t* ptr = (uint32_t*) bitmap.getAddr(x, y); |
| + *ptr = SkPackARGB32NoCheck(clampFloatToByte(linearA), |
| + clampFloatToByte(curveR), |
| + clampFloatToByte(curveG), |
| + clampFloatToByte(curveB)); |
| + } |
| + |
| + rowPtr = SkTAddOffset<uint64_t>(rowPtr, rowBytes); |
| + } |
| + |
| canvas->drawBitmap(bitmap, 0, 0); |
| break; |
| + } |
| default: |
| SkASSERT(false); |
| return "Invalid fMode"; |