1 /*
2 * Copyright 2012 The Android Open Source Project
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 #ifndef SkImageEncoderFns_DEFINED
9 #define SkImageEncoderFns_DEFINED
10
11 /**
12 * Functions to transform scanlines between packed-pixel formats.
13 */
14
15 #include "SkBitmap.h"
16 #include "SkColor.h"
17 #include "SkColorPriv.h"
18 #include "SkColorSpace_Base.h"
19 #include "SkICC.h"
20 #include "SkOpts.h"
21 #include "SkPreConfig.h"
22 #include "SkRasterPipeline.h"
23 #include "SkUnPreMultiply.h"
24 #include "SkUnPreMultiplyPriv.h"
25
26 /**
27 * Function template for transforming scanlines.
28 * Transform 'width' pixels from 'src' buffer into 'dst' buffer,
29 * repacking color channel data as appropriate for the given transformation.
30 * 'bpp' is bytes per pixel in the 'src' buffer.
31 */
32 typedef void (*transform_scanline_proc)(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
33 int width, int bpp, const SkPMColor* colors);
34
35 /**
36 * Identity transformation: just copy bytes from src to dst.
37 */
transform_scanline_memcpy(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int bpp,const SkPMColor *)38 static inline void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
39 int width, int bpp, const SkPMColor*) {
40 memcpy(dst, src, width * bpp);
41 }
42
transform_scanline_index8_opaque(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor * colors)43 static inline void transform_scanline_index8_opaque(char* SK_RESTRICT dst,
44 const char* SK_RESTRICT src, int width, int,
45 const SkPMColor* colors) {
46 for (int i = 0; i < width; i++) {
47 const uint32_t c = colors[(uint8_t)*src++];
48 dst[0] = SkGetPackedR32(c);
49 dst[1] = SkGetPackedG32(c);
50 dst[2] = SkGetPackedB32(c);
51 dst += 3;
52 }
53 }
54
transform_scanline_index8_unpremul(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor * colors)55 static inline void transform_scanline_index8_unpremul(char* SK_RESTRICT dst,
56 const char* SK_RESTRICT src, int width, int,
57 const SkPMColor* colors) {
58 uint32_t* SK_RESTRICT dst32 = (uint32_t*) dst;
59 for (int i = 0; i < width; i++) {
60 // This function swizzles R and B on platforms where SkPMColor is BGRA. This is
61 // exactly what we want.
62 dst32[i] = SkSwizzle_RGBA_to_PMColor(colors[(uint8_t)*src++]);
63 }
64 }
65
transform_scanline_gray(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor * colors)66 static inline void transform_scanline_gray(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
67 int width, int, const SkPMColor* colors) {
68 for (int i = 0; i < width; i++) {
69 const uint8_t g = (uint8_t) *src++;
70 dst[0] = g;
71 dst[1] = g;
72 dst[2] = g;
73 dst += 3;
74 }
75 }
76
77 /**
78 * Transform from kRGB_565_Config to 3-bytes-per-pixel RGB.
79 * Alpha channel data is not present in kRGB_565_Config format, so there is no
80 * alpha channel data to preserve.
81 */
transform_scanline_565(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)82 static inline void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
83 int width, int, const SkPMColor*) {
84 const uint16_t* srcP = (const uint16_t*)src;
85 for (int i = 0; i < width; i++) {
86 unsigned c = *srcP++;
87 *dst++ = SkPacked16ToR32(c);
88 *dst++ = SkPacked16ToG32(c);
89 *dst++ = SkPacked16ToB32(c);
90 }
91 }
92
93 /**
94 * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB.
95 * Alpha channel data is abandoned.
96 */
transform_scanline_RGBX(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)97 static inline void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
98 int width, int, const SkPMColor*) {
99 const uint32_t* srcP = (const SkPMColor*)src;
100 for (int i = 0; i < width; i++) {
101 uint32_t c = *srcP++;
102 *dst++ = (c >> 0) & 0xFF;
103 *dst++ = (c >> 8) & 0xFF;
104 *dst++ = (c >> 16) & 0xFF;
105 }
106 }
107
108 /**
109 * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB.
110 * Alpha channel data is abandoned.
111 */
transform_scanline_BGRX(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)112 static inline void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
113 int width, int, const SkPMColor*) {
114 const uint32_t* srcP = (const SkPMColor*)src;
115 for (int i = 0; i < width; i++) {
116 uint32_t c = *srcP++;
117 *dst++ = (c >> 16) & 0xFF;
118 *dst++ = (c >> 8) & 0xFF;
119 *dst++ = (c >> 0) & 0xFF;
120 }
121 }
122
123 /**
124 * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB.
125 * Alpha channel data, if any, is abandoned.
126 */
transform_scanline_444(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)127 static inline void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
128 int width, int, const SkPMColor*) {
129 const SkPMColor16* srcP = (const SkPMColor16*)src;
130 for (int i = 0; i < width; i++) {
131 SkPMColor16 c = *srcP++;
132 *dst++ = SkPacked4444ToR32(c);
133 *dst++ = SkPacked4444ToG32(c);
134 *dst++ = SkPacked4444ToB32(c);
135 }
136 }
137
138 /**
139 * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
140 */
transform_scanline_rgbA(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)141 static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
142 int width, int, const SkPMColor*) {
143 SkUnpremultiplyRow<false>((uint32_t*) dst, (const uint32_t*) src, width);
144 }
145
146 /**
147 * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
148 */
transform_scanline_bgrA(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)149 static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
150 int width, int, const SkPMColor*) {
151 SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width);
152 }
153
154 template <bool kIsRGBA>
transform_scanline_unpremultiply_sRGB(void * dst,const void * src,int width)155 static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width) {
156 SkRasterPipeline_<256> p;
157 if (kIsRGBA) {
158 p.append(SkRasterPipeline::load_8888, &src);
159 } else {
160 p.append(SkRasterPipeline::load_bgra, &src);
161 }
162
163 p.append_from_srgb(kPremul_SkAlphaType);
164 p.append(SkRasterPipeline::unpremul);
165 p.append(SkRasterPipeline::to_srgb);
166 p.append(SkRasterPipeline::store_8888, &dst);
167 p.run(0,0, width);
168 }
169
170 /**
171 * Premultiply RGBA to rgbA.
172 */
transform_scanline_to_premul_legacy(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)173 static inline void transform_scanline_to_premul_legacy(char* SK_RESTRICT dst,
174 const char* SK_RESTRICT src,
175 int width, int, const SkPMColor*) {
176 SkOpts::RGBA_to_rgbA((uint32_t*)dst, (const uint32_t*)src, width);
177 }
178
179 /**
180 * Premultiply RGBA to rgbA linearly.
181 */
transform_scanline_to_premul_linear(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)182 static inline void transform_scanline_to_premul_linear(char* SK_RESTRICT dst,
183 const char* SK_RESTRICT src,
184 int width, int, const SkPMColor*) {
185 SkRasterPipeline_<256> p;
186 p.append(SkRasterPipeline::load_8888, (const void**) &src);
187 p.append_from_srgb(kUnpremul_SkAlphaType);
188 p.append(SkRasterPipeline::premul);
189 p.append(SkRasterPipeline::to_srgb);
190 p.append(SkRasterPipeline::store_8888, (void**) &dst);
191 p.run(0,0, width);
192 }
193
194 /**
195 * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
196 */
transform_scanline_srgbA(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)197 static inline void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
198 int width, int, const SkPMColor*) {
199 transform_scanline_unpremultiply_sRGB<true>(dst, src, width);
200 }
201
202 /**
203 * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
204 */
transform_scanline_sbgrA(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)205 static inline void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
206 int width, int, const SkPMColor*) {
207 transform_scanline_unpremultiply_sRGB<false>(dst, src, width);
208 }
209
210 /**
211 * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
212 */
transform_scanline_BGRA(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)213 static inline void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
214 int width, int, const SkPMColor*) {
215 const uint32_t* srcP = (const SkPMColor*)src;
216 for (int i = 0; i < width; i++) {
217 uint32_t c = *srcP++;
218 *dst++ = (c >> 16) & 0xFF;
219 *dst++ = (c >> 8) & 0xFF;
220 *dst++ = (c >> 0) & 0xFF;
221 *dst++ = (c >> 24) & 0xFF;
222 }
223 }
224
225 /**
226 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA,
227 * with scaling of RGB based on alpha channel.
228 */
transform_scanline_4444(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)229 static inline void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
230 int width, int, const SkPMColor*) {
231 const SkPMColor16* srcP = (const SkPMColor16*)src;
232 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
233
234 for (int i = 0; i < width; i++) {
235 SkPMColor16 c = *srcP++;
236 unsigned a = SkPacked4444ToA32(c);
237 unsigned r = SkPacked4444ToR32(c);
238 unsigned g = SkPacked4444ToG32(c);
239 unsigned b = SkPacked4444ToB32(c);
240
241 if (0 != a && 255 != a) {
242 SkUnPreMultiply::Scale scale = table[a];
243 r = SkUnPreMultiply::ApplyScale(scale, r);
244 g = SkUnPreMultiply::ApplyScale(scale, g);
245 b = SkUnPreMultiply::ApplyScale(scale, b);
246 }
247 *dst++ = r;
248 *dst++ = g;
249 *dst++ = b;
250 *dst++ = a;
251 }
252 }
253
254 /**
255 * Transform from kRGBA_F16 to 8-bytes-per-pixel RGBA.
256 */
transform_scanline_F16(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)257 static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
258 int width, int, const SkPMColor*) {
259 SkRasterPipeline_<256> p;
260 p.append(SkRasterPipeline::load_f16, (const void**) &src);
261 p.append(SkRasterPipeline::to_srgb);
262 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
263 p.run(0,0, width);
264 }
265
266 /**
267 * Transform from kPremul, kRGBA_F16 to 8-bytes-per-pixel RGBA.
268 */
transform_scanline_F16_premul(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)269 static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
270 int width, int, const SkPMColor*) {
271 SkRasterPipeline_<256> p;
272 p.append(SkRasterPipeline::load_f16, (const void**) &src);
273 p.append(SkRasterPipeline::unpremul);
274 p.append(SkRasterPipeline::to_srgb);
275 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
276 p.run(0,0, width);
277 }
278
279 /**
280 * Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA.
281 */
transform_scanline_F16_to_8888(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)282 static inline void transform_scanline_F16_to_8888(char* SK_RESTRICT dst,
283 const char* SK_RESTRICT src, int width, int,
284 const SkPMColor*) {
285 SkRasterPipeline_<256> p;
286 p.append(SkRasterPipeline::load_f16, (const void**) &src);
287 p.append(SkRasterPipeline::to_srgb);
288 p.append(SkRasterPipeline::store_8888, (void**) &dst);
289 p.run(0,0, width);
290 }
291
292 /**
293 * Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA.
294 */
transform_scanline_F16_premul_to_8888(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)295 static inline void transform_scanline_F16_premul_to_8888(char* SK_RESTRICT dst,
296 const char* SK_RESTRICT src, int width,
297 int, const SkPMColor*) {
298 SkRasterPipeline_<256> p;
299 p.append(SkRasterPipeline::load_f16, (const void**) &src);
300 p.append(SkRasterPipeline::unpremul);
301 p.append(SkRasterPipeline::to_srgb);
302 p.append(SkRasterPipeline::store_8888, (void**) &dst);
303 p.run(0,0, width);
304 }
305
306 /**
307 * Transform from kUnpremul, kRGBA_F16 to premultiplied rgbA 8888.
308 */
transform_scanline_F16_to_premul_8888(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)309 static inline void transform_scanline_F16_to_premul_8888(char* SK_RESTRICT dst,
310 const char* SK_RESTRICT src, int width, int, const SkPMColor*) {
311 SkRasterPipeline_<256> p;
312 p.append(SkRasterPipeline::load_f16, (const void**) &src);
313 p.append(SkRasterPipeline::premul);
314 p.append(SkRasterPipeline::to_srgb);
315 p.append(SkRasterPipeline::store_8888, (void**) &dst);
316 p.run(0,0, width);
317 }
318
icc_from_color_space(const SkImageInfo & info)319 static inline sk_sp<SkData> icc_from_color_space(const SkImageInfo& info) {
320 SkColorSpace* cs = info.colorSpace();
321 if (!cs) {
322 return nullptr;
323 }
324
325 sk_sp<SkColorSpace> owned;
326 if (kRGBA_F16_SkColorType == info.colorType()) {
327 owned = as_CSB(cs)->makeSRGBGamma();
328 cs = owned.get();
329 }
330
331 SkColorSpaceTransferFn fn;
332 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
333 if (cs->isNumericalTransferFn(&fn) && cs->toXYZD50(&toXYZD50)) {
334 return SkICC::WriteToICC(fn, toXYZD50);
335 }
336
337 // TODO: Should we support writing ICC profiles for additional color spaces?
338 return nullptr;
339 }
340
341 #endif // SkImageEncoderFns_DEFINED
342