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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « dm/DMSrcSink.h ('k') | gyp/core.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "DMSrcSink.h" 8 #include "DMSrcSink.h"
9 #include "SkAndroidCodec.h" 9 #include "SkAndroidCodec.h"
10 #include "SkCodec.h" 10 #include "SkCodec.h"
11 #include "SkCodecImageGenerator.h" 11 #include "SkCodecImageGenerator.h"
12 #include "SkColorSpaceXform.h"
12 #include "SkCommonFlags.h" 13 #include "SkCommonFlags.h"
13 #include "SkData.h" 14 #include "SkData.h"
14 #include "SkDocument.h" 15 #include "SkDocument.h"
15 #include "SkError.h" 16 #include "SkError.h"
17 #include "SkHalf.h"
16 #include "SkImageGenerator.h" 18 #include "SkImageGenerator.h"
17 #include "SkImageGeneratorCG.h" 19 #include "SkImageGeneratorCG.h"
18 #include "SkImageGeneratorWIC.h" 20 #include "SkImageGeneratorWIC.h"
19 #include "SkMallocPixelRef.h" 21 #include "SkMallocPixelRef.h"
20 #include "SkMultiPictureDraw.h" 22 #include "SkMultiPictureDraw.h"
21 #include "SkNullCanvas.h" 23 #include "SkNullCanvas.h"
22 #include "SkOSFile.h" 24 #include "SkOSFile.h"
23 #include "SkOpts.h" 25 #include "SkOpts.h"
24 #include "SkPictureData.h" 26 #include "SkPictureData.h"
25 #include "SkPictureRecorder.h" 27 #include "SkPictureRecorder.h"
(...skipping 909 matching lines...) Expand 10 before | Expand all | Expand 10 after
935 ColorCodecSrc::ColorCodecSrc(Path path, Mode mode) 937 ColorCodecSrc::ColorCodecSrc(Path path, Mode mode)
936 : fPath(path) 938 : fPath(path)
937 , fMode(mode) 939 , fMode(mode)
938 {} 940 {}
939 941
940 bool ColorCodecSrc::veto(SinkFlags flags) const { 942 bool ColorCodecSrc::veto(SinkFlags flags) const {
941 // Test to direct raster backends (8888 and 565). 943 // Test to direct raster backends (8888 and 565).
942 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDir ect; 944 return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDir ect;
943 } 945 }
944 946
947 static uint8_t clampFloatToByte(float v) {
948 v = v * 255.0f;
949 if (v > 255.0f) {
950 return 255;
951 } else if (v < 0.0f) {
952 return 0;
953 } else {
954 return (uint8_t) (v + 0.5f);
955 }
956 }
957
945 Error ColorCodecSrc::draw(SkCanvas* canvas) const { 958 Error ColorCodecSrc::draw(SkCanvas* canvas) const {
946 if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) { 959 if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) {
947 return Error::Nonfatal("No need to test color correction to 565 backend. "); 960 return Error::Nonfatal("No need to test color correction to 565 backend. ");
948 } 961 }
949 962
950 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 963 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
951 if (!encoded) { 964 if (!encoded) {
952 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); 965 return SkStringPrintf("Couldn't read %s.", fPath.c_str());
953 } 966 }
954 967
955 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 968 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
956 if (nullptr == codec.get()) { 969 if (nullptr == codec.get()) {
957 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); 970 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str());
958 } 971 }
959 972
960 SkImageInfo decodeInfo = codec->getInfo().makeColorType(kN32_SkColorType); 973 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
974 uint32_t width = info.width();
975 uint32_t height = info.height();
961 SkBitmap bitmap; 976 SkBitmap bitmap;
962 if (!bitmap.tryAllocPixels(decodeInfo)) { 977 if (!bitmap.tryAllocPixels(info)) {
963 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(), 978 return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(),
964 decodeInfo.width(), decodeInfo.height()); 979 info.width(), info.height());
980 }
981
982 SkImageInfo decodeInfo = info;
983 if (kBaseline_Mode != fMode) {
984 decodeInfo = decodeInfo.makeColorType(kRGBA_8888_SkColorType);
985 }
986
987 SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap. rowBytes());
988 if (SkCodec::kSuccess != r) {
989 return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_st r(), r);
965 } 990 }
966 991
967 switch (fMode) { 992 switch (fMode) {
968 case kBaseline_Mode: 993 case kBaseline_Mode:
969 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowB ytes())) {
970 case SkCodec::kSuccess:
971 break;
972 default:
973 // Everything else is considered a failure.
974 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str( ));
975 }
976 canvas->drawBitmap(bitmap, 0, 0); 994 canvas->drawBitmap(bitmap, 0, 0);
977 break; 995 break;
996 case kSrcToLinear_Mode: {
997 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
998 if (!srcSpace) {
999 return SkStringPrintf("Cannot test color correction without a sr c profile.");
1000 }
1001
1002 SkAutoTDelete<SkColorSpaceXform> xform(SkColorSpaceXform::New(srcSpa ce, nullptr,
1003 SkColorSpaceXform::kSrcToLinear_Op));
1004 if (!xform) {
1005 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?
1006 }
1007
1008 // Create a F16 destination buffer for the output of color conversio n.
1009 size_t rowBytes = width * SkColorTypeBytesPerPixel(kRGBA_F16_SkColor Type);
1010 SkAutoMalloc pixels(rowBytes * height);
1011
1012 // Apply the conversion to linear F16 pixels.
1013 SkISize size = SkISize::Make(width, height);
1014 xform->apply(pixels.get(), bitmap.getPixels(), size, rowBytes, bitma p.rowBytes());
1015
1016 // Converting to a linear color space is useful because most post-de code operations
1017 // assume linear pixels (ex: scaling, premultiplying, etc). However , we will want
1018 // 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
1019 // In order to test, we will assume that the dst wants sRGB pixels a nd convert the
1020 // linear intermediate to sRGB. This will make the output images lo ok normal (or
1021 // prettier than normal) if there are no bugs in our conversions.
1022 uint64_t* rowPtr = (uint64_t*) pixels.get();
1023 for (uint32_t y = 0; y < height; y++) {
1024 for (uint32_t x = 0; x < width; x++) {
1025 // Extract floats.
1026 uint64_t pixel = rowPtr[x];
1027 float linearR = SkHalfToFloat((pixel >> 0) & 0xFFFF);
1028 float linearG = SkHalfToFloat((pixel >> 16) & 0xFFFF);
1029 float linearB = SkHalfToFloat((pixel >> 32) & 0xFFFF);
1030 float linearA = SkHalfToFloat((pixel >> 48) & 0xFFFF);
1031
1032 // Currently we only support decodes to F16 when the encoded image has
1033 // a color space.
1034 SkColorSpace* colorSpace = codec->getColorSpace();
1035 SkASSERT(colorSpace);
1036
1037 // Convert to XYZ gamut.
1038 const SkMatrix44& toXYZ = colorSpace->xyz();
1039 float xyzR = linearR*toXYZ.getFloat(0, 0) + linearG*toXYZ.ge tFloat(1, 0) +
1040 linearB*toXYZ.getFloat(2, 0) + toXYZ.getFloat(3 , 0);
1041 float xyzG = linearR*toXYZ.getFloat(0, 1) + linearG*toXYZ.ge tFloat(1, 1) +
1042 linearB*toXYZ.getFloat(2, 1) + toXYZ.getFloat(3 , 1);
1043 float xyzB = linearR*toXYZ.getFloat(0, 2) + linearG*toXYZ.ge tFloat(1, 2) +
1044 linearB*toXYZ.getFloat(2, 2) + toXYZ.getFloat(3 , 2);
1045
1046 // Convert to sRGB gamut, using inverse sRGB matrix.
1047 float dstR = xyzR*3.13651f + xyzG*-1.61902f + xyzB*-0.490837 f;
1048 float dstG = xyzR*-0.978981f + xyzG*1.91625f + xyzB*0.033434 9f;
1049 float dstB = xyzR*0.072085f + xyzG*-0.229113f + xyzB*1.40577 f;
1050
1051 // Convert to sRGB gamma.
1052 float curveR = pow(dstR, 1.0f/2.2f);
1053 float curveG = pow(dstG, 1.0f/2.2f);
1054 float curveB = pow(dstB, 1.0f/2.2f);
1055
1056 uint32_t* ptr = (uint32_t*) bitmap.getAddr(x, y);
1057 *ptr = SkPackARGB32NoCheck(clampFloatToByte(linearA),
1058 clampFloatToByte(curveR),
1059 clampFloatToByte(curveG),
1060 clampFloatToByte(curveB));
1061 }
1062
1063 rowPtr = SkTAddOffset<uint64_t>(rowPtr, rowBytes);
1064 }
1065
1066 canvas->drawBitmap(bitmap, 0, 0);
1067 break;
1068 }
978 default: 1069 default:
979 SkASSERT(false); 1070 SkASSERT(false);
980 return "Invalid fMode"; 1071 return "Invalid fMode";
981 } 1072 }
982 return ""; 1073 return "";
983 } 1074 }
984 1075
985 SkISize ColorCodecSrc::size() const { 1076 SkISize ColorCodecSrc::size() const {
986 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); 1077 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str()));
987 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); 1078 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded));
(...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after
1563 skr.visit(i, drawsAsSingletonPictures); 1654 skr.visit(i, drawsAsSingletonPictures);
1564 } 1655 }
1565 sk_sp<SkPicture> macroPic(macroRec.finishRecordingAsPicture()); 1656 sk_sp<SkPicture> macroPic(macroRec.finishRecordingAsPicture());
1566 1657
1567 canvas->drawPicture(macroPic); 1658 canvas->drawPicture(macroPic);
1568 return check_against_reference(bitmap, src, fSink); 1659 return check_against_reference(bitmap, src, fSink);
1569 }); 1660 });
1570 } 1661 }
1571 1662
1572 } // namespace DM 1663 } // namespace DM
OLDNEW
« 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