blob: a17b30b10405c33ca040181852f9cac58b551e35 [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 Sarett1950e0a2017-06-12 16:17:30 -040018#include "SkColorSpace_Base.h"
Matt Sarett5df93de2017-03-22 21:52:47 +000019#include "SkICC.h"
Matt Sarett2e61b182017-05-09 12:46:50 -040020#include "SkOpts.h"
epoger@google.com4ce738b2012-11-16 18:44:18 +000021#include "SkPreConfig.h"
Matt Sarett84014f02017-01-10 11:28:54 -050022#include "SkRasterPipeline.h"
epoger@google.com4ce738b2012-11-16 18:44:18 +000023#include "SkUnPreMultiply.h"
Matt Sarettc7b29082017-02-09 16:22:39 -050024#include "SkUnPreMultiplyPriv.h"
Mike Klein45c16fa2017-07-18 18:15:13 -040025#include "../jumper/SkJumper.h"
epoger@google.com4ce738b2012-11-16 18:44:18 +000026
27/**
28 * Function template for transforming scanlines.
29 * Transform 'width' pixels from 'src' buffer into 'dst' buffer,
30 * repacking color channel data as appropriate for the given transformation.
msarettf17b71f2016-09-12 14:30:03 -070031 * 'bpp' is bytes per pixel in the 'src' buffer.
epoger@google.com4ce738b2012-11-16 18:44:18 +000032 */
msarettf17b71f2016-09-12 14:30:03 -070033typedef void (*transform_scanline_proc)(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
Matt Sarett62bb2802017-01-23 12:28:02 -050034 int width, int bpp, const SkPMColor* colors);
epoger@google.com4ce738b2012-11-16 18:44:18 +000035
36/**
37 * Identity transformation: just copy bytes from src to dst.
38 */
Matt Sarett62bb2802017-01-23 12:28:02 -050039static inline void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
40 int width, int bpp, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070041 memcpy(dst, src, width * bpp);
epoger@google.com4ce738b2012-11-16 18:44:18 +000042}
43
Matt Sarett62bb2802017-01-23 12:28:02 -050044static inline void transform_scanline_index8_opaque(char* SK_RESTRICT dst,
45 const char* SK_RESTRICT src, int width, int,
46 const SkPMColor* colors) {
47 for (int i = 0; i < width; i++) {
48 const uint32_t c = colors[(uint8_t)*src++];
49 dst[0] = SkGetPackedR32(c);
50 dst[1] = SkGetPackedG32(c);
51 dst[2] = SkGetPackedB32(c);
52 dst += 3;
53 }
54}
55
56static inline void transform_scanline_index8_unpremul(char* SK_RESTRICT dst,
57 const char* SK_RESTRICT src, int width, int,
58 const SkPMColor* colors) {
59 uint32_t* SK_RESTRICT dst32 = (uint32_t*) dst;
60 for (int i = 0; i < width; i++) {
61 // This function swizzles R and B on platforms where SkPMColor is BGRA. This is
62 // exactly what we want.
63 dst32[i] = SkSwizzle_RGBA_to_PMColor(colors[(uint8_t)*src++]);
64 }
65}
66
67static inline void transform_scanline_gray(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
68 int width, int, const SkPMColor* colors) {
69 for (int i = 0; i < width; i++) {
70 const uint8_t g = (uint8_t) *src++;
71 dst[0] = g;
72 dst[1] = g;
73 dst[2] = g;
74 dst += 3;
75 }
76}
77
epoger@google.com4ce738b2012-11-16 18:44:18 +000078/**
79 * Transform from kRGB_565_Config to 3-bytes-per-pixel RGB.
80 * Alpha channel data is not present in kRGB_565_Config format, so there is no
81 * alpha channel data to preserve.
82 */
Matt Sarett62bb2802017-01-23 12:28:02 -050083static inline void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
84 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070085 const uint16_t* srcP = (const uint16_t*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000086 for (int i = 0; i < width; i++) {
87 unsigned c = *srcP++;
88 *dst++ = SkPacked16ToR32(c);
89 *dst++ = SkPacked16ToG32(c);
90 *dst++ = SkPacked16ToB32(c);
91 }
92}
93
94/**
msarettf17b71f2016-09-12 14:30:03 -070095 * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB.
96 * Alpha channel data is abandoned.
epoger@google.com4ce738b2012-11-16 18:44:18 +000097 */
Matt Sarett62bb2802017-01-23 12:28:02 -050098static inline void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
99 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700100 const uint32_t* srcP = (const SkPMColor*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000101 for (int i = 0; i < width; i++) {
msarettf17b71f2016-09-12 14:30:03 -0700102 uint32_t c = *srcP++;
103 *dst++ = (c >> 0) & 0xFF;
104 *dst++ = (c >> 8) & 0xFF;
105 *dst++ = (c >> 16) & 0xFF;
106 }
107}
108
109/**
110 * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB.
111 * Alpha channel data is abandoned.
112 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500113static inline void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
114 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700115 const uint32_t* srcP = (const SkPMColor*)src;
116 for (int i = 0; i < width; i++) {
117 uint32_t c = *srcP++;
118 *dst++ = (c >> 16) & 0xFF;
119 *dst++ = (c >> 8) & 0xFF;
120 *dst++ = (c >> 0) & 0xFF;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000121 }
122}
123
124/**
125 * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB.
126 * Alpha channel data, if any, is abandoned.
127 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500128static inline void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
129 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700130 const SkPMColor16* srcP = (const SkPMColor16*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000131 for (int i = 0; i < width; i++) {
132 SkPMColor16 c = *srcP++;
133 *dst++ = SkPacked4444ToR32(c);
134 *dst++ = SkPacked4444ToG32(c);
135 *dst++ = SkPacked4444ToB32(c);
136 }
137}
138
epoger@google.com4ce738b2012-11-16 18:44:18 +0000139/**
Matt Sarett84014f02017-01-10 11:28:54 -0500140 * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
141 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500142static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
143 int width, int, const SkPMColor*) {
Matt Sarettc7b29082017-02-09 16:22:39 -0500144 SkUnpremultiplyRow<false>((uint32_t*) dst, (const uint32_t*) src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500145}
146
147/**
148 * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
149 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500150static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
151 int width, int, const SkPMColor*) {
Matt Sarettc7b29082017-02-09 16:22:39 -0500152 SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500153}
154
155template <bool kIsRGBA>
Matt Sarett1da27ef2017-01-19 17:14:07 -0500156static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width) {
Mike Klein45c16fa2017-07-18 18:15:13 -0400157 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
158 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400159 SkRasterPipeline_<256> p;
Mike Kleinc2d20762017-06-27 19:53:21 -0400160 if (kIsRGBA) {
Mike Klein45c16fa2017-07-18 18:15:13 -0400161 p.append(SkRasterPipeline::load_8888, &src_ctx);
Mike Kleinc2d20762017-06-27 19:53:21 -0400162 } else {
Mike Klein45c16fa2017-07-18 18:15:13 -0400163 p.append(SkRasterPipeline::load_bgra, &src_ctx);
Matt Sarett84014f02017-01-10 11:28:54 -0500164 }
165
166 p.append_from_srgb(kPremul_SkAlphaType);
167 p.append(SkRasterPipeline::unpremul);
168 p.append(SkRasterPipeline::to_srgb);
Mike Klein45c16fa2017-07-18 18:15:13 -0400169 p.append(SkRasterPipeline::store_8888, &dst_ctx);
170 p.run(0,0, width,1);
Matt Sarett84014f02017-01-10 11:28:54 -0500171}
172
173/**
Matt Sarett2e61b182017-05-09 12:46:50 -0400174 * Premultiply RGBA to rgbA.
175 */
176static inline void transform_scanline_to_premul_legacy(char* SK_RESTRICT dst,
177 const char* SK_RESTRICT src,
178 int width, int, const SkPMColor*) {
179 SkOpts::RGBA_to_rgbA((uint32_t*)dst, (const uint32_t*)src, width);
180}
181
182/**
183 * Premultiply RGBA to rgbA linearly.
184 */
185static inline void transform_scanline_to_premul_linear(char* SK_RESTRICT dst,
186 const char* SK_RESTRICT src,
187 int width, int, const SkPMColor*) {
Mike Klein45c16fa2017-07-18 18:15:13 -0400188 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
189 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400190 SkRasterPipeline_<256> p;
Mike Klein45c16fa2017-07-18 18:15:13 -0400191 p.append(SkRasterPipeline::load_8888, &src_ctx);
Matt Sarett2e61b182017-05-09 12:46:50 -0400192 p.append_from_srgb(kUnpremul_SkAlphaType);
193 p.append(SkRasterPipeline::premul);
194 p.append(SkRasterPipeline::to_srgb);
Mike Klein45c16fa2017-07-18 18:15:13 -0400195 p.append(SkRasterPipeline::store_8888, &dst_ctx);
196 p.run(0,0, width,1);
Matt Sarett2e61b182017-05-09 12:46:50 -0400197}
198
199/**
msarettf17b71f2016-09-12 14:30:03 -0700200 * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
201 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500202static inline void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
203 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500204 transform_scanline_unpremultiply_sRGB<true>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700205}
206
207/**
208 * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
209 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500210static inline void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
211 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500212 transform_scanline_unpremultiply_sRGB<false>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700213}
214
215/**
216 * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
217 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500218static inline void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
219 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700220 const uint32_t* srcP = (const SkPMColor*)src;
221 for (int i = 0; i < width; i++) {
222 uint32_t c = *srcP++;
223 *dst++ = (c >> 16) & 0xFF;
224 *dst++ = (c >> 8) & 0xFF;
225 *dst++ = (c >> 0) & 0xFF;
226 *dst++ = (c >> 24) & 0xFF;
227 }
228}
229
230/**
epoger@google.com4ce738b2012-11-16 18:44:18 +0000231 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA,
232 * with scaling of RGB based on alpha channel.
233 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500234static inline void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
235 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700236 const SkPMColor16* srcP = (const SkPMColor16*)src;
237 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
epoger@google.com4ce738b2012-11-16 18:44:18 +0000238
239 for (int i = 0; i < width; i++) {
240 SkPMColor16 c = *srcP++;
241 unsigned a = SkPacked4444ToA32(c);
242 unsigned r = SkPacked4444ToR32(c);
243 unsigned g = SkPacked4444ToG32(c);
244 unsigned b = SkPacked4444ToB32(c);
245
246 if (0 != a && 255 != a) {
247 SkUnPreMultiply::Scale scale = table[a];
248 r = SkUnPreMultiply::ApplyScale(scale, r);
249 g = SkUnPreMultiply::ApplyScale(scale, g);
250 b = SkUnPreMultiply::ApplyScale(scale, b);
251 }
252 *dst++ = r;
253 *dst++ = g;
254 *dst++ = b;
255 *dst++ = a;
256 }
257}
Matt Sarett1da27ef2017-01-19 17:14:07 -0500258
259/**
Matt Sarett55213562017-01-23 19:37:37 -0500260 * Transform from kRGBA_F16 to 8-bytes-per-pixel RGBA.
Matt Sarett1da27ef2017-01-19 17:14:07 -0500261 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500262static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
263 int width, int, const SkPMColor*) {
Mike Klein45c16fa2017-07-18 18:15:13 -0400264 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
265 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400266 SkRasterPipeline_<256> p;
Mike Klein45c16fa2017-07-18 18:15:13 -0400267 p.append(SkRasterPipeline::load_f16, &src_ctx);
Mike Kleince988012017-07-21 13:11:37 -0400268 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
269 p.append(SkRasterPipeline::clamp_1);
Matt Sarett1950e0a2017-06-12 16:17:30 -0400270 p.append(SkRasterPipeline::to_srgb);
Mike Klein45c16fa2017-07-18 18:15:13 -0400271 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
272 p.run(0,0, width,1);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500273}
274
275/**
Matt Sarett55213562017-01-23 19:37:37 -0500276 * Transform from kPremul, kRGBA_F16 to 8-bytes-per-pixel RGBA.
Matt Sarett1da27ef2017-01-19 17:14:07 -0500277 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500278static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
279 int width, int, const SkPMColor*) {
Mike Klein45c16fa2017-07-18 18:15:13 -0400280 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
281 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400282 SkRasterPipeline_<256> p;
Mike Klein45c16fa2017-07-18 18:15:13 -0400283 p.append(SkRasterPipeline::load_f16, &src_ctx);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500284 p.append(SkRasterPipeline::unpremul);
Mike Kleince988012017-07-21 13:11:37 -0400285 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
286 p.append(SkRasterPipeline::clamp_1);
Matt Sarett1950e0a2017-06-12 16:17:30 -0400287 p.append(SkRasterPipeline::to_srgb);
Mike Klein45c16fa2017-07-18 18:15:13 -0400288 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
289 p.run(0,0, width,1);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500290}
Matt Sarett55213562017-01-23 19:37:37 -0500291
292/**
293 * Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA.
294 */
295static inline void transform_scanline_F16_to_8888(char* SK_RESTRICT dst,
296 const char* SK_RESTRICT src, int width, int,
297 const SkPMColor*) {
Mike Klein45c16fa2017-07-18 18:15:13 -0400298 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
299 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400300 SkRasterPipeline_<256> p;
Mike Klein45c16fa2017-07-18 18:15:13 -0400301 p.append(SkRasterPipeline::load_f16, &src_ctx);
Mike Kleince988012017-07-21 13:11:37 -0400302 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
303 p.append(SkRasterPipeline::clamp_1);
Matt Sarett55213562017-01-23 19:37:37 -0500304 p.append(SkRasterPipeline::to_srgb);
Mike Klein45c16fa2017-07-18 18:15:13 -0400305 p.append(SkRasterPipeline::store_8888, &dst_ctx);
306 p.run(0,0, width,1);
Matt Sarett55213562017-01-23 19:37:37 -0500307}
308
309/**
310 * Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA.
311 */
312static inline void transform_scanline_F16_premul_to_8888(char* SK_RESTRICT dst,
313 const char* SK_RESTRICT src, int width,
314 int, const SkPMColor*) {
Mike Klein45c16fa2017-07-18 18:15:13 -0400315 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
316 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400317 SkRasterPipeline_<256> p;
Mike Klein45c16fa2017-07-18 18:15:13 -0400318 p.append(SkRasterPipeline::load_f16, &src_ctx);
Matt Sarett55213562017-01-23 19:37:37 -0500319 p.append(SkRasterPipeline::unpremul);
Mike Kleince988012017-07-21 13:11:37 -0400320 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
321 p.append(SkRasterPipeline::clamp_1);
Matt Sarett55213562017-01-23 19:37:37 -0500322 p.append(SkRasterPipeline::to_srgb);
Mike Klein45c16fa2017-07-18 18:15:13 -0400323 p.append(SkRasterPipeline::store_8888, &dst_ctx);
324 p.run(0,0, width,1);
Matt Sarett55213562017-01-23 19:37:37 -0500325}
Matt Sarett5df93de2017-03-22 21:52:47 +0000326
Matt Sarett2e61b182017-05-09 12:46:50 -0400327/**
328 * Transform from kUnpremul, kRGBA_F16 to premultiplied rgbA 8888.
329 */
330static inline void transform_scanline_F16_to_premul_8888(char* SK_RESTRICT dst,
331 const char* SK_RESTRICT src, int width, int, const SkPMColor*) {
Mike Klein45c16fa2017-07-18 18:15:13 -0400332 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 },
333 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400334 SkRasterPipeline_<256> p;
Mike Klein45c16fa2017-07-18 18:15:13 -0400335 p.append(SkRasterPipeline::load_f16, &src_ctx);
Mike Kleince988012017-07-21 13:11:37 -0400336 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
337 p.append(SkRasterPipeline::clamp_1);
Matt Sarett2e61b182017-05-09 12:46:50 -0400338 p.append(SkRasterPipeline::premul);
339 p.append(SkRasterPipeline::to_srgb);
Mike Klein45c16fa2017-07-18 18:15:13 -0400340 p.append(SkRasterPipeline::store_8888, &dst_ctx);
341 p.run(0,0, width,1);
Matt Sarett2e61b182017-05-09 12:46:50 -0400342}
343
Matt Sarett1950e0a2017-06-12 16:17:30 -0400344static inline sk_sp<SkData> icc_from_color_space(const SkImageInfo& info) {
345 SkColorSpace* cs = info.colorSpace();
346 if (!cs) {
347 return nullptr;
348 }
349
350 sk_sp<SkColorSpace> owned;
351 if (kRGBA_F16_SkColorType == info.colorType()) {
352 owned = as_CSB(cs)->makeSRGBGamma();
353 cs = owned.get();
354 }
355
Matt Sarett5df93de2017-03-22 21:52:47 +0000356 SkColorSpaceTransferFn fn;
357 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
Matt Sarett1950e0a2017-06-12 16:17:30 -0400358 if (cs->isNumericalTransferFn(&fn) && cs->toXYZD50(&toXYZD50)) {
Matt Sarett5df93de2017-03-22 21:52:47 +0000359 return SkICC::WriteToICC(fn, toXYZD50);
360 }
361
362 // TODO: Should we support writing ICC profiles for additional color spaces?
363 return nullptr;
364}
365
366#endif // SkImageEncoderFns_DEFINED