Home | History | Annotate | Download | only in private
      1 /*
      2  * Copyright 2016 Google Inc.
      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 SkEncodedInfo_DEFINED
      9 #define SkEncodedInfo_DEFINED
     10 
     11 #include "SkData.h"
     12 #include "SkImageInfo.h"
     13 #include "../../third_party/skcms/skcms.h"
     14 
     15 struct SkEncodedInfo {
     16 public:
     17     class ICCProfile {
     18     public:
     19         static std::unique_ptr<ICCProfile> Make(sk_sp<SkData>);
     20         static std::unique_ptr<ICCProfile> Make(const skcms_ICCProfile&);
     21 
     22         const skcms_ICCProfile* profile() const { return &fProfile; }
     23     private:
     24         ICCProfile(const skcms_ICCProfile&, sk_sp<SkData> = nullptr);
     25 
     26         skcms_ICCProfile fProfile;
     27         sk_sp<SkData>    fData;
     28     };
     29 
     30     enum Alpha {
     31         kOpaque_Alpha,
     32         kUnpremul_Alpha,
     33 
     34         // Each pixel is either fully opaque or fully transparent.
     35         // There is no difference between requesting kPremul or kUnpremul.
     36         kBinary_Alpha,
     37     };
     38 
     39     /*
     40      * We strive to make the number of components per pixel obvious through
     41      * our naming conventions.
     42      * Ex: kRGB has 3 components.  kRGBA has 4 components.
     43      *
     44      * This sometimes results in redundant Alpha and Color information.
     45      * Ex: kRGB images must also be kOpaque.
     46      */
     47     enum Color {
     48         // PNG, WBMP
     49         kGray_Color,
     50 
     51         // PNG
     52         kGrayAlpha_Color,
     53 
     54         // PNG with Skia-specific sBIT
     55         // Like kGrayAlpha, except this expects to be treated as
     56         // kAlpha_8_SkColorType, which ignores the gray component. If
     57         // decoded to full color (e.g. kN32), the gray component is respected
     58         // (so it can share code with kGrayAlpha).
     59         kXAlpha_Color,
     60 
     61         // PNG
     62         // 565 images may be encoded to PNG by specifying the number of
     63         // significant bits for each channel.  This is a strange 565
     64         // representation because the image is still encoded with 8 bits per
     65         // component.
     66         k565_Color,
     67 
     68         // PNG, GIF, BMP
     69         kPalette_Color,
     70 
     71         // PNG, RAW
     72         kRGB_Color,
     73         kRGBA_Color,
     74 
     75         // BMP
     76         kBGR_Color,
     77         kBGRX_Color,
     78         kBGRA_Color,
     79 
     80         // JPEG, WEBP
     81         kYUV_Color,
     82 
     83         // WEBP
     84         kYUVA_Color,
     85 
     86         // JPEG
     87         // Photoshop actually writes inverted CMYK data into JPEGs, where zero
     88         // represents 100% ink coverage.  For this reason, we treat CMYK JPEGs
     89         // as having inverted CMYK.  libjpeg-turbo warns that this may break
     90         // other applications, but the CMYK JPEGs we see on the web expect to
     91         // be treated as inverted CMYK.
     92         kInvertedCMYK_Color,
     93         kYCCK_Color,
     94     };
     95 
     96     static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha,
     97             int bitsPerComponent) {
     98         return Make(width, height, color, alpha, bitsPerComponent, nullptr);
     99     }
    100 
    101     static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha,
    102             int bitsPerComponent, std::unique_ptr<ICCProfile> profile) {
    103         SkASSERT(1 == bitsPerComponent ||
    104                  2 == bitsPerComponent ||
    105                  4 == bitsPerComponent ||
    106                  8 == bitsPerComponent ||
    107                  16 == bitsPerComponent);
    108 
    109         switch (color) {
    110             case kGray_Color:
    111                 SkASSERT(kOpaque_Alpha == alpha);
    112                 break;
    113             case kGrayAlpha_Color:
    114                 SkASSERT(kOpaque_Alpha != alpha);
    115                 break;
    116             case kPalette_Color:
    117                 SkASSERT(16 != bitsPerComponent);
    118                 break;
    119             case kRGB_Color:
    120             case kBGR_Color:
    121             case kBGRX_Color:
    122                 SkASSERT(kOpaque_Alpha == alpha);
    123                 SkASSERT(bitsPerComponent >= 8);
    124                 break;
    125             case kYUV_Color:
    126             case kInvertedCMYK_Color:
    127             case kYCCK_Color:
    128                 SkASSERT(kOpaque_Alpha == alpha);
    129                 SkASSERT(8 == bitsPerComponent);
    130                 break;
    131             case kRGBA_Color:
    132                 SkASSERT(bitsPerComponent >= 8);
    133                 break;
    134             case kBGRA_Color:
    135             case kYUVA_Color:
    136                 SkASSERT(8 == bitsPerComponent);
    137                 break;
    138             case kXAlpha_Color:
    139                 SkASSERT(kUnpremul_Alpha == alpha);
    140                 SkASSERT(8 == bitsPerComponent);
    141                 break;
    142             case k565_Color:
    143                 SkASSERT(kOpaque_Alpha == alpha);
    144                 SkASSERT(8 == bitsPerComponent);
    145                 break;
    146             default:
    147                 SkASSERT(false);
    148                 break;
    149         }
    150 
    151         return SkEncodedInfo(width, height, color, alpha, bitsPerComponent, std::move(profile));
    152     }
    153 
    154     /*
    155      * Returns a recommended SkImageInfo.
    156      *
    157      * TODO: Leave this up to the client.
    158      */
    159     SkImageInfo makeImageInfo() const {
    160         auto ct =  kGray_Color == fColor ? kGray_8_SkColorType   :
    161                  kXAlpha_Color == fColor ? kAlpha_8_SkColorType  :
    162                     k565_Color == fColor ? kRGB_565_SkColorType  :
    163                                            kN32_SkColorType      ;
    164         auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType
    165                                              : kUnpremul_SkAlphaType;
    166         sk_sp<SkColorSpace> cs = fProfile ? SkColorSpace::Make(*fProfile->profile())
    167                                           : nullptr;
    168         if (!cs) {
    169             cs = SkColorSpace::MakeSRGB();
    170         }
    171         return SkImageInfo::Make(fWidth, fHeight, ct, alpha, std::move(cs));
    172     }
    173 
    174     int   width() const { return fWidth;  }
    175     int  height() const { return fHeight; }
    176     Color color() const { return fColor;  }
    177     Alpha alpha() const { return fAlpha;  }
    178     bool opaque() const { return fAlpha == kOpaque_Alpha; }
    179     const skcms_ICCProfile* profile() const {
    180         if (!fProfile) return nullptr;
    181         return fProfile->profile();
    182     }
    183 
    184     uint8_t bitsPerComponent() const { return fBitsPerComponent; }
    185 
    186     uint8_t bitsPerPixel() const {
    187         switch (fColor) {
    188             case kGray_Color:
    189                 return fBitsPerComponent;
    190             case kXAlpha_Color:
    191             case kGrayAlpha_Color:
    192                 return 2 * fBitsPerComponent;
    193             case kPalette_Color:
    194                 return fBitsPerComponent;
    195             case kRGB_Color:
    196             case kBGR_Color:
    197             case kYUV_Color:
    198             case k565_Color:
    199                 return 3 * fBitsPerComponent;
    200             case kRGBA_Color:
    201             case kBGRA_Color:
    202             case kBGRX_Color:
    203             case kYUVA_Color:
    204             case kInvertedCMYK_Color:
    205             case kYCCK_Color:
    206                 return 4 * fBitsPerComponent;
    207             default:
    208                 SkASSERT(false);
    209                 return 0;
    210         }
    211     }
    212 
    213     SkEncodedInfo(const SkEncodedInfo& orig) = delete;
    214     SkEncodedInfo& operator=(const SkEncodedInfo&) = delete;
    215 
    216     SkEncodedInfo(SkEncodedInfo&& orig) = default;
    217     SkEncodedInfo& operator=(SkEncodedInfo&&) = default;
    218 
    219     // Explicit copy method, to avoid accidental copying.
    220     SkEncodedInfo copy() const {
    221         auto copy = SkEncodedInfo::Make(fWidth, fHeight, fColor, fAlpha, fBitsPerComponent);
    222         if (fProfile) {
    223             copy.fProfile.reset(new ICCProfile(*fProfile.get()));
    224         }
    225         return copy;
    226     }
    227 
    228 private:
    229     SkEncodedInfo(int width, int height, Color color, Alpha alpha,
    230             uint8_t bitsPerComponent, std::unique_ptr<ICCProfile> profile)
    231         : fWidth(width)
    232         , fHeight(height)
    233         , fColor(color)
    234         , fAlpha(alpha)
    235         , fBitsPerComponent(bitsPerComponent)
    236         , fProfile(std::move(profile))
    237     {}
    238 
    239     int                         fWidth;
    240     int                         fHeight;
    241     Color                       fColor;
    242     Alpha                       fAlpha;
    243     uint8_t                     fBitsPerComponent;
    244     std::unique_ptr<ICCProfile> fProfile;
    245 };
    246 
    247 #endif
    248