• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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