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 "SkColorData.h" 18 #include "SkICC.h" 19 #include "SkOpts.h" 20 #include "SkPreConfig.h" 21 #include "SkRasterPipeline.h" 22 #include "SkUnPreMultiply.h" 23 #include "SkUnPreMultiplyPriv.h" 24 #include "../jumper/SkJumper.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 kAlpha_8_Config to 2-bytes-per-pixel GrayAlpha. 95 */ 96 static inline void transform_scanline_A8_to_GrayAlpha(char* SK_RESTRICT dst, 97 const char* SK_RESTRICT src, 98 int width, int, const SkPMColor*) { 99 for (int i = 0; i < width; i++) { 100 *dst++ = 0; // gray (ignored) 101 *dst++ = *src++; // alpha 102 } 103 } 104 105 /** 106 * Transform from kRGBA_8888_SkColorType to 3-bytes-per-pixel RGB. 107 * Alpha channel data is abandoned. 108 */ 109 static inline void transform_scanline_RGBX(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 110 int width, int, const SkPMColor*) { 111 const uint32_t* srcP = (const SkPMColor*)src; 112 for (int i = 0; i < width; i++) { 113 uint32_t c = *srcP++; 114 *dst++ = (c >> 0) & 0xFF; 115 *dst++ = (c >> 8) & 0xFF; 116 *dst++ = (c >> 16) & 0xFF; 117 } 118 } 119 120 /** 121 * Transform from kBGRA_8888_SkColorType to 3-bytes-per-pixel RGB. 122 * Alpha channel data is abandoned. 123 */ 124 static inline void transform_scanline_BGRX(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 125 int width, int, const SkPMColor*) { 126 const uint32_t* srcP = (const SkPMColor*)src; 127 for (int i = 0; i < width; i++) { 128 uint32_t c = *srcP++; 129 *dst++ = (c >> 16) & 0xFF; 130 *dst++ = (c >> 8) & 0xFF; 131 *dst++ = (c >> 0) & 0xFF; 132 } 133 } 134 135 /** 136 * Transform from kARGB_4444_Config to 3-bytes-per-pixel RGB. 137 * Alpha channel data, if any, is abandoned. 138 */ 139 static inline void transform_scanline_444(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 140 int width, int, const SkPMColor*) { 141 const SkPMColor16* srcP = (const SkPMColor16*)src; 142 for (int i = 0; i < width; i++) { 143 SkPMColor16 c = *srcP++; 144 *dst++ = SkPacked4444ToR32(c); 145 *dst++ = SkPacked4444ToG32(c); 146 *dst++ = SkPacked4444ToB32(c); 147 } 148 } 149 150 /** 151 * Transform from legacy kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. 152 */ 153 static inline void transform_scanline_rgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 154 int width, int, const SkPMColor*) { 155 SkUnpremultiplyRow<false>((uint32_t*) dst, (const uint32_t*) src, width); 156 } 157 158 /** 159 * Transform from legacy kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. 160 */ 161 static inline void transform_scanline_bgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 162 int width, int, const SkPMColor*) { 163 SkUnpremultiplyRow<true>((uint32_t*) dst, (const uint32_t*) src, width); 164 } 165 166 template <bool kIsRGBA> 167 static inline void transform_scanline_unpremultiply_sRGB(void* dst, const void* src, int width) { 168 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 }, 169 dst_ctx = { (void*)dst, 0 }; 170 SkRasterPipeline_<256> p; 171 if (kIsRGBA) { 172 p.append(SkRasterPipeline::load_8888, &src_ctx); 173 } else { 174 p.append(SkRasterPipeline::load_bgra, &src_ctx); 175 } 176 177 p.append(SkRasterPipeline::from_srgb); 178 p.append(SkRasterPipeline::unpremul); 179 p.append(SkRasterPipeline::to_srgb); 180 p.append(SkRasterPipeline::store_8888, &dst_ctx); 181 p.run(0,0, width,1); 182 } 183 184 /** 185 * Premultiply RGBA to rgbA. 186 */ 187 static inline void transform_scanline_to_premul_legacy(char* SK_RESTRICT dst, 188 const char* SK_RESTRICT src, 189 int width, int, const SkPMColor*) { 190 SkOpts::RGBA_to_rgbA((uint32_t*)dst, (const uint32_t*)src, width); 191 } 192 193 /** 194 * Premultiply RGBA to rgbA linearly. 195 */ 196 static inline void transform_scanline_to_premul_linear(char* SK_RESTRICT dst, 197 const char* SK_RESTRICT src, 198 int width, int, const SkPMColor*) { 199 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 }, 200 dst_ctx = { (void*)dst, 0 }; 201 SkRasterPipeline_<256> p; 202 p.append(SkRasterPipeline::load_8888, &src_ctx); 203 p.append(SkRasterPipeline::from_srgb); 204 p.append(SkRasterPipeline::premul); 205 p.append(SkRasterPipeline::to_srgb); 206 p.append(SkRasterPipeline::store_8888, &dst_ctx); 207 p.run(0,0, width,1); 208 } 209 210 /** 211 * Transform from kPremul, kRGBA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. 212 */ 213 static inline void transform_scanline_srgbA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 214 int width, int, const SkPMColor*) { 215 transform_scanline_unpremultiply_sRGB<true>(dst, src, width); 216 } 217 218 /** 219 * Transform from kPremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. 220 */ 221 static inline void transform_scanline_sbgrA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 222 int width, int, const SkPMColor*) { 223 transform_scanline_unpremultiply_sRGB<false>(dst, src, width); 224 } 225 226 /** 227 * Transform from kUnpremul, kBGRA_8888_SkColorType to 4-bytes-per-pixel unpremultiplied RGBA. 228 */ 229 static inline void transform_scanline_BGRA(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 230 int width, int, const SkPMColor*) { 231 const uint32_t* srcP = (const SkPMColor*)src; 232 for (int i = 0; i < width; i++) { 233 uint32_t c = *srcP++; 234 *dst++ = (c >> 16) & 0xFF; 235 *dst++ = (c >> 8) & 0xFF; 236 *dst++ = (c >> 0) & 0xFF; 237 *dst++ = (c >> 24) & 0xFF; 238 } 239 } 240 241 /** 242 * Transform from kARGB_8888_Config to 4-bytes-per-pixel RGBA, 243 * with scaling of RGB based on alpha channel. 244 */ 245 static inline void transform_scanline_4444(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 246 int width, int, const SkPMColor*) { 247 const SkPMColor16* srcP = (const SkPMColor16*)src; 248 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); 249 250 for (int i = 0; i < width; i++) { 251 SkPMColor16 c = *srcP++; 252 unsigned a = SkPacked4444ToA32(c); 253 unsigned r = SkPacked4444ToR32(c); 254 unsigned g = SkPacked4444ToG32(c); 255 unsigned b = SkPacked4444ToB32(c); 256 257 if (0 != a && 255 != a) { 258 SkUnPreMultiply::Scale scale = table[a]; 259 r = SkUnPreMultiply::ApplyScale(scale, r); 260 g = SkUnPreMultiply::ApplyScale(scale, g); 261 b = SkUnPreMultiply::ApplyScale(scale, b); 262 } 263 *dst++ = r; 264 *dst++ = g; 265 *dst++ = b; 266 *dst++ = a; 267 } 268 } 269 270 // 888x is opaque RGB in four bytes, with 8 junk bits. We convert that to 3 byte RGB. 271 static inline void transform_scanline_888x(char* dst, const char* src, 272 int width, int, const SkPMColor*) { 273 while (width --> 0) { 274 dst[0] = src[0]; 275 dst[1] = src[1]; 276 dst[2] = src[2]; 277 dst += 3; 278 src += 4; 279 } 280 } 281 282 // 101010x is opaque RGB in four bytes, with 2 bits junk. We convert to 6 byte RGB (big endian). 283 static inline void transform_scanline_101010x(char* dst, const char* src, 284 int width, int, const SkPMColor*) { 285 auto d = ( uint16_t*)dst; 286 auto s = (const uint32_t*)src; 287 while (width --> 0) { 288 uint32_t r = (*s >> 0) & 1023, 289 g = (*s >> 10) & 1023, 290 b = (*s >> 20) & 1023; 291 292 // Scale 10-bit unorms to 16-bit by replicating the most significant bits. 293 r = (r << 6) | (r >> 4); 294 g = (g << 6) | (g >> 4); 295 b = (b << 6) | (b >> 4); 296 297 // Store big-endian. 298 d[0] = (r >> 8) | (r << 8); 299 d[1] = (g >> 8) | (g << 8); 300 d[2] = (b >> 8) | (b << 8); 301 302 d += 3; // 3 channels 303 s += 1; // 1 whole pixel 304 } 305 } 306 307 static inline void transform_scanline_1010102(char* dst, const char* src, 308 int width, int, const SkPMColor*) { 309 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 }, 310 dst_ctx = { (void*)dst, 0 }; 311 SkRasterPipeline_<256> p; 312 p.append(SkRasterPipeline::load_1010102, &src_ctx); 313 p.append(SkRasterPipeline::store_u16_be, &dst_ctx); 314 p.run(0,0, width,1); 315 } 316 317 static inline void transform_scanline_1010102_premul(char* dst, const char* src, 318 int width, int, const SkPMColor*) { 319 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 }, 320 dst_ctx = { (void*)dst, 0 }; 321 SkRasterPipeline_<256> p; 322 p.append(SkRasterPipeline::load_1010102, &src_ctx); 323 p.append(SkRasterPipeline::unpremul); 324 p.append(SkRasterPipeline::store_u16_be, &dst_ctx); 325 p.run(0,0, width,1); 326 } 327 328 /** 329 * Transform from kRGBA_F16 to 8-bytes-per-pixel RGBA. 330 */ 331 static inline void transform_scanline_F16(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 332 int width, int, const SkPMColor*) { 333 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 }, 334 dst_ctx = { (void*)dst, 0 }; 335 SkRasterPipeline_<256> p; 336 p.append(SkRasterPipeline::load_f16, &src_ctx); 337 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp. 338 p.append(SkRasterPipeline::clamp_1); 339 p.append(SkRasterPipeline::to_srgb); 340 p.append(SkRasterPipeline::store_u16_be, &dst_ctx); 341 p.run(0,0, width,1); 342 } 343 344 /** 345 * Transform from kPremul, kRGBA_F16 to 8-bytes-per-pixel RGBA. 346 */ 347 static inline void transform_scanline_F16_premul(char* SK_RESTRICT dst, const char* SK_RESTRICT src, 348 int width, int, const SkPMColor*) { 349 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 }, 350 dst_ctx = { (void*)dst, 0 }; 351 SkRasterPipeline_<256> p; 352 p.append(SkRasterPipeline::load_f16, &src_ctx); 353 p.append(SkRasterPipeline::unpremul); 354 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp. 355 p.append(SkRasterPipeline::clamp_1); 356 p.append(SkRasterPipeline::to_srgb); 357 p.append(SkRasterPipeline::store_u16_be, &dst_ctx); 358 p.run(0,0, width,1); 359 } 360 361 /** 362 * Transform from kRGBA_F16 to 4-bytes-per-pixel RGBA. 363 */ 364 static inline void transform_scanline_F16_to_8888(char* SK_RESTRICT dst, 365 const char* SK_RESTRICT src, int width, int, 366 const SkPMColor*) { 367 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 }, 368 dst_ctx = { (void*)dst, 0 }; 369 SkRasterPipeline_<256> p; 370 p.append(SkRasterPipeline::load_f16, &src_ctx); 371 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp. 372 p.append(SkRasterPipeline::clamp_1); 373 p.append(SkRasterPipeline::to_srgb); 374 p.append(SkRasterPipeline::store_8888, &dst_ctx); 375 p.run(0,0, width,1); 376 } 377 378 /** 379 * Transform from kPremul, kRGBA_F16 to 4-bytes-per-pixel RGBA. 380 */ 381 static inline void transform_scanline_F16_premul_to_8888(char* SK_RESTRICT dst, 382 const char* SK_RESTRICT src, int width, 383 int, const SkPMColor*) { 384 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 }, 385 dst_ctx = { (void*)dst, 0 }; 386 SkRasterPipeline_<256> p; 387 p.append(SkRasterPipeline::load_f16, &src_ctx); 388 p.append(SkRasterPipeline::unpremul); 389 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp. 390 p.append(SkRasterPipeline::clamp_1); 391 p.append(SkRasterPipeline::to_srgb); 392 p.append(SkRasterPipeline::store_8888, &dst_ctx); 393 p.run(0,0, width,1); 394 } 395 396 /** 397 * Transform from kUnpremul, kRGBA_F16 to premultiplied rgbA 8888. 398 */ 399 static inline void transform_scanline_F16_to_premul_8888(char* SK_RESTRICT dst, 400 const char* SK_RESTRICT src, int width, int, const SkPMColor*) { 401 SkJumper_MemoryCtx src_ctx = { (void*)src, 0 }, 402 dst_ctx = { (void*)dst, 0 }; 403 SkRasterPipeline_<256> p; 404 p.append(SkRasterPipeline::load_f16, &src_ctx); 405 p.append(SkRasterPipeline::clamp_0); // F16 values may be out of [0,1] range, so clamp. 406 p.append(SkRasterPipeline::clamp_1); 407 p.append(SkRasterPipeline::premul); 408 p.append(SkRasterPipeline::to_srgb); 409 p.append(SkRasterPipeline::store_8888, &dst_ctx); 410 p.run(0,0, width,1); 411 } 412 413 static inline sk_sp<SkData> icc_from_color_space(const SkImageInfo& info) { 414 SkColorSpace* cs = info.colorSpace(); 415 if (!cs) { 416 return nullptr; 417 } 418 419 sk_sp<SkColorSpace> owned; 420 if (kRGBA_F16_SkColorType == info.colorType()) { 421 owned = cs->makeSRGBGamma(); 422 cs = owned.get(); 423 } 424 425 SkColorSpaceTransferFn fn; 426 SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); 427 if (cs->isNumericalTransferFn(&fn) && cs->toXYZD50(&toXYZD50)) { 428 return SkICC::WriteToICC(fn, toXYZD50); 429 } 430 431 // TODO: Should we support writing ICC profiles for additional color spaces? 432 return nullptr; 433 } 434 435 #endif // SkImageEncoderFns_DEFINED 436