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