blob: 262baa032553481ed518607ccdd8ab0260bfa162 [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
epoger@google.com4ce738b2012-11-16 18:44:18 +000011#include "SkBitmap.h"
12#include "SkColor.h"
Cary Clarka4083c92017-09-15 11:59:23 -040013#include "SkColorData.h"
Matt Sarett5df93de2017-03-22 21:52:47 +000014#include "SkICC.h"
Matt Sarett2e61b182017-05-09 12:46:50 -040015#include "SkOpts.h"
Matt Sarett84014f02017-01-10 11:28:54 -050016#include "SkRasterPipeline.h"
Mike Klein0c904fa2018-11-02 12:24:15 -040017#include "SkTypes.h"
epoger@google.com4ce738b2012-11-16 18:44:18 +000018#include "SkUnPreMultiply.h"
Matt Sarettc7b29082017-02-09 16:22:39 -050019#include "SkUnPreMultiplyPriv.h"
epoger@google.com4ce738b2012-11-16 18:44:18 +000020
Mike Klein0c904fa2018-11-02 12:24:15 -040021typedef void (*transform_scanline_proc)(char* dst, const char* src, int width, int bpp);
epoger@google.com4ce738b2012-11-16 18:44:18 +000022
Mike Klein0c904fa2018-11-02 12:24:15 -040023static inline void transform_scanline_memcpy(char* dst, const char* src, int width, int bpp) {
msarettf17b71f2016-09-12 14:30:03 -070024 memcpy(dst, src, width * bpp);
epoger@google.com4ce738b2012-11-16 18:44:18 +000025}
26
Mike Klein0c904fa2018-11-02 12:24:15 -040027static inline void transform_scanline_gray(char* dst, const char* src, int width, int) {
Matt Sarett62bb2802017-01-23 12:28:02 -050028 for (int i = 0; i < width; i++) {
29 const uint8_t g = (uint8_t) *src++;
30 dst[0] = g;
31 dst[1] = g;
32 dst[2] = g;
33 dst += 3;
34 }
35}
36
Mike Klein0c904fa2018-11-02 12:24:15 -040037static inline void transform_scanline_565(char* dst, const char* src, int width, int) {
msarettf17b71f2016-09-12 14:30:03 -070038 const uint16_t* srcP = (const uint16_t*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000039 for (int i = 0; i < width; i++) {
40 unsigned c = *srcP++;
41 *dst++ = SkPacked16ToR32(c);
42 *dst++ = SkPacked16ToG32(c);
43 *dst++ = SkPacked16ToB32(c);
44 }
45}
46
Mike Klein0c904fa2018-11-02 12:24:15 -040047static inline void transform_scanline_A8_to_GrayAlpha(char* dst, const char* src, int width, int) {
Mike Reedd6cb11e2017-11-30 15:33:04 -050048 for (int i = 0; i < width; i++) {
49 *dst++ = 0; // gray (ignored)
50 *dst++ = *src++; // alpha
51 }
52}
53
Mike Klein0c904fa2018-11-02 12:24:15 -040054static inline void transform_scanline_RGBX(char* dst, const char* src, int width, int) {
msarettf17b71f2016-09-12 14:30:03 -070055 const uint32_t* srcP = (const SkPMColor*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000056 for (int i = 0; i < width; i++) {
msarettf17b71f2016-09-12 14:30:03 -070057 uint32_t c = *srcP++;
58 *dst++ = (c >> 0) & 0xFF;
59 *dst++ = (c >> 8) & 0xFF;
60 *dst++ = (c >> 16) & 0xFF;
61 }
62}
63
Mike Klein0c904fa2018-11-02 12:24:15 -040064static inline void transform_scanline_BGRX(char* dst, const char* src, int width, int) {
msarettf17b71f2016-09-12 14:30:03 -070065 const uint32_t* srcP = (const SkPMColor*)src;
66 for (int i = 0; i < width; i++) {
67 uint32_t c = *srcP++;
68 *dst++ = (c >> 16) & 0xFF;
69 *dst++ = (c >> 8) & 0xFF;
70 *dst++ = (c >> 0) & 0xFF;
epoger@google.com4ce738b2012-11-16 18:44:18 +000071 }
72}
73
Mike Klein0c904fa2018-11-02 12:24:15 -040074static inline void transform_scanline_444(char* dst, const char* src, int width, int) {
msarettf17b71f2016-09-12 14:30:03 -070075 const SkPMColor16* srcP = (const SkPMColor16*)src;
epoger@google.com4ce738b2012-11-16 18:44:18 +000076 for (int i = 0; i < width; i++) {
77 SkPMColor16 c = *srcP++;
78 *dst++ = SkPacked4444ToR32(c);
79 *dst++ = SkPacked4444ToG32(c);
80 *dst++ = SkPacked4444ToB32(c);
81 }
82}
83
Mike Klein0c904fa2018-11-02 12:24:15 -040084static inline void transform_scanline_rgbA(char* dst, const char* src, int width, int) {
Matt Sarettc7b29082017-02-09 16:22:39 -050085 SkUnpremultiplyRow<false>((uint32_t*) dst, (const uint32_t*) src, width);
Matt Sarett84014f02017-01-10 11:28:54 -050086}
87
Mike Klein0c904fa2018-11-02 12:24:15 -040088static inline void transform_scanline_bgrA(char* dst, const char* src, int width, int) {
Matt Sarettc7b29082017-02-09 16:22:39 -050089 SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width);
Matt Sarett84014f02017-01-10 11:28:54 -050090}
91
Mike Klein0c904fa2018-11-02 12:24:15 -040092static inline void transform_scanline_to_premul_legacy(char* dst, const char* src, int width, int) {
Matt Sarett2e61b182017-05-09 12:46:50 -040093 SkOpts::RGBA_to_rgbA((uint32_t*)dst, (const uint32_t*)src, width);
94}
95
Mike Klein0c904fa2018-11-02 12:24:15 -040096static inline void transform_scanline_BGRA(char* dst, const char* src, int width, int) {
msarettf17b71f2016-09-12 14:30:03 -070097 const uint32_t* srcP = (const SkPMColor*)src;
98 for (int i = 0; i < width; i++) {
99 uint32_t c = *srcP++;
100 *dst++ = (c >> 16) & 0xFF;
101 *dst++ = (c >> 8) & 0xFF;
102 *dst++ = (c >> 0) & 0xFF;
103 *dst++ = (c >> 24) & 0xFF;
104 }
105}
106
Mike Klein0c904fa2018-11-02 12:24:15 -0400107static inline void transform_scanline_4444(char* dst, const char* src, int width, int) {
msarettf17b71f2016-09-12 14:30:03 -0700108 const SkPMColor16* srcP = (const SkPMColor16*)src;
109 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
epoger@google.com4ce738b2012-11-16 18:44:18 +0000110
111 for (int i = 0; i < width; i++) {
112 SkPMColor16 c = *srcP++;
113 unsigned a = SkPacked4444ToA32(c);
114 unsigned r = SkPacked4444ToR32(c);
115 unsigned g = SkPacked4444ToG32(c);
116 unsigned b = SkPacked4444ToB32(c);
117
118 if (0 != a && 255 != a) {
119 SkUnPreMultiply::Scale scale = table[a];
120 r = SkUnPreMultiply::ApplyScale(scale, r);
121 g = SkUnPreMultiply::ApplyScale(scale, g);
122 b = SkUnPreMultiply::ApplyScale(scale, b);
123 }
124 *dst++ = r;
125 *dst++ = g;
126 *dst++ = b;
127 *dst++ = a;
128 }
129}
Matt Sarett1da27ef2017-01-19 17:14:07 -0500130
Mike Klein0c904fa2018-11-02 12:24:15 -0400131static inline void transform_scanline_101010x(char* dst, const char* src, int width, int) {
Mike Kleinac568a92018-01-25 09:09:32 -0500132 auto d = ( uint16_t*)dst;
133 auto s = (const uint32_t*)src;
134 while (width --> 0) {
135 uint32_t r = (*s >> 0) & 1023,
136 g = (*s >> 10) & 1023,
137 b = (*s >> 20) & 1023;
138
139 // Scale 10-bit unorms to 16-bit by replicating the most significant bits.
140 r = (r << 6) | (r >> 4);
141 g = (g << 6) | (g >> 4);
142 b = (b << 6) | (b >> 4);
143
144 // Store big-endian.
145 d[0] = (r >> 8) | (r << 8);
146 d[1] = (g >> 8) | (g << 8);
147 d[2] = (b >> 8) | (b << 8);
148
149 d += 3; // 3 channels
150 s += 1; // 1 whole pixel
151 }
152}
153
Mike Klein0c904fa2018-11-02 12:24:15 -0400154static inline void transform_scanline_1010102(char* dst, const char* src, int width, int) {
Mike Kleinb11ab572018-10-24 06:42:14 -0400155 SkRasterPipeline_MemoryCtx src_ctx = { (void*)src, 0 },
156 dst_ctx = { (void*)dst, 0 };
Mike Kleinac568a92018-01-25 09:09:32 -0500157 SkRasterPipeline_<256> p;
158 p.append(SkRasterPipeline::load_1010102, &src_ctx);
159 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
160 p.run(0,0, width,1);
161}
162
Mike Klein0c904fa2018-11-02 12:24:15 -0400163static inline void transform_scanline_1010102_premul(char* dst, const char* src, int width, int) {
Mike Kleinb11ab572018-10-24 06:42:14 -0400164 SkRasterPipeline_MemoryCtx src_ctx = { (void*)src, 0 },
165 dst_ctx = { (void*)dst, 0 };
Mike Kleinac568a92018-01-25 09:09:32 -0500166 SkRasterPipeline_<256> p;
167 p.append(SkRasterPipeline::load_1010102, &src_ctx);
168 p.append(SkRasterPipeline::unpremul);
169 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
170 p.run(0,0, width,1);
171}
172
Mike Klein0c904fa2018-11-02 12:24:15 -0400173static inline void transform_scanline_F16(char* dst, const char* src, int width, int) {
Mike Kleinb11ab572018-10-24 06:42:14 -0400174 SkRasterPipeline_MemoryCtx src_ctx = { (void*)src, 0 },
175 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400176 SkRasterPipeline_<256> p;
Mike Klein45c16fa2017-07-18 18:15:13 -0400177 p.append(SkRasterPipeline::load_f16, &src_ctx);
Mike Kleince988012017-07-21 13:11:37 -0400178 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
179 p.append(SkRasterPipeline::clamp_1);
Mike Klein45c16fa2017-07-18 18:15:13 -0400180 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
181 p.run(0,0, width,1);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500182}
183
Mike Klein0c904fa2018-11-02 12:24:15 -0400184static inline void transform_scanline_F16_premul(char* dst, const char* src, int width, int) {
Mike Kleinb11ab572018-10-24 06:42:14 -0400185 SkRasterPipeline_MemoryCtx src_ctx = { (void*)src, 0 },
186 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400187 SkRasterPipeline_<256> p;
Mike Klein45c16fa2017-07-18 18:15:13 -0400188 p.append(SkRasterPipeline::load_f16, &src_ctx);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500189 p.append(SkRasterPipeline::unpremul);
Mike Kleince988012017-07-21 13:11:37 -0400190 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
191 p.append(SkRasterPipeline::clamp_1);
Mike Klein45c16fa2017-07-18 18:15:13 -0400192 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
193 p.run(0,0, width,1);
Matt Sarett1da27ef2017-01-19 17:14:07 -0500194}
Matt Sarett55213562017-01-23 19:37:37 -0500195
Mike Klein0c904fa2018-11-02 12:24:15 -0400196static inline void transform_scanline_F16_to_8888(char* dst, const char* src, int width, int) {
Mike Kleinb11ab572018-10-24 06:42:14 -0400197 SkRasterPipeline_MemoryCtx src_ctx = { (void*)src, 0 },
198 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400199 SkRasterPipeline_<256> p;
Mike Klein45c16fa2017-07-18 18:15:13 -0400200 p.append(SkRasterPipeline::load_f16, &src_ctx);
Mike Kleince988012017-07-21 13:11:37 -0400201 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
202 p.append(SkRasterPipeline::clamp_1);
Mike Klein45c16fa2017-07-18 18:15:13 -0400203 p.append(SkRasterPipeline::store_8888, &dst_ctx);
204 p.run(0,0, width,1);
Matt Sarett55213562017-01-23 19:37:37 -0500205}
206
Mike Klein0c904fa2018-11-02 12:24:15 -0400207static inline void transform_scanline_F16_premul_to_8888(char* dst,
208 const char* src,
209 int width,
210 int) {
Mike Kleinb11ab572018-10-24 06:42:14 -0400211 SkRasterPipeline_MemoryCtx src_ctx = { (void*)src, 0 },
212 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400213 SkRasterPipeline_<256> p;
Mike Klein45c16fa2017-07-18 18:15:13 -0400214 p.append(SkRasterPipeline::load_f16, &src_ctx);
Matt Sarett55213562017-01-23 19:37:37 -0500215 p.append(SkRasterPipeline::unpremul);
Mike Kleince988012017-07-21 13:11:37 -0400216 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
217 p.append(SkRasterPipeline::clamp_1);
Mike Klein45c16fa2017-07-18 18:15:13 -0400218 p.append(SkRasterPipeline::store_8888, &dst_ctx);
219 p.run(0,0, width,1);
Matt Sarett55213562017-01-23 19:37:37 -0500220}
Matt Sarett5df93de2017-03-22 21:52:47 +0000221
Mike Klein0c904fa2018-11-02 12:24:15 -0400222static inline void transform_scanline_F16_to_premul_8888(char* dst,
223 const char* src,
224 int width,
225 int) {
Mike Kleinb11ab572018-10-24 06:42:14 -0400226 SkRasterPipeline_MemoryCtx src_ctx = { (void*)src, 0 },
227 dst_ctx = { (void*)dst, 0 };
Mike Kleinb24704d2017-05-24 07:53:00 -0400228 SkRasterPipeline_<256> p;
Mike Klein45c16fa2017-07-18 18:15:13 -0400229 p.append(SkRasterPipeline::load_f16, &src_ctx);
Mike Kleince988012017-07-21 13:11:37 -0400230 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp.
231 p.append(SkRasterPipeline::clamp_1);
Matt Sarett2e61b182017-05-09 12:46:50 -0400232 p.append(SkRasterPipeline::premul);
Mike Klein45c16fa2017-07-18 18:15:13 -0400233 p.append(SkRasterPipeline::store_8888, &dst_ctx);
234 p.run(0,0, width,1);
Matt Sarett2e61b182017-05-09 12:46:50 -0400235}
236
Mike Klein0c904fa2018-11-02 12:24:15 -0400237static inline void transform_scanline_F32(char* dst, const char* src, int width, int) {
Mike Kleinb11ab572018-10-24 06:42:14 -0400238 SkRasterPipeline_MemoryCtx src_ctx = { (void*)src, 0 },
239 dst_ctx = { (void*)dst, 0 };
Mike Klein37854712018-06-26 11:43:06 -0400240 SkRasterPipeline_<256> p;
241 p.append(SkRasterPipeline::load_f32, &src_ctx);
242 p.append(SkRasterPipeline::clamp_0); // F32 values may be out of [0,1] range, so clamp.
243 p.append(SkRasterPipeline::clamp_1);
Mike Klein37854712018-06-26 11:43:06 -0400244 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
245 p.run(0,0, width,1);
246}
247
Mike Klein0c904fa2018-11-02 12:24:15 -0400248static inline void transform_scanline_F32_premul(char* dst, const char* src, int width, int) {
Mike Kleinb11ab572018-10-24 06:42:14 -0400249 SkRasterPipeline_MemoryCtx src_ctx = { (void*)src, 0 },
250 dst_ctx = { (void*)dst, 0 };
Mike Klein37854712018-06-26 11:43:06 -0400251 SkRasterPipeline_<256> p;
252 p.append(SkRasterPipeline::load_f32, &src_ctx);
253 p.append(SkRasterPipeline::unpremul);
254 p.append(SkRasterPipeline::clamp_0); // F32 values may be out of [0,1] range, so clamp.
255 p.append(SkRasterPipeline::clamp_1);
Mike Klein37854712018-06-26 11:43:06 -0400256 p.append(SkRasterPipeline::store_u16_be, &dst_ctx);
257 p.run(0,0, width,1);
258}
259
Matt Sarett1950e0a2017-06-12 16:17:30 -0400260static inline sk_sp<SkData> icc_from_color_space(const SkImageInfo& info) {
261 SkColorSpace* cs = info.colorSpace();
262 if (!cs) {
263 return nullptr;
264 }
265
Matt Sarett5df93de2017-03-22 21:52:47 +0000266 SkColorSpaceTransferFn fn;
Mike Klein4429a4f2018-10-04 09:06:00 -0400267 SkMatrix44 toXYZD50;
Matt Sarett1950e0a2017-06-12 16:17:30 -0400268 if (cs->isNumericalTransferFn(&fn) && cs->toXYZD50(&toXYZD50)) {
Matt Sarett5df93de2017-03-22 21:52:47 +0000269 return SkICC::WriteToICC(fn, toXYZD50);
270 }
Matt Sarett5df93de2017-03-22 21:52:47 +0000271 return nullptr;
272}
273
274#endif // SkImageEncoderFns_DEFINED