• 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 "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