blob: 5120570c484ab1cab254ee6803aa29288516cf32 [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"
epoger@google.com4ce738b2012-11-16 18:44:18 +000019#include "SkPreConfig.h"
Matt Sarett84014f02017-01-10 11:28:54 -050020#include "SkRasterPipeline.h"
epoger@google.com4ce738b2012-11-16 18:44:18 +000021#include "SkUnPreMultiply.h"
Matt Sarettc7b29082017-02-09 16:22:39 -050022#include "SkUnPreMultiplyPriv.h"
epoger@google.com4ce738b2012-11-16 18:44:18 +000023
24/**
25 * Function template for transforming scanlines.
26 * Transform 'width' pixels from 'src' buffer into 'dst' buffer,
27 * repacking color channel data as appropriate for the given transformation.
msarettf17b71f2016-09-12 14:30:03 -070028 * 'bpp' is bytes per pixel in the 'src' buffer.
epoger@google.com4ce738b2012-11-16 18:44:18 +000029 */
msarettf17b71f2016-09-12 14:30:03 -070030typedef void (*transform_scanline_proc)(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
Matt Sarett62bb2802017-01-23 12:28:02 -050031 int width, int bpp, const SkPMColor* colors);
epoger@google.com4ce738b2012-11-16 18:44:18 +000032
33/**
34 * Identity transformation: just copy bytes from src to dst.
35 */
Matt Sarett62bb2802017-01-23 12:28:02 -050036static inline void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
37 int width, int bpp, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070038 memcpy(dst, src, width * bpp);
epoger@google.com4ce738b2012-11-16 18:44:18 +000039}
40
Matt Sarett62bb2802017-01-23 12:28:02 -050041static inline void transform_scanline_index8_opaque(char* SK_RESTRICT dst,
42 const char* SK_RESTRICT src, int width, int,
43 const SkPMColor* colors) {
44 for (int i = 0; i < width; i++) {
45 const uint32_t c = colors[(uint8_t)*src++];
46 dst[0] = SkGetPackedR32(c);
47 dst[1] = SkGetPackedG32(c);
48 dst[2] = SkGetPackedB32(c);
49 dst += 3;
50 }
51}
52
53static inline void transform_scanline_index8_unpremul(char* SK_RESTRICT dst,
54 const char* SK_RESTRICT src, int width, int,
55 const SkPMColor* colors) {
56 uint32_t* SK_RESTRICT dst32 = (uint32_t*) dst;
57 for (int i = 0; i < width; i++) {
58 // This function swizzles R and B on platforms where SkPMColor is BGRA. This is
59 // exactly what we want.
60 dst32[i] = SkSwizzle_RGBA_to_PMColor(colors[(uint8_t)*src++]);
61 }
62}
63
64static inline void transform_scanline_gray(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
65 int width, int, const SkPMColor* colors) {
66 for (int i = 0; i < width; i++) {
67 const uint8_t g = (uint8_t) *src++;
68 dst[0] = g;
69 dst[1] = g;
70 dst[2] = g;
71 dst += 3;
72 }
73}
74
epoger@google.com4ce738b2012-11-16 18:44:18 +000075/**
76 * Transform from kRGB_565_Config to 3-bytes-per-pixel RGB.
77 * Alpha channel data is not present in kRGB_565_Config format, so there is no
78 * alpha channel data to preserve.
79 */
Matt Sarett62bb2802017-01-23 12:28:02 -050080static inline void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
81 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070082 const uint16_t* srcP = (const uint16_t*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000083 for (int i = 0; i < width; i++) {
84 unsigned c = *srcP++;
85 *dst++ = SkPacked16ToR32(c);
86 *dst++ = SkPacked16ToG32(c);
87 *dst++ = SkPacked16ToB32(c);
88 }
89}
90
91/**
msarettf17b71f2016-09-12 14:30:03 -070092 * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB.
93 * Alpha channel data is abandoned.
epoger@google.com4ce738b2012-11-16 18:44:18 +000094 */
Matt Sarett62bb2802017-01-23 12:28:02 -050095static inline void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
96 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070097 const uint32_t* srcP = (const SkPMColor*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000098 for (int i = 0; i < width; i++) {
msarettf17b71f2016-09-12 14:30:03 -070099 uint32_t c = *srcP++;
100 *dst++ = (c >> 0) & 0xFF;
101 *dst++ = (c >> 8) & 0xFF;
102 *dst++ = (c >> 16) & 0xFF;
103 }
104}
105
106/**
107 * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB.
108 * Alpha channel data is abandoned.
109 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500110static inline void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
111 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700112 const uint32_t* srcP = (const SkPMColor*)src;
113 for (int i = 0; i < width; i++) {
114 uint32_t c = *srcP++;
115 *dst++ = (c >> 16) & 0xFF;
116 *dst++ = (c >> 8) & 0xFF;
117 *dst++ = (c >> 0) & 0xFF;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000118 }
119}
120
121/**
122 * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB.
123 * Alpha channel data, if any, is abandoned.
124 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500125static inline void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
126 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700127 const SkPMColor16* srcP = (const SkPMColor16*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000128 for (int i = 0; i < width; i++) {
129 SkPMColor16 c = *srcP++;
130 *dst++ = SkPacked4444ToR32(c);
131 *dst++ = SkPacked4444ToG32(c);
132 *dst++ = SkPacked4444ToB32(c);
133 }
134}
135
epoger@google.com4ce738b2012-11-16 18:44:18 +0000136/**
Matt Sarett84014f02017-01-10 11:28:54 -0500137 * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
138 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500139static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
140 int width, int, const SkPMColor*) {
Matt Sarettc7b29082017-02-09 16:22:39 -0500141 SkUnpremultiplyRow<false>((uint32_t*) dst, (const uint32_t*) src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500142}
143
144/**
145 * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
146 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500147static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
148 int width, int, const SkPMColor*) {
Matt Sarettc7b29082017-02-09 16:22:39 -0500149 SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500150}
151
152template <bool kIsRGBA>
Matt Sarett1da27ef2017-01-19 17:14:07 -0500153static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width) {
Matt Sarett84014f02017-01-10 11:28:54 -0500154 SkRasterPipeline p;
155 p.append(SkRasterPipeline::load_8888, &src);
156 if (!kIsRGBA) {
157 p.append(SkRasterPipeline::swap_rb);
158 }
159
160 p.append_from_srgb(kPremul_SkAlphaType);
161 p.append(SkRasterPipeline::unpremul);
162 p.append(SkRasterPipeline::to_srgb);
163 p.append(SkRasterPipeline::store_8888, &dst);
Mike Klein319ba3d2017-01-20 15:11:54 -0500164 p.run(0, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500165}
166
167/**
msarettf17b71f2016-09-12 14:30:03 -0700168 * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
169 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500170static inline void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
171 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500172 transform_scanline_unpremultiply_sRGB<true>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700173}
174
175/**
176 * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
177 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500178static inline void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
179 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500180 transform_scanline_unpremultiply_sRGB<false>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700181}
182
183/**
184 * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
185 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500186static inline void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
187 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700188 const uint32_t* srcP = (const SkPMColor*)src;
189 for (int i = 0; i < width; i++) {
190 uint32_t c = *srcP++;
191 *dst++ = (c >> 16) & 0xFF;
192 *dst++ = (c >> 8) & 0xFF;
193 *dst++ = (c >> 0) & 0xFF;
194 *dst++ = (c >> 24) & 0xFF;
195 }
196}
197
198/**
epoger@google.com4ce738b2012-11-16 18:44:18 +0000199 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA,
200 * with scaling of RGB based on alpha channel.
201 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500202static inline void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
203 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700204 const SkPMColor16* srcP = (const SkPMColor16*)src;
205 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
epoger@google.com4ce738b2012-11-16 18:44:18 +0000206
207 for (int i = 0; i < width; i++) {
208 SkPMColor16 c = *srcP++;
209 unsigned a = SkPacked4444ToA32(c);
210 unsigned r = SkPacked4444ToR32(c);
211 unsigned g = SkPacked4444ToG32(c);
212 unsigned b = SkPacked4444ToB32(c);
213
214 if (0 != a && 255 != a) {
215 SkUnPreMultiply::Scale scale = table[a];
216 r = SkUnPreMultiply::ApplyScale(scale, r);
217 g = SkUnPreMultiply::ApplyScale(scale, g);
218 b = SkUnPreMultiply::ApplyScale(scale, b);
219 }
220 *dst++ = r;
221 *dst++ = g;
222 *dst++ = b;
223 *dst++ = a;
224 }
225}
Matt Sarett1da27ef2017-01-19 17:14:07 -0500226
227/**
Matt Sarett55213562017-01-23 19:37:37 -0500228 * Transform from kRGBA_F16 to 8-bytes-per-pixel RGBA.
Matt Sarett1da27ef2017-01-19 17:14:07 -0500229 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500230static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
231 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500232 SkRasterPipeline p;
233 p.append(SkRasterPipeline::load_f16, (const void**) &src);
234 p.append(SkRasterPipeline::to_srgb);
235 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
Mike Klein319ba3d2017-01-20 15:11:54 -0500236 p.run(0, width);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500237}
238
239/**
Matt Sarett55213562017-01-23 19:37:37 -0500240 * Transform from kPremul, kRGBA_F16 to 8-bytes-per-pixel RGBA.
Matt Sarett1da27ef2017-01-19 17:14:07 -0500241 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500242static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
243 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500244 SkRasterPipeline p;
245 p.append(SkRasterPipeline::load_f16, (const void**) &src);
246 p.append(SkRasterPipeline::unpremul);
247 p.append(SkRasterPipeline::to_srgb);
248 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
Mike Klein319ba3d2017-01-20 15:11:54 -0500249 p.run(0, width);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500250}
Matt Sarett55213562017-01-23 19:37:37 -0500251
252/**
253 * Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA.
254 */
255static inline void transform_scanline_F16_to_8888(char* SK_RESTRICT dst,
256 const char* SK_RESTRICT src, int width, int,
257 const SkPMColor*) {
258 SkRasterPipeline p;
259 p.append(SkRasterPipeline::load_f16, (const void**) &src);
260 p.append(SkRasterPipeline::to_srgb);
261 p.append(SkRasterPipeline::store_8888, (void**) &dst);
262 p.run(0, width);
263}
264
265/**
266 * Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA.
267 */
268static inline void transform_scanline_F16_premul_to_8888(char* SK_RESTRICT dst,
269 const char* SK_RESTRICT src, int width,
270 int, const SkPMColor*) {
271 SkRasterPipeline 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_8888, (void**) &dst);
276 p.run(0, width);
277}
Matt Sarett5df93de2017-03-22 21:52:47 +0000278
279static inline sk_sp<SkData> icc_from_color_space(const SkColorSpace& cs) {
280 SkColorSpaceTransferFn fn;
281 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
282 if (cs.isNumericalTransferFn(&fn) && cs.toXYZD50(&toXYZD50)) {
283 return SkICC::WriteToICC(fn, toXYZD50);
284 }
285
286 // TODO: Should we support writing ICC profiles for additional color spaces?
287 return nullptr;
288}
289
290#endif // SkImageEncoderFns_DEFINED