1 /* 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 */ 7 8 #ifndef SkImageEncoderFns_DEFINED 9 #define SkImageEncoderFns_DEFINED 10 11 /** 12 * Functions to transform scanlines between packed-pixel formats. 13 */ 14 15 #include "SkBitmap.h" 16 #include "SkColor.h" 17 #include "SkColorPriv.h" 18 #include "SkColorSpace_Base.h" 19 #include "SkICC.h" 20 #include "SkOpts.h" 21 #include "SkPreConfig.h" 22 #include "SkRasterPipeline.h" 23 #include "SkUnPreMultiply.h" 24 #include "SkUnPreMultiplyPriv.h" 25 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. 30 * 'bpp' is bytes per pixel in the 'src' buffer. 31 */ 32 typedef void (*transform_scanline_proc)(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 33 int width, int bpp, const SkPMColor* colors); 34 35 /** 36 * Identity transformation: just copy bytes from src to dst. 37 */ 38 static inline void transform_scanline_memcpy(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 39 int width, int bpp, const SkPMColor*) { 40 memcpy(dst, src, width * bpp); 41 } 42 43 static 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 55 static 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 66 static 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 77 /** 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 */ 82 static inline void transform_scanline_565(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 83 int width, int, const SkPMColor*) { 84 const uint16_t* srcP = (const uint16_t*)src; 85 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 /** 94 * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB. 95 * Alpha channel data is abandoned. 96 */ 97 static inline void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 98 int width, int, const SkPMColor*) { 99 const uint32_t* srcP = (const SkPMColor*)src; 100 for (int i = 0; i < width; i++) { 101 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 */ 112 static inline void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 113 int width, int, const SkPMColor*) { 114 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; 120 } 121 } 122 123 /** 124 * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB. 125 * Alpha channel data, if any, is abandoned. 126 */ 127 static inline void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 128 int width, int, const SkPMColor*) { 129 const SkPMColor16* srcP = (const SkPMColor16*)src; 130 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 138 /** 139 * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. 140 */ 141 static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 142 int width, int, const SkPMColor*) { 143 SkUnpremultiplyRow<false>((uint32_t*) dst, (const uint32_t*) src, width); 144 } 145 146 /** 147 * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. 148 */ 149 static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 150 int width, int, const SkPMColor*) { 151 SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width); 152 } 153 154 template <bool kIsRGBA> 155 static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width) { 156 SkRasterPipeline_<256> p; 157 if (kIsRGBA) { 158 p.append(SkRasterPipeline::load_8888, &src); 159 } else { 160 p.append(SkRasterPipeline::load_bgra, &src); 161 } 162 163 p.append_from_srgb(kPremul_SkAlphaType); 164 p.append(SkRasterPipeline::unpremul); 165 p.append(SkRasterPipeline::to_srgb); 166 p.append(SkRasterPipeline::store_8888, &dst); 167 p.run(0,0, width); 168 } 169 170 /** 171 * Premultiply RGBA to rgbA. 172 */ 173 static inline void transform_scanline_to_premul_legacy(char* SK_RESTRICT dst, 174 const char* SK_RESTRICT src, 175 int width, int, const SkPMColor*) { 176 SkOpts::RGBA_to_rgbA((uint32_t*)dst, (const uint32_t*)src, width); 177 } 178 179 /** 180 * Premultiply RGBA to rgbA linearly. 181 */ 182 static inline void transform_scanline_to_premul_linear(char* SK_RESTRICT dst, 183 const char* SK_RESTRICT src, 184 int width, int, const SkPMColor*) { 185 SkRasterPipeline_<256> p; 186 p.append(SkRasterPipeline::load_8888, (const void**) &src); 187 p.append_from_srgb(kUnpremul_SkAlphaType); 188 p.append(SkRasterPipeline::premul); 189 p.append(SkRasterPipeline::to_srgb); 190 p.append(SkRasterPipeline::store_8888, (void**) &dst); 191 p.run(0,0, width); 192 } 193 194 /** 195 * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. 196 */ 197 static inline void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 198 int width, int, const SkPMColor*) { 199 transform_scanline_unpremultiply_sRGB<true>(dst, src, width); 200 } 201 202 /** 203 * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. 204 */ 205 static inline void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 206 int width, int, const SkPMColor*) { 207 transform_scanline_unpremultiply_sRGB<false>(dst, src, width); 208 } 209 210 /** 211 * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. 212 */ 213 static inline void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 214 int width, int, const SkPMColor*) { 215 const uint32_t* srcP = (const SkPMColor*)src; 216 for (int i = 0; i < width; i++) { 217 uint32_t c = *srcP++; 218 *dst++ = (c >> 16) & 0xFF; 219 *dst++ = (c >> 8) & 0xFF; 220 *dst++ = (c >> 0) & 0xFF; 221 *dst++ = (c >> 24) & 0xFF; 222 } 223 } 224 225 /** 226 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA, 227 * with scaling of RGB based on alpha channel. 228 */ 229 static inline void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 230 int width, int, const SkPMColor*) { 231 const SkPMColor16* srcP = (const SkPMColor16*)src; 232 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); 233 234 for (int i = 0; i < width; i++) { 235 SkPMColor16 c = *srcP++; 236 unsigned a = SkPacked4444ToA32(c); 237 unsigned r = SkPacked4444ToR32(c); 238 unsigned g = SkPacked4444ToG32(c); 239 unsigned b = SkPacked4444ToB32(c); 240 241 if (0 != a && 255 != a) { 242 SkUnPreMultiply::Scale scale = table[a]; 243 r = SkUnPreMultiply::ApplyScale(scale, r); 244 g = SkUnPreMultiply::ApplyScale(scale, g); 245 b = SkUnPreMultiply::ApplyScale(scale, b); 246 } 247 *dst++ = r; 248 *dst++ = g; 249 *dst++ = b; 250 *dst++ = a; 251 } 252 } 253 254 /** 255 * Transform from kRGBA_F16 to 8-bytes-per-pixel RGBA. 256 */ 257 static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 258 int width, int, const SkPMColor*) { 259 SkRasterPipeline_<256> p; 260 p.append(SkRasterPipeline::load_f16, (const void**) &src); 261 p.append(SkRasterPipeline::to_srgb); 262 p.append(SkRasterPipeline::store_u16_be, (void**) &dst); 263 p.run(0,0, width); 264 } 265 266 /** 267 * Transform from kPremul, kRGBA_F16 to 8-bytes-per-pixel RGBA. 268 */ 269 static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 270 int width, int, const SkPMColor*) { 271 SkRasterPipeline_<256> 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_u16_be, (void**) &dst); 276 p.run(0,0, width); 277 } 278 279 /** 280 * Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA. 281 */ 282 static inline void transform_scanline_F16_to_8888(char* SK_RESTRICT dst, 283 const char* SK_RESTRICT src, int width, int, 284 const SkPMColor*) { 285 SkRasterPipeline_<256> p; 286 p.append(SkRasterPipeline::load_f16, (const void**) &src); 287 p.append(SkRasterPipeline::to_srgb); 288 p.append(SkRasterPipeline::store_8888, (void**) &dst); 289 p.run(0,0, width); 290 } 291 292 /** 293 * Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA. 294 */ 295 static inline void transform_scanline_F16_premul_to_8888(char* SK_RESTRICT dst, 296 const char* SK_RESTRICT src, int width, 297 int, const SkPMColor*) { 298 SkRasterPipeline_<256> p; 299 p.append(SkRasterPipeline::load_f16, (const void**) &src); 300 p.append(SkRasterPipeline::unpremul); 301 p.append(SkRasterPipeline::to_srgb); 302 p.append(SkRasterPipeline::store_8888, (void**) &dst); 303 p.run(0,0, width); 304 } 305 306 /** 307 * Transform from kUnpremul, kRGBA_F16 to premultiplied rgbA 8888. 308 */ 309 static inline void transform_scanline_F16_to_premul_8888(char* SK_RESTRICT dst, 310 const char* SK_RESTRICT src, int width, int, const SkPMColor*) { 311 SkRasterPipeline_<256> p; 312 p.append(SkRasterPipeline::load_f16, (const void**) &src); 313 p.append(SkRasterPipeline::premul); 314 p.append(SkRasterPipeline::to_srgb); 315 p.append(SkRasterPipeline::store_8888, (void**) &dst); 316 p.run(0,0, width); 317 } 318 319 static inline sk_sp<SkData> icc_from_color_space(const SkImageInfo& info) { 320 SkColorSpace* cs = info.colorSpace(); 321 if (!cs) { 322 return nullptr; 323 } 324 325 sk_sp<SkColorSpace> owned; 326 if (kRGBA_F16_SkColorType == info.colorType()) { 327 owned = as_CSB(cs)->makeSRGBGamma(); 328 cs = owned.get(); 329 } 330 331 SkColorSpaceTransferFn fn; 332 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); 333 if (cs->isNumericalTransferFn(&fn) && cs->toXYZD50(&toXYZD50)) { 334 return SkICC::WriteToICC(fn, toXYZD50); 335 } 336 337 // TODO: Should we support writing ICC profiles for additional color spaces? 338 return nullptr; 339 } 340 341 #endif // SkImageEncoderFns_DEFINED 342