OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |