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 "SkColorData.h"
18 #include "SkICC.h"
19 #include "SkOpts.h"
20 #include "SkPreConfig.h"
21 #include "SkRasterPipeline.h"
22 #include "SkUnPreMultiply.h"
23 #include "SkUnPreMultiplyPriv.h"
24 #include "../jumper/SkJumper.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 kAlpha_8_Config to 2-bytes-per-pixel GrayAlpha.
95 */
transform_scanline_A8_to_GrayAlpha(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)96 static inline void transform_scanline_A8_to_GrayAlpha(char* SK_RESTRICT dst,
97 const char* SK_RESTRICT src,
98 int width, int, const SkPMColor*) {
99 for (int i = 0; i < width; i++) {
100 *dst++ = 0; // gray (ignored)
101 *dst++ = *src++; // alpha
102 }
103 }
104
105 /**
106 * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB.
107 * Alpha channel data is abandoned.
108 */
transform_scanline_RGBX(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)109 static inline void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
110 int width, int, const SkPMColor*) {
111 const uint32_t* srcP = (const SkPMColor*)src;
112 for (int i = 0; i < width; i++) {
113 uint32_t c = *srcP++;
114 *dst++ = (c >> 0) & 0xFF;
115 *dst++ = (c >> 8) & 0xFF;
116 *dst++ = (c >> 16) & 0xFF;
117 }
118 }
119
120 /**
121 * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB.
122 * Alpha channel data is abandoned.
123 */
transform_scanline_BGRX(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)124 static inline void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
125 int width, int, const SkPMColor*) {
126 const uint32_t* srcP = (const SkPMColor*)src;
127 for (int i = 0; i < width; i++) {
128 uint32_t c = *srcP++;
129 *dst++ = (c >> 16) & 0xFF;
130 *dst++ = (c >> 8) & 0xFF;
131 *dst++ = (c >> 0) & 0xFF;
132 }
133 }
134
135 /**
136 * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB.
137 * Alpha channel data, if any, is abandoned.
138 */
transform_scanline_444(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)139 static inline void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
140 int width, int, const SkPMColor*) {
141 const SkPMColor16* srcP = (const SkPMColor16*)src;
142 for (int i = 0; i < width; i++) {
143 SkPMColor16 c = *srcP++;
144 *dst++ = SkPacked4444ToR32(c);
145 *dst++ = SkPacked4444ToG32(c);
146 *dst++ = SkPacked4444ToB32(c);
147 }
148 }
149
150 /**
151 * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
152 */
transform_scanline_rgbA(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)153 static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
154 int width, int, const SkPMColor*) {
155 SkUnpremultiplyRow<false>((uint32_t*) dst, (const uint32_t*) src, width);
156 }
157
158 /**
159 * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
160 */
transform_scanline_bgrA(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)161 static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
162 int width, int, const SkPMColor*) {
163 SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width);
164 }
165
166 template <bool kIsRGBA>
transform_scanline_unpremultiply_sRGB(void * dst,const void * src,int width)167 static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width) {
168 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
169 dst_ctx = { (void*)dst, 0 };
170 SkRasterPipeline_<256> p;
171 if (kIsRGBA) {
172 p.append(SkRasterPipeline::load_8888, &src_ctx);
173 } else {
174 p.append(SkRasterPipeline::load_bgra, &src_ctx);
175 }
176
177 p.append(SkRasterPipeline::from_srgb);
178 p.append(SkRasterPipeline::unpremul);
179 p.append(SkRasterPipeline::to_srgb);
180 p.append(SkRasterPipeline::store_8888, &dst_ctx);
181 p.run(0,0, width,1);
182 }
183
184 /**
185 * Premultiply RGBA to rgbA.
186 */
transform_scanline_to_premul_legacy(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)187 static inline void transform_scanline_to_premul_legacy(char* SK_RESTRICT dst,
188 const char* SK_RESTRICT src,
189 int width, int, const SkPMColor*) {
190 SkOpts::RGBA_to_rgbA((uint32_t*)dst, (const uint32_t*)src, width);
191 }
192
193 /**
194 * Premultiply RGBA to rgbA linearly.
195 */
transform_scanline_to_premul_linear(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)196 static inline void transform_scanline_to_premul_linear(char* SK_RESTRICT dst,
197 const char* SK_RESTRICT src,
198 int width, int, const SkPMColor*) {
199 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
200 dst_ctx = { (void*)dst, 0 };
201 SkRasterPipeline_<256> p;
202 p.append(SkRasterPipeline::load_8888, &src_ctx);
203 p.append(SkRasterPipeline::from_srgb);
204 p.append(SkRasterPipeline::premul);
205 p.append(SkRasterPipeline::to_srgb);
206 p.append(SkRasterPipeline::store_8888, &dst_ctx);
207 p.run(0,0, width,1);
208 }
209
210 /**
211 * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
212 */
transform_scanline_srgbA(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)213 static inline void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
214 int width, int, const SkPMColor*) {
215 transform_scanline_unpremultiply_sRGB<true>(dst, src, width);
216 }
217
218 /**
219 * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
220 */
transform_scanline_sbgrA(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)221 static inline void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
222 int width, int, const SkPMColor*) {
223 transform_scanline_unpremultiply_sRGB<false>(dst, src, width);
224 }
225
226 /**
227 * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
228 */
transform_scanline_BGRA(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)229 static inline void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
230 int width, int, const SkPMColor*) {
231 const uint32_t* srcP = (const SkPMColor*)src;
232 for (int i = 0; i < width; i++) {
233 uint32_t c = *srcP++;
234 *dst++ = (c >> 16) & 0xFF;
235 *dst++ = (c >> 8) & 0xFF;
236 *dst++ = (c >> 0) & 0xFF;
237 *dst++ = (c >> 24) & 0xFF;
238 }
239 }
240
241 /**
242 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA,
243 * with scaling of RGB based on alpha channel.
244 */
transform_scanline_4444(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)245 static inline void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
246 int width, int, const SkPMColor*) {
247 const SkPMColor16* srcP = (const SkPMColor16*)src;
248 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
249
250 for (int i = 0; i < width; i++) {
251 SkPMColor16 c = *srcP++;
252 unsigned a = SkPacked4444ToA32(c);
253 unsigned r = SkPacked4444ToR32(c);
254 unsigned g = SkPacked4444ToG32(c);
255 unsigned b = SkPacked4444ToB32(c);
256
257 if (0 != a && 255 != a) {
258 SkUnPreMultiply::Scale scale = table[a];
259 r = SkUnPreMultiply::ApplyScale(scale, r);
260 g = SkUnPreMultiply::ApplyScale(scale, g);
261 b = SkUnPreMultiply::ApplyScale(scale, b);
262 }
263 *dst++ = r;
264 *dst++ = g;
265 *dst++ = b;
266 *dst++ = a;
267 }
268 }
269
270 // 888x is opaque RGB in four bytes, with 8 junk bits. We convert that to 3 byte RGB.
transform_scanline_888x(char * dst,const char * src,int width,int,const SkPMColor *)271 static inline void transform_scanline_888x(char* dst, const char* src,
272 int width, int, const SkPMColor*) {
273 while (width --> 0) {
274 dst[0] = src[0];
275 dst[1] = src[1];
276 dst[2] = src[2];
277 dst += 3;
278 src += 4;
279 }
280 }
281
282 // 101010x is opaque RGB in four bytes, with 2 bits junk. We convert to 6 byte RGB (big endian).
transform_scanline_101010x(char * dst,const char * src,int width,int,const SkPMColor *)283 static inline void transform_scanline_101010x(char* dst, const char* src,
284 int width, int, const SkPMColor*) {
285 auto d = ( uint16_t*)dst;
286 auto s = (const uint32_t*)src;
287 while (width --> 0) {
288 uint32_t r = (*s >> 0) & 1023,
289 g = (*s >> 10) & 1023,
290 b = (*s >> 20) & 1023;
291
292 // Scale 10-bit unorms to 16-bit by replicating the most significant bits.
293 r = (r << 6) | (r >> 4);
294 g = (g << 6) | (g >> 4);
295 b = (b << 6) | (b >> 4);
296
297 // Store big-endian.
298 d[0] = (r >> 8) | (r << 8);
299 d[1] = (g >> 8) | (g << 8);
300 d[2] = (b >> 8) | (b << 8);
301
302 d += 3; // 3 channels
303 s += 1; // 1 whole pixel
304 }
305 }
306
transform_scanline_1010102(char * dst,const char * src,int width,int,const SkPMColor *)307 static inline void transform_scanline_1010102(char* dst, const char* src,
308 int width, int, const SkPMColor*) {
309 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
310 dst_ctx = { (void*)dst, 0 };
311 SkRasterPipeline_<256> p;
312 p.append(SkRasterPipeline::load_1010102, &src_ctx);
313 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
314 p.run(0,0, width,1);
315 }
316
transform_scanline_1010102_premul(char * dst,const char * src,int width,int,const SkPMColor *)317 static inline void transform_scanline_1010102_premul(char* dst, const char* src,
318 int width, int, const SkPMColor*) {
319 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
320 dst_ctx = { (void*)dst, 0 };
321 SkRasterPipeline_<256> p;
322 p.append(SkRasterPipeline::load_1010102, &src_ctx);
323 p.append(SkRasterPipeline::unpremul);
324 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
325 p.run(0,0, width,1);
326 }
327
328 /**
329 * Transform from kRGBA_F16 to 8-bytes-per-pixel RGBA.
330 */
transform_scanline_F16(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)331 static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
332 int width, int, const SkPMColor*) {
333 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
334 dst_ctx = { (void*)dst, 0 };
335 SkRasterPipeline_<256> p;
336 p.append(SkRasterPipeline::load_f16, &src_ctx);
337 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
338 p.append(SkRasterPipeline::clamp_1);
339 p.append(SkRasterPipeline::to_srgb);
340 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
341 p.run(0,0, width,1);
342 }
343
344 /**
345 * Transform from kPremul, kRGBA_F16 to 8-bytes-per-pixel RGBA.
346 */
transform_scanline_F16_premul(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)347 static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
348 int width, int, const SkPMColor*) {
349 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
350 dst_ctx = { (void*)dst, 0 };
351 SkRasterPipeline_<256> p;
352 p.append(SkRasterPipeline::load_f16, &src_ctx);
353 p.append(SkRasterPipeline::unpremul);
354 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
355 p.append(SkRasterPipeline::clamp_1);
356 p.append(SkRasterPipeline::to_srgb);
357 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
358 p.run(0,0, width,1);
359 }
360
361 /**
362 * Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA.
363 */
transform_scanline_F16_to_8888(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)364 static inline void transform_scanline_F16_to_8888(char* SK_RESTRICT dst,
365 const char* SK_RESTRICT src, int width, int,
366 const SkPMColor*) {
367 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
368 dst_ctx = { (void*)dst, 0 };
369 SkRasterPipeline_<256> p;
370 p.append(SkRasterPipeline::load_f16, &src_ctx);
371 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
372 p.append(SkRasterPipeline::clamp_1);
373 p.append(SkRasterPipeline::to_srgb);
374 p.append(SkRasterPipeline::store_8888, &dst_ctx);
375 p.run(0,0, width,1);
376 }
377
378 /**
379 * Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA.
380 */
transform_scanline_F16_premul_to_8888(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)381 static inline void transform_scanline_F16_premul_to_8888(char* SK_RESTRICT dst,
382 const char* SK_RESTRICT src, int width,
383 int, const SkPMColor*) {
384 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
385 dst_ctx = { (void*)dst, 0 };
386 SkRasterPipeline_<256> p;
387 p.append(SkRasterPipeline::load_f16, &src_ctx);
388 p.append(SkRasterPipeline::unpremul);
389 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
390 p.append(SkRasterPipeline::clamp_1);
391 p.append(SkRasterPipeline::to_srgb);
392 p.append(SkRasterPipeline::store_8888, &dst_ctx);
393 p.run(0,0, width,1);
394 }
395
396 /**
397 * Transform from kUnpremul, kRGBA_F16 to premultiplied rgbA 8888.
398 */
transform_scanline_F16_to_premul_8888(char * SK_RESTRICT dst,const char * SK_RESTRICT src,int width,int,const SkPMColor *)399 static inline void transform_scanline_F16_to_premul_8888(char* SK_RESTRICT dst,
400 const char* SK_RESTRICT src, int width, int, const SkPMColor*) {
401 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
402 dst_ctx = { (void*)dst, 0 };
403 SkRasterPipeline_<256> p;
404 p.append(SkRasterPipeline::load_f16, &src_ctx);
405 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
406 p.append(SkRasterPipeline::clamp_1);
407 p.append(SkRasterPipeline::premul);
408 p.append(SkRasterPipeline::to_srgb);
409 p.append(SkRasterPipeline::store_8888, &dst_ctx);
410 p.run(0,0, width,1);
411 }
412
icc_from_color_space(const SkImageInfo & info)413 static inline sk_sp<SkData> icc_from_color_space(const SkImageInfo& info) {
414 SkColorSpace* cs = info.colorSpace();
415 if (!cs) {
416 return nullptr;
417 }
418
419 sk_sp<SkColorSpace> owned;
420 if (kRGBA_F16_SkColorType == info.colorType()) {
421 owned = cs->makeSRGBGamma();
422 cs = owned.get();
423 }
424
425 SkColorSpaceTransferFn fn;
426 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
427 if (cs->isNumericalTransferFn(&fn) && cs->toXYZD50(&toXYZD50)) {
428 return SkICC::WriteToICC(fn, toXYZD50);
429 }
430
431 // TODO: Should we support writing ICC profiles for additional color spaces?
432 return nullptr;
433 }
434
435 #endif // SkImageEncoderFns_DEFINED
436