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