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"; |