blob: afc949811bc0fab9f103b6f65e4f3c59f384c236 [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
8#include "../third_party/skcms/skcms.h"
Mike Kleinfd731e42018-10-23 13:21:53 -04009#include "SkCanvas.h"
Mike Klein7af351a2018-07-27 09:54:43 -040010#include "SkColorSpacePriv.h"
11#include "SkData.h"
12#include "SkImage.h"
13#include "SkStream.h"
Mike Kleinfd731e42018-10-23 13:21:53 -040014#include "SkSurface.h"
15
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();
31 if (dst_profile_path) {
32 sk_sp<SkData> blob = SkData::MakeFromFileName(dst_profile_path);
33 if (!skcms_Parse(blob->data(), blob->size(), &dst_profile)) {
34 SkDebugf("Can't parse %s as an ICC profile.\n", dst_profile_path);
35 return 1;
36 }
37 }
38
39 auto blob = SkData::MakeFromFileName(source_path);
40
41 skcms_ICCProfile src_profile;
42 if (skcms_Parse(blob->data(), blob->size(), &src_profile)) {
43 // Transform white, black, primaries, and primary complements.
44 float src[] = {
45 0,0,0,
46 1,1,1,
47
48 1,0,0,
49 0,1,0,
50 0,0,1,
51
52 0,1,1,
53 1,0,1,
54 1,1,0,
55 };
56 float dst[24] = {0};
57
58 if (!skcms_Transform(
59 src, skcms_PixelFormat_RGB_fff, skcms_AlphaFormat_Unpremul, &src_profile,
60 dst, skcms_PixelFormat_RGB_fff, skcms_AlphaFormat_Unpremul, &dst_profile,
61 8)) {
62 SkDebugf("Cannot transform.\n");
63 return 1;
64 }
65 for (int i = 0; i < 8; i++) {
66 SkDebugf("(%g, %g, %g) --> (%+.4f, %+.4f, %+.4f)\n",
67 src[3*i+0], src[3*i+1], src[3*i+2],
68 dst[3*i+0], dst[3*i+1], dst[3*i+2]);
69 }
70 return 0;
71 }
72
73 sk_sp<SkImage> image = SkImage::MakeFromEncoded(blob);
Mike Klein7af351a2018-07-27 09:54:43 -040074 if (!image) {
Mike Klein06a215b2018-09-06 14:21:09 -040075 SkDebugf("Couldn't decode %s as an SkImage or an ICC profile.\n", source_path);
Mike Klein7af351a2018-07-27 09:54:43 -040076 return 1;
77 }
78
79 image = image->makeRasterImage();
80 if (!image) {
81 SkDebugf("Converting to raster image failed.\n");
82 return 1;
83 }
84
85 SkPixmap pixmap;
86 if (!image->peekPixels(&pixmap)) {
87 SkDebugf("We really should be able to peek raster pixels.\n");
88 return 1;
89 }
90
Mike Kleinfd731e42018-10-23 13:21:53 -040091 sk_sp<SkColorSpace> dst_cs = SkColorSpace::Make(dst_profile);
92 if (!dst_cs) {
93 SkDebugf("We can't convert to this destination profile.\n");
94 return 1;
95 }
Mike Klein7af351a2018-07-27 09:54:43 -040096
Mike Kleinfd731e42018-10-23 13:21:53 -040097 { // transform with skcms
98 SkColorSpace* src_cs = image->colorSpace() ? image->colorSpace()
99 : sk_srgb_singleton();
100 src_cs->toProfile(&src_profile);
101
102 skcms_PixelFormat fmt;
103 switch (pixmap.colorType()) {
104 case kRGBA_8888_SkColorType: fmt = skcms_PixelFormat_RGBA_8888; break;
105 case kBGRA_8888_SkColorType: fmt = skcms_PixelFormat_BGRA_8888; break;
106 default:
107 SkDebugf("color type %d not yet supported, imgcvt.cpp needs an update.\n",
108 pixmap.colorType());
109 return 1;
110 }
111
112 if (pixmap.alphaType() != kPremul_SkAlphaType) {
113 SkDebugf("not premul, that's weird.\n");
Mike Klein7af351a2018-07-27 09:54:43 -0400114 return 1;
Mike Kleinfd731e42018-10-23 13:21:53 -0400115 }
116 auto alpha = skcms_AlphaFormat_PremulAsEncoded;
117
118 if (pixmap.rowBytes() != (size_t)pixmap.width() * pixmap.info().bytesPerPixel()) {
119 SkDebugf("not a tight pixmap, need a loop here\n");
120 return 1;
121 }
122
123 if (!skcms_Transform(pixmap.addr(), fmt,alpha, &src_profile,
124 pixmap.writable_addr(), fmt,alpha, &dst_profile,
125 pixmap.width() * pixmap.height())) {
126 SkDebugf("skcms_Transform() failed\n");
127 return 1;
128 }
129 pixmap.setColorSpace(dst_cs);
130
131 write_png("transformed-skcms.png", SkImage::MakeRasterCopy(pixmap));
Mike Klein7af351a2018-07-27 09:54:43 -0400132 }
133
Mike Kleinfd731e42018-10-23 13:21:53 -0400134 { // transform with writePixels()
135 sk_sp<SkSurface> surface = SkSurface::MakeRaster(pixmap.info().makeColorSpace(dst_cs));
136 if (!surface) {
137 SkDebugf("couldn't create a surface\n");
138 return 1;
139 }
Mike Klein7af351a2018-07-27 09:54:43 -0400140
Mike Kleinfd731e42018-10-23 13:21:53 -0400141 surface->writePixels(pixmap, 0,0);
142
143 write_png("transformed-writepixels.png", surface->makeImageSnapshot());
Mike Klein7af351a2018-07-27 09:54:43 -0400144 }
145
Mike Kleinfd731e42018-10-23 13:21:53 -0400146 { // transform by drawing
147 sk_sp<SkSurface> surface = SkSurface::MakeRaster(pixmap.info().makeColorSpace(dst_cs));
148 if (!surface) {
149 SkDebugf("couldn't create a surface\n");
150 return 1;
151 }
Mike Klein7af351a2018-07-27 09:54:43 -0400152
Mike Kleinfd731e42018-10-23 13:21:53 -0400153 surface->getCanvas()->drawImage(image, 0,0);
Mike Klein7af351a2018-07-27 09:54:43 -0400154
Mike Kleinfd731e42018-10-23 13:21:53 -0400155 write_png("transformed-draw.png", surface->makeImageSnapshot());
156 }
Mike Klein7af351a2018-07-27 09:54:43 -0400157
158 return 0;
159}