blob: f5a33e5d67f5ecf25b860ab8e94a74b83321240b [file] [log] [blame]
epoger@google.com4ce738b2012-11-16 18:44:18 +00001/*
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 */
Matt Sarett5df93de2017-03-22 21:52:47 +00007
8#ifndef SkImageEncoderFns_DEFINED
9#define SkImageEncoderFns_DEFINED
epoger@google.com4ce738b2012-11-16 18:44:18 +000010
11/**
12 * Functions to transform scanlines between packed-pixel formats.
13 */
14
15#include "SkBitmap.h"
16#include "SkColor.h"
17#include "SkColorPriv.h"
Matt Sarett5df93de2017-03-22 21:52:47 +000018#include "SkICC.h"
Matt Sarett2e61b182017-05-09 12:46:50 -040019#include "SkOpts.h"
epoger@google.com4ce738b2012-11-16 18:44:18 +000020#include "SkPreConfig.h"
Matt Sarett84014f02017-01-10 11:28:54 -050021#include "SkRasterPipeline.h"
epoger@google.com4ce738b2012-11-16 18:44:18 +000022#include "SkUnPreMultiply.h"
Matt Sarettc7b29082017-02-09 16:22:39 -050023#include "SkUnPreMultiplyPriv.h"
epoger@google.com4ce738b2012-11-16 18:44:18 +000024
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.
msarettf17b71f2016-09-12 14:30:03 -070029 * 'bpp' is bytes per pixel in the 'src' buffer.
epoger@google.com4ce738b2012-11-16 18:44:18 +000030 */
msarettf17b71f2016-09-12 14:30:03 -070031typedef void (*transform_scanline_proc)(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
Matt Sarett62bb2802017-01-23 12:28:02 -050032 int width, int bpp, const SkPMColor* colors);
epoger@google.com4ce738b2012-11-16 18:44:18 +000033
34/**
35 * Identity transformation: just copy bytes from src to dst.
36 */
Matt Sarett62bb2802017-01-23 12:28:02 -050037static inline void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
38 int width, int bpp, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070039 memcpy(dst, src, width * bpp);
epoger@google.com4ce738b2012-11-16 18:44:18 +000040}
41
Matt Sarett62bb2802017-01-23 12:28:02 -050042static 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
54static 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
65static 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
epoger@google.com4ce738b2012-11-16 18:44:18 +000076/**
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 */
Matt Sarett62bb2802017-01-23 12:28:02 -050081static inline void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
82 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070083 const uint16_t* srcP = (const uint16_t*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000084 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/**
msarettf17b71f2016-09-12 14:30:03 -070093 * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB.
94 * Alpha channel data is abandoned.
epoger@google.com4ce738b2012-11-16 18:44:18 +000095 */
Matt Sarett62bb2802017-01-23 12:28:02 -050096static inline void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
97 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070098 const uint32_t* srcP = (const SkPMColor*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000099 for (int i = 0; i < width; i++) {
msarettf17b71f2016-09-12 14:30:03 -0700100 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 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500111static inline void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
112 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700113 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;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000119 }
120}
121
122/**
123 * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB.
124 * Alpha channel data, if any, is abandoned.
125 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500126static inline void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
127 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700128 const SkPMColor16* srcP = (const SkPMColor16*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000129 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
epoger@google.com4ce738b2012-11-16 18:44:18 +0000137/**
Matt Sarett84014f02017-01-10 11:28:54 -0500138 * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
139 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500140static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
141 int width, int, const SkPMColor*) {
Matt Sarettc7b29082017-02-09 16:22:39 -0500142 SkUnpremultiplyRow<false>((uint32_t*) dst, (const uint32_t*) src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500143}
144
145/**
146 * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
147 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500148static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
149 int width, int, const SkPMColor*) {
Matt Sarettc7b29082017-02-09 16:22:39 -0500150 SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500151}
152
153template <bool kIsRGBA>
Matt Sarett1da27ef2017-01-19 17:14:07 -0500154static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400155 SkRasterPipeline_<256> p;
Matt Sarett84014f02017-01-10 11:28:54 -0500156 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);
Mike Klein761d27c2017-06-01 12:37:08 -0400165 p.run(0,0, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500166}
167
168/**
Matt Sarett2e61b182017-05-09 12:46:50 -0400169 * Premultiply RGBA to rgbA.
170 */
171static inline void transform_scanline_to_premul_legacy(char* SK_RESTRICT dst,
172 const char* SK_RESTRICT src,
173 int width, int, const SkPMColor*) {
174 SkOpts::RGBA_to_rgbA((uint32_t*)dst, (const uint32_t*)src, width);
175}
176
177/**
178 * Premultiply RGBA to rgbA linearly.
179 */
180static inline void transform_scanline_to_premul_linear(char* SK_RESTRICT dst,
181 const char* SK_RESTRICT src,
182 int width, int, const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400183 SkRasterPipeline_<256> p;
Matt Sarett2e61b182017-05-09 12:46:50 -0400184 p.append(SkRasterPipeline::load_8888, (const void**) &src);
185 p.append_from_srgb(kUnpremul_SkAlphaType);
186 p.append(SkRasterPipeline::premul);
187 p.append(SkRasterPipeline::to_srgb);
188 p.append(SkRasterPipeline::store_8888, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400189 p.run(0,0, width);
Matt Sarett2e61b182017-05-09 12:46:50 -0400190}
191
192/**
msarettf17b71f2016-09-12 14:30:03 -0700193 * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
194 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500195static inline void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
196 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500197 transform_scanline_unpremultiply_sRGB<true>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700198}
199
200/**
201 * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
202 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500203static inline void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
204 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500205 transform_scanline_unpremultiply_sRGB<false>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700206}
207
208/**
209 * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
210 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500211static inline void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
212 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700213 const uint32_t* srcP = (const SkPMColor*)src;
214 for (int i = 0; i < width; i++) {
215 uint32_t c = *srcP++;
216 *dst++ = (c >> 16) & 0xFF;
217 *dst++ = (c >> 8) & 0xFF;
218 *dst++ = (c >> 0) & 0xFF;
219 *dst++ = (c >> 24) & 0xFF;
220 }
221}
222
223/**
epoger@google.com4ce738b2012-11-16 18:44:18 +0000224 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA,
225 * with scaling of RGB based on alpha channel.
226 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500227static inline void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
228 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700229 const SkPMColor16* srcP = (const SkPMColor16*)src;
230 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
epoger@google.com4ce738b2012-11-16 18:44:18 +0000231
232 for (int i = 0; i < width; i++) {
233 SkPMColor16 c = *srcP++;
234 unsigned a = SkPacked4444ToA32(c);
235 unsigned r = SkPacked4444ToR32(c);
236 unsigned g = SkPacked4444ToG32(c);
237 unsigned b = SkPacked4444ToB32(c);
238
239 if (0 != a && 255 != a) {
240 SkUnPreMultiply::Scale scale = table[a];
241 r = SkUnPreMultiply::ApplyScale(scale, r);
242 g = SkUnPreMultiply::ApplyScale(scale, g);
243 b = SkUnPreMultiply::ApplyScale(scale, b);
244 }
245 *dst++ = r;
246 *dst++ = g;
247 *dst++ = b;
248 *dst++ = a;
249 }
250}
Matt Sarett1da27ef2017-01-19 17:14:07 -0500251
252/**
Matt Sarett55213562017-01-23 19:37:37 -0500253 * Transform from kRGBA_F16 to 8-bytes-per-pixel RGBA.
Matt Sarett1da27ef2017-01-19 17:14:07 -0500254 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500255static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
256 int width, int, const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400257 SkRasterPipeline_<256> p;
Matt Sarett1da27ef2017-01-19 17:14:07 -0500258 p.append(SkRasterPipeline::load_f16, (const void**) &src);
259 p.append(SkRasterPipeline::to_srgb);
260 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400261 p.run(0,0, width);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500262}
263
264/**
Matt Sarett55213562017-01-23 19:37:37 -0500265 * Transform from kPremul, kRGBA_F16 to 8-bytes-per-pixel RGBA.
Matt Sarett1da27ef2017-01-19 17:14:07 -0500266 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500267static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
268 int width, int, const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400269 SkRasterPipeline_<256> p;
Matt Sarett1da27ef2017-01-19 17:14:07 -0500270 p.append(SkRasterPipeline::load_f16, (const void**) &src);
271 p.append(SkRasterPipeline::unpremul);
272 p.append(SkRasterPipeline::to_srgb);
273 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400274 p.run(0,0, width);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500275}
Matt Sarett55213562017-01-23 19:37:37 -0500276
277/**
278 * Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA.
279 */
280static inline void transform_scanline_F16_to_8888(char* SK_RESTRICT dst,
281 const char* SK_RESTRICT src, int width, int,
282 const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400283 SkRasterPipeline_<256> p;
Matt Sarett55213562017-01-23 19:37:37 -0500284 p.append(SkRasterPipeline::load_f16, (const void**) &src);
285 p.append(SkRasterPipeline::to_srgb);
286 p.append(SkRasterPipeline::store_8888, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400287 p.run(0,0, width);
Matt Sarett55213562017-01-23 19:37:37 -0500288}
289
290/**
291 * Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA.
292 */
293static inline void transform_scanline_F16_premul_to_8888(char* SK_RESTRICT dst,
294 const char* SK_RESTRICT src, int width,
295 int, const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400296 SkRasterPipeline_<256> p;
Matt Sarett55213562017-01-23 19:37:37 -0500297 p.append(SkRasterPipeline::load_f16, (const void**) &src);
298 p.append(SkRasterPipeline::unpremul);
299 p.append(SkRasterPipeline::to_srgb);
300 p.append(SkRasterPipeline::store_8888, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400301 p.run(0,0, width);
Matt Sarett55213562017-01-23 19:37:37 -0500302}
Matt Sarett5df93de2017-03-22 21:52:47 +0000303
Matt Sarett2e61b182017-05-09 12:46:50 -0400304/**
305 * Transform from kUnpremul, kRGBA_F16 to premultiplied rgbA 8888.
306 */
307static inline void transform_scanline_F16_to_premul_8888(char* SK_RESTRICT dst,
308 const char* SK_RESTRICT src, int width, int, const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400309 SkRasterPipeline_<256> p;
Matt Sarett2e61b182017-05-09 12:46:50 -0400310 p.append(SkRasterPipeline::load_f16, (const void**) &src);
311 p.append(SkRasterPipeline::premul);
312 p.append(SkRasterPipeline::to_srgb);
313 p.append(SkRasterPipeline::store_8888, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400314 p.run(0,0, width);
Matt Sarett2e61b182017-05-09 12:46:50 -0400315}
316
Matt Sarett5df93de2017-03-22 21:52:47 +0000317static inline sk_sp<SkData> icc_from_color_space(const SkColorSpace& cs) {
318 SkColorSpaceTransferFn fn;
319 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
320 if (cs.isNumericalTransferFn(&fn) && cs.toXYZD50(&toXYZD50)) {
321 return SkICC::WriteToICC(fn, toXYZD50);
322 }
323
324 // TODO: Should we support writing ICC profiles for additional color spaces?
325 return nullptr;
326}
327
328#endif // SkImageEncoderFns_DEFINED