Home | History | Annotate | Download | only in images
      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