blob: 5c024f0462a761f2a95fc29cd3069042dc401983 [file] [log] [blame]
Mike Klein7af351a2018-07-27 09:54:43 -04001/*
2* Copyright 2018 Google Inc.
3*
4* Use of this source code is governed by a BSD-style license that can be
5* found in the LICENSE file.
6*/
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkCanvas.h"
9#include "include/core/SkData.h"
10#include "include/core/SkImage.h"
11#include "include/core/SkStream.h"
12#include "include/core/SkSurface.h"
Brian Osmanea236bf2019-04-29 10:28:22 -040013#include "include/third_party/skcms/skcms.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/core/SkColorSpacePriv.h"
Mike Kleinfd731e42018-10-23 13:21:53 -040015
16static void write_png(const char* path, sk_sp<SkImage> img) {
17 sk_sp<SkData> png = img->encodeToData();
18 SkFILEWStream(path).write(png->data(), png->size());
19}
Mike Klein7af351a2018-07-27 09:54:43 -040020
21int main(int argc, char** argv) {
Mike Klein06a215b2018-09-06 14:21:09 -040022 const char* source_path = argc > 1 ? argv[1] : nullptr;
23 if (!source_path) {
24 SkDebugf("Please pass an image or profile to convert"
25 " as the first argument to this program.\n");
Mike Klein7af351a2018-07-27 09:54:43 -040026 return 1;
27 }
28
Mike Klein06a215b2018-09-06 14:21:09 -040029 const char* dst_profile_path = argc > 2 ? argv[2] : nullptr;
30 skcms_ICCProfile dst_profile = *skcms_sRGB_profile();
Brian Osman18df87e2019-01-04 11:03:42 -050031 sk_sp<SkData> dst_blob;
Mike Klein06a215b2018-09-06 14:21:09 -040032 if (dst_profile_path) {
Brian Osman18df87e2019-01-04 11:03:42 -050033 dst_blob = SkData::MakeFromFileName(dst_profile_path);
34 if (!skcms_Parse(dst_blob->data(), dst_blob->size(), &dst_profile)) {
Mike Klein06a215b2018-09-06 14:21:09 -040035 SkDebugf("Can't parse %s as an ICC profile.\n", dst_profile_path);
36 return 1;
37 }
38 }
39
40 auto blob = SkData::MakeFromFileName(source_path);
41
42 skcms_ICCProfile src_profile;
43 if (skcms_Parse(blob->data(), blob->size(), &src_profile)) {
44 // Transform white, black, primaries, and primary complements.
45 float src[] = {
46 0,0,0,
47 1,1,1,
48
49 1,0,0,
50 0,1,0,
51 0,0,1,
52
53 0,1,1,
54 1,0,1,
55 1,1,0,
56 };
57 float dst[24] = {0};
58
59 if (!skcms_Transform(
60 src, skcms_PixelFormat_RGB_fff, skcms_AlphaFormat_Unpremul, &src_profile,
61 dst, skcms_PixelFormat_RGB_fff, skcms_AlphaFormat_Unpremul, &dst_profile,
62 8)) {
63 SkDebugf("Cannot transform.\n");
64 return 1;
65 }
66 for (int i = 0; i < 8; i++) {
67 SkDebugf("(%g, %g, %g) --> (%+.4f, %+.4f, %+.4f)\n",
68 src[3*i+0], src[3*i+1], src[3*i+2],
69 dst[3*i+0], dst[3*i+1], dst[3*i+2]);
70 }
71 return 0;
72 }
73
74 sk_sp<SkImage> image = SkImage::MakeFromEncoded(blob);
Mike Klein7af351a2018-07-27 09:54:43 -040075 if (!image) {
Mike Klein06a215b2018-09-06 14:21:09 -040076 SkDebugf("Couldn't decode %s as an SkImage or an ICC profile.\n", source_path);
Mike Klein7af351a2018-07-27 09:54:43 -040077 return 1;
78 }
79
80 image = image->makeRasterImage();
81 if (!image) {
82 SkDebugf("Converting to raster image failed.\n");
83 return 1;
84 }
85
86 SkPixmap pixmap;
87 if (!image->peekPixels(&pixmap)) {
88 SkDebugf("We really should be able to peek raster pixels.\n");
89 return 1;
90 }
91
Mike Kleinfd731e42018-10-23 13:21:53 -040092 sk_sp<SkColorSpace> dst_cs = SkColorSpace::Make(dst_profile);
93 if (!dst_cs) {
Brian Osman18df87e2019-01-04 11:03:42 -050094 SkDebugf("We can't convert to this destination profile as-is. Coercing it.\n");
95 if (skcms_MakeUsableAsDestinationWithSingleCurve(&dst_profile)) {
96 dst_cs = SkColorSpace::Make(dst_profile);
97 }
98 if (!dst_cs) {
99 SkDebugf("We can't convert to this destination profile at all.\n");
100 return 1;
101 }
Mike Kleinfd731e42018-10-23 13:21:53 -0400102 }
Mike Klein7af351a2018-07-27 09:54:43 -0400103
Mike Kleinfd731e42018-10-23 13:21:53 -0400104 { // transform with skcms
105 SkColorSpace* src_cs = image->colorSpace() ? image->colorSpace()
106 : sk_srgb_singleton();
107 src_cs->toProfile(&src_profile);
108
109 skcms_PixelFormat fmt;
110 switch (pixmap.colorType()) {
111 case kRGBA_8888_SkColorType: fmt = skcms_PixelFormat_RGBA_8888; break;
112 case kBGRA_8888_SkColorType: fmt = skcms_PixelFormat_BGRA_8888; break;
113 default:
114 SkDebugf("color type %d not yet supported, imgcvt.cpp needs an update.\n",
115 pixmap.colorType());
116 return 1;
117 }
118
Brian Osman18df87e2019-01-04 11:03:42 -0500119 if (pixmap.alphaType() == kUnpremul_SkAlphaType) {
Mike Kleinfd731e42018-10-23 13:21:53 -0400120 SkDebugf("not premul, that's weird.\n");
Mike Klein7af351a2018-07-27 09:54:43 -0400121 return 1;
Mike Kleinfd731e42018-10-23 13:21:53 -0400122 }
123 auto alpha = skcms_AlphaFormat_PremulAsEncoded;
124
125 if (pixmap.rowBytes() != (size_t)pixmap.width() * pixmap.info().bytesPerPixel()) {
126 SkDebugf("not a tight pixmap, need a loop here\n");
127 return 1;
128 }
129
130 if (!skcms_Transform(pixmap.addr(), fmt,alpha, &src_profile,
131 pixmap.writable_addr(), fmt,alpha, &dst_profile,
132 pixmap.width() * pixmap.height())) {
133 SkDebugf("skcms_Transform() failed\n");
134 return 1;
135 }
136 pixmap.setColorSpace(dst_cs);
137
138 write_png("transformed-skcms.png", SkImage::MakeRasterCopy(pixmap));
Mike Klein7af351a2018-07-27 09:54:43 -0400139 }
140
Mike Kleinfd731e42018-10-23 13:21:53 -0400141 { // transform with writePixels()
142 sk_sp<SkSurface> surface = SkSurface::MakeRaster(pixmap.info().makeColorSpace(dst_cs));
143 if (!surface) {
144 SkDebugf("couldn't create a surface\n");
145 return 1;
146 }
Mike Klein7af351a2018-07-27 09:54:43 -0400147
Mike Kleinfd731e42018-10-23 13:21:53 -0400148 surface->writePixels(pixmap, 0,0);
149
150 write_png("transformed-writepixels.png", surface->makeImageSnapshot());
Mike Klein7af351a2018-07-27 09:54:43 -0400151 }
152
Mike Kleinfd731e42018-10-23 13:21:53 -0400153 { // transform by drawing
154 sk_sp<SkSurface> surface = SkSurface::MakeRaster(pixmap.info().makeColorSpace(dst_cs));
155 if (!surface) {
156 SkDebugf("couldn't create a surface\n");
157 return 1;
158 }
Mike Klein7af351a2018-07-27 09:54:43 -0400159
Mike Kleinfd731e42018-10-23 13:21:53 -0400160 surface->getCanvas()->drawImage(image, 0,0);
Mike Klein7af351a2018-07-27 09:54:43 -0400161
Mike Kleinfd731e42018-10-23 13:21:53 -0400162 write_png("transformed-draw.png", surface->makeImageSnapshot());
163 }
Mike Klein7af351a2018-07-27 09:54:43 -0400164
165 return 0;
166}