blob: 6012a45697b2f90dcc6bb2ddb4572657e713c61f [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"
epoger@google.com4ce738b2012-11-16 18:44:18 +000025
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.
msarettf17b71f2016-09-12 14:30:03 -070030 * 'bpp' is bytes per pixel in the 'src' buffer.
epoger@google.com4ce738b2012-11-16 18:44:18 +000031 */
msarettf17b71f2016-09-12 14:30:03 -070032typedef void (*transform_scanline_proc)(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
Matt Sarett62bb2802017-01-23 12:28:02 -050033 int width, int bpp, const SkPMColor* colors);
epoger@google.com4ce738b2012-11-16 18:44:18 +000034
35/**
36 * Identity transformation: just copy bytes from src to dst.
37 */
Matt Sarett62bb2802017-01-23 12:28:02 -050038static inline void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
39 int width, int bpp, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070040 memcpy(dst, src, width * bpp);
epoger@google.com4ce738b2012-11-16 18:44:18 +000041}
42
Matt Sarett62bb2802017-01-23 12:28:02 -050043static 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
55static 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
66static 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
epoger@google.com4ce738b2012-11-16 18:44:18 +000077/**
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 */
Matt Sarett62bb2802017-01-23 12:28:02 -050082static inline void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
83 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070084 const uint16_t* srcP = (const uint16_t*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000085 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/**
msarettf17b71f2016-09-12 14:30:03 -070094 * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB.
95 * Alpha channel data is abandoned.
epoger@google.com4ce738b2012-11-16 18:44:18 +000096 */
Matt Sarett62bb2802017-01-23 12:28:02 -050097static inline void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
98 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -070099 const uint32_t* srcP = (const SkPMColor*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000100 for (int i = 0; i < width; i++) {
msarettf17b71f2016-09-12 14:30:03 -0700101 uint32_t c = *srcP++;
102 *dst++ = (c >> 0) & 0xFF;
103 *dst++ = (c >> 8) & 0xFF;
104 *dst++ = (c >> 16) & 0xFF;
105 }
106}
107
108/**
109 * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB.
110 * Alpha channel data is abandoned.
111 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500112static inline void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
113 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700114 const uint32_t* srcP = (const SkPMColor*)src;
115 for (int i = 0; i < width; i++) {
116 uint32_t c = *srcP++;
117 *dst++ = (c >> 16) & 0xFF;
118 *dst++ = (c >> 8) & 0xFF;
119 *dst++ = (c >> 0) & 0xFF;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000120 }
121}
122
123/**
124 * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB.
125 * Alpha channel data, if any, is abandoned.
126 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500127static inline void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
128 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700129 const SkPMColor16* srcP = (const SkPMColor16*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +0000130 for (int i = 0; i < width; i++) {
131 SkPMColor16 c = *srcP++;
132 *dst++ = SkPacked4444ToR32(c);
133 *dst++ = SkPacked4444ToG32(c);
134 *dst++ = SkPacked4444ToB32(c);
135 }
136}
137
epoger@google.com4ce738b2012-11-16 18:44:18 +0000138/**
Matt Sarett84014f02017-01-10 11:28:54 -0500139 * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
140 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500141static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
142 int width, int, const SkPMColor*) {
Matt Sarettc7b29082017-02-09 16:22:39 -0500143 SkUnpremultiplyRow<false>((uint32_t*) dst, (const uint32_t*) src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500144}
145
146/**
147 * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
148 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500149static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
150 int width, int, const SkPMColor*) {
Matt Sarettc7b29082017-02-09 16:22:39 -0500151 SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500152}
153
154template <bool kIsRGBA>
Matt Sarett1da27ef2017-01-19 17:14:07 -0500155static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400156 SkRasterPipeline_<256> p;
Matt Sarett84014f02017-01-10 11:28:54 -0500157 p.append(SkRasterPipeline::load_8888, &src);
158 if (!kIsRGBA) {
159 p.append(SkRasterPipeline::swap_rb);
160 }
161
162 p.append_from_srgb(kPremul_SkAlphaType);
163 p.append(SkRasterPipeline::unpremul);
164 p.append(SkRasterPipeline::to_srgb);
165 p.append(SkRasterPipeline::store_8888, &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400166 p.run(0,0, width);
Matt Sarett84014f02017-01-10 11:28:54 -0500167}
168
169/**
Matt Sarett2e61b182017-05-09 12:46:50 -0400170 * Premultiply RGBA to rgbA.
171 */
172static inline void transform_scanline_to_premul_legacy(char* SK_RESTRICT dst,
173 const char* SK_RESTRICT src,
174 int width, int, const SkPMColor*) {
175 SkOpts::RGBA_to_rgbA((uint32_t*)dst, (const uint32_t*)src, width);
176}
177
178/**
179 * Premultiply RGBA to rgbA linearly.
180 */
181static inline void transform_scanline_to_premul_linear(char* SK_RESTRICT dst,
182 const char* SK_RESTRICT src,
183 int width, int, const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400184 SkRasterPipeline_<256> p;
Matt Sarett2e61b182017-05-09 12:46:50 -0400185 p.append(SkRasterPipeline::load_8888, (const void**) &src);
186 p.append_from_srgb(kUnpremul_SkAlphaType);
187 p.append(SkRasterPipeline::premul);
188 p.append(SkRasterPipeline::to_srgb);
189 p.append(SkRasterPipeline::store_8888, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400190 p.run(0,0, width);
Matt Sarett2e61b182017-05-09 12:46:50 -0400191}
192
193/**
msarettf17b71f2016-09-12 14:30:03 -0700194 * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
195 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500196static inline void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
197 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500198 transform_scanline_unpremultiply_sRGB<true>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700199}
200
201/**
202 * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
203 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500204static inline void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
205 int width, int, const SkPMColor*) {
Matt Sarett1da27ef2017-01-19 17:14:07 -0500206 transform_scanline_unpremultiply_sRGB<false>(dst, src, width);
msarettf17b71f2016-09-12 14:30:03 -0700207}
208
209/**
210 * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA.
211 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500212static inline void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
213 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700214 const uint32_t* srcP = (const SkPMColor*)src;
215 for (int i = 0; i < width; i++) {
216 uint32_t c = *srcP++;
217 *dst++ = (c >> 16) & 0xFF;
218 *dst++ = (c >> 8) & 0xFF;
219 *dst++ = (c >> 0) & 0xFF;
220 *dst++ = (c >> 24) & 0xFF;
221 }
222}
223
224/**
epoger@google.com4ce738b2012-11-16 18:44:18 +0000225 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA,
226 * with scaling of RGB based on alpha channel.
227 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500228static inline void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
229 int width, int, const SkPMColor*) {
msarettf17b71f2016-09-12 14:30:03 -0700230 const SkPMColor16* srcP = (const SkPMColor16*)src;
231 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
epoger@google.com4ce738b2012-11-16 18:44:18 +0000232
233 for (int i = 0; i < width; i++) {
234 SkPMColor16 c = *srcP++;
235 unsigned a = SkPacked4444ToA32(c);
236 unsigned r = SkPacked4444ToR32(c);
237 unsigned g = SkPacked4444ToG32(c);
238 unsigned b = SkPacked4444ToB32(c);
239
240 if (0 != a && 255 != a) {
241 SkUnPreMultiply::Scale scale = table[a];
242 r = SkUnPreMultiply::ApplyScale(scale, r);
243 g = SkUnPreMultiply::ApplyScale(scale, g);
244 b = SkUnPreMultiply::ApplyScale(scale, b);
245 }
246 *dst++ = r;
247 *dst++ = g;
248 *dst++ = b;
249 *dst++ = a;
250 }
251}
Matt Sarett1da27ef2017-01-19 17:14:07 -0500252
253/**
Matt Sarett55213562017-01-23 19:37:37 -0500254 * Transform from kRGBA_F16 to 8-bytes-per-pixel RGBA.
Matt Sarett1da27ef2017-01-19 17:14:07 -0500255 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500256static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
257 int width, int, const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400258 SkRasterPipeline_<256> p;
Matt Sarett1da27ef2017-01-19 17:14:07 -0500259 p.append(SkRasterPipeline::load_f16, (const void**) &src);
Matt Sarett1950e0a2017-06-12 16:17:30 -0400260 p.append(SkRasterPipeline::to_srgb);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500261 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400262 p.run(0,0, width);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500263}
264
265/**
Matt Sarett55213562017-01-23 19:37:37 -0500266 * Transform from kPremul, kRGBA_F16 to 8-bytes-per-pixel RGBA.
Matt Sarett1da27ef2017-01-19 17:14:07 -0500267 */
Matt Sarett62bb2802017-01-23 12:28:02 -0500268static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src,
269 int width, int, const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400270 SkRasterPipeline_<256> p;
Matt Sarett1da27ef2017-01-19 17:14:07 -0500271 p.append(SkRasterPipeline::load_f16, (const void**) &src);
272 p.append(SkRasterPipeline::unpremul);
Matt Sarett1950e0a2017-06-12 16:17:30 -0400273 p.append(SkRasterPipeline::to_srgb);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500274 p.append(SkRasterPipeline::store_u16_be, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400275 p.run(0,0, width);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500276}
Matt Sarett55213562017-01-23 19:37:37 -0500277
278/**
279 * Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA.
280 */
281static inline void transform_scanline_F16_to_8888(char* SK_RESTRICT dst,
282 const char* SK_RESTRICT src, int width, int,
283 const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400284 SkRasterPipeline_<256> p;
Matt Sarett55213562017-01-23 19:37:37 -0500285 p.append(SkRasterPipeline::load_f16, (const void**) &src);
286 p.append(SkRasterPipeline::to_srgb);
287 p.append(SkRasterPipeline::store_8888, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400288 p.run(0,0, width);
Matt Sarett55213562017-01-23 19:37:37 -0500289}
290
291/**
292 * Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA.
293 */
294static inline void transform_scanline_F16_premul_to_8888(char* SK_RESTRICT dst,
295 const char* SK_RESTRICT src, int width,
296 int, const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400297 SkRasterPipeline_<256> p;
Matt Sarett55213562017-01-23 19:37:37 -0500298 p.append(SkRasterPipeline::load_f16, (const void**) &src);
299 p.append(SkRasterPipeline::unpremul);
300 p.append(SkRasterPipeline::to_srgb);
301 p.append(SkRasterPipeline::store_8888, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400302 p.run(0,0, width);
Matt Sarett55213562017-01-23 19:37:37 -0500303}
Matt Sarett5df93de2017-03-22 21:52:47 +0000304
Matt Sarett2e61b182017-05-09 12:46:50 -0400305/**
306 * Transform from kUnpremul, kRGBA_F16 to premultiplied rgbA 8888.
307 */
308static inline void transform_scanline_F16_to_premul_8888(char* SK_RESTRICT dst,
309 const char* SK_RESTRICT src, int width, int, const SkPMColor*) {
Mike Kleinb24704d2017-05-24 07:53:00 -0400310 SkRasterPipeline_<256> p;
Matt Sarett2e61b182017-05-09 12:46:50 -0400311 p.append(SkRasterPipeline::load_f16, (const void**) &src);
312 p.append(SkRasterPipeline::premul);
313 p.append(SkRasterPipeline::to_srgb);
314 p.append(SkRasterPipeline::store_8888, (void**) &dst);
Mike Klein761d27c2017-06-01 12:37:08 -0400315 p.run(0,0, width);
Matt Sarett2e61b182017-05-09 12:46:50 -0400316}
317
Matt Sarett1950e0a2017-06-12 16:17:30 -0400318static inline sk_sp<SkData> icc_from_color_space(const SkImageInfo& info) {
319 SkColorSpace* cs = info.colorSpace();
320 if (!cs) {
321 return nullptr;
322 }
323
324 sk_sp<SkColorSpace> owned;
325 if (kRGBA_F16_SkColorType == info.colorType()) {
326 owned = as_CSB(cs)->makeSRGBGamma();
327 cs = owned.get();
328 }
329
Matt Sarett5df93de2017-03-22 21:52:47 +0000330 SkColorSpaceTransferFn fn;
331 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
Matt Sarett1950e0a2017-06-12 16:17:30 -0400332 if (cs->isNumericalTransferFn(&fn) && cs->toXYZD50(&toXYZD50)) {
Matt Sarett5df93de2017-03-22 21:52:47 +0000333 return SkICC::WriteToICC(fn, toXYZD50);
334 }
335
336 // TODO: Should we support writing ICC profiles for additional color spaces?
337 return nullptr;
338}
339
340#endif // SkImageEncoderFns_DEFINED