Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Unified Diff: dm/DMSrcSink.cpp

Issue 1952063002: Create SkColorSpaceXform to handle color conversions (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Multiply by the inverse of 255.0f Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « dm/DMSrcSink.h ('k') | gyp/core.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: dm/DMSrcSink.cpp
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index f99afe48597247dd015f8c69d3aa1192a5ea39a4..5d5dc58cff82cc3807943166bb3f9ec2842bfdec 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,102 @@ 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());
+ if (SkCodec::kSuccess != r) {
+ 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());
scroggo 2016/05/05 20:57:26 Should we update the API to return a const sk_sp<S
msarett 2016/05/05 21:34:26 We *should* do that. We actually can't because Sk
+ 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.");
scroggo 2016/05/05 20:57:26 Alternatively, should we only upload an image for
msarett 2016/05/05 21:34:26 I believe that's how it works now. The only image
scroggo 2016/05/06 13:50:00 In that case, shouldn't this be a fatal error?
}
+
+ // 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.
scroggo 2016/05/05 20:57:26 It's strange that we are talking about writing to
msarett 2016/05/05 21:34:26 Agreed I'll go back and explain this further... W
+ // 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.
+ 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";
« no previous file with comments | « dm/DMSrcSink.h ('k') | gyp/core.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698