blob: 0c4b305156fa913b4ffb04dd416b698fe25a4467 [file] [log] [blame] [edit]
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkEncodedInfo_DEFINED
#define SkEncodedInfo_DEFINED
#include "include/core/SkAlphaType.h"
#include "include/core/SkColorSpace.h"
#include "include/core/SkColorType.h"
#include "include/core/SkData.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkTypes.h"
#include "include/private/SkHdrMetadata.h"
#include "include/private/base/SkTo.h"
#include "modules/skcms/skcms.h"
#include <cstdint>
#include <memory>
#include <tuple>
#include <utility>
struct SkEncodedInfo {
public:
class ICCProfile {
public:
static std::unique_ptr<ICCProfile> Make(sk_sp<SkData>);
static std::unique_ptr<ICCProfile> Make(const skcms_ICCProfile&);
const skcms_ICCProfile* profile() const { return &fProfile; }
sk_sp<const SkData> data() const { return fData; }
private:
ICCProfile(const skcms_ICCProfile&, sk_sp<const SkData> = nullptr);
skcms_ICCProfile fProfile;
sk_sp<const SkData> fData;
};
enum Alpha {
kOpaque_Alpha,
kUnpremul_Alpha,
// Each pixel is either fully opaque or fully transparent.
// There is no difference between requesting kPremul or kUnpremul.
kBinary_Alpha,
};
/*
* We strive to make the number of components per pixel obvious through
* our naming conventions.
* Ex: kRGB has 3 components. kRGBA has 4 components.
*
* This sometimes results in redundant Alpha and Color information.
* Ex: kRGB images must also be kOpaque.
*/
enum Color {
// PNG, WBMP
kGray_Color,
// PNG
kGrayAlpha_Color,
// PNG with Skia-specific sBIT
// Like kGrayAlpha, except this expects to be treated as
// kAlpha_8_SkColorType, which ignores the gray component. If
// decoded to full color (e.g. kN32), the gray component is respected
// (so it can share code with kGrayAlpha).
kXAlpha_Color,
// PNG
// 565 images may be encoded to PNG by specifying the number of
// significant bits for each channel. This is a strange 565
// representation because the image is still encoded with 8 bits per
// component.
k565_Color,
// PNG, GIF, BMP
kPalette_Color,
// PNG, RAW
kRGB_Color,
kRGBA_Color,
// BMP
kBGR_Color,
kBGRX_Color,
kBGRA_Color,
// JPEG, WEBP
kYUV_Color,
// WEBP
kYUVA_Color,
// JPEG
// Photoshop actually writes inverted CMYK data into JPEGs, where zero
// represents 100% ink coverage. For this reason, we treat CMYK JPEGs
// as having inverted CMYK. libjpeg-turbo warns that this may break
// other applications, but the CMYK JPEGs we see on the web expect to
// be treated as inverted CMYK.
kInvertedCMYK_Color,
kYCCK_Color,
};
static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha,
int bitsPerComponent) {
return Make(width, height, color, alpha, bitsPerComponent, nullptr);
}
static SkEncodedInfo Make(int width, int height, Color color,
Alpha alpha, int bitsPerComponent, std::unique_ptr<ICCProfile> profile) {
return Make(width, height, color, alpha, /*bitsPerComponent*/ bitsPerComponent,
std::move(profile), /*colorDepth*/ bitsPerComponent);
}
static SkEncodedInfo Make(int width, int height, Color color,
Alpha alpha, int bitsPerComponent, std::unique_ptr<ICCProfile> profile,
int colorDepth) {
return Make(width, height, color, alpha, bitsPerComponent, colorDepth, std::move(profile),
skhdr::Metadata::MakeEmpty());
}
static SkEncodedInfo Make(int width, int height, Color color,
Alpha alpha, int bitsPerComponent, int colorDepth, std::unique_ptr<ICCProfile> profile,
const skhdr::Metadata& hdrMetadata) {
SkASSERT(1 == bitsPerComponent ||
2 == bitsPerComponent ||
4 == bitsPerComponent ||
8 == bitsPerComponent ||
16 == bitsPerComponent);
VerifyColor(color, alpha, bitsPerComponent);
return SkEncodedInfo(width,
height,
color,
alpha,
SkToU8(bitsPerComponent),
SkToU8(colorDepth),
std::move(profile),
hdrMetadata);
}
/*
* Returns a recommended SkImageInfo.
*
* TODO: Leave this up to the client.
*/
SkImageInfo makeImageInfo() const {
auto ct = kGray_Color == fColor ? kGray_8_SkColorType :
kXAlpha_Color == fColor ? kAlpha_8_SkColorType :
k565_Color == fColor ? kRGB_565_SkColorType :
kN32_SkColorType ;
auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType
: kUnpremul_SkAlphaType;
sk_sp<SkColorSpace> cs = fProfile ? SkColorSpace::Make(*fProfile->profile())
: nullptr;
if (!cs) {
cs = SkColorSpace::MakeSRGB();
}
return SkImageInfo::Make(fWidth, fHeight, ct, alpha, std::move(cs));
}
int width() const { return fWidth; }
int height() const { return fHeight; }
Color color() const { return fColor; }
Alpha alpha() const { return fAlpha; }
bool opaque() const { return fAlpha == kOpaque_Alpha; }
const skcms_ICCProfile* profile() const {
if (!fProfile) return nullptr;
return fProfile->profile();
}
sk_sp<const SkData> profileData() const {
if (!fProfile) return nullptr;
return fProfile->data();
}
uint8_t bitsPerComponent() const { return fBitsPerComponent; }
uint8_t bitsPerPixel() const {
switch (fColor) {
case kGray_Color:
return fBitsPerComponent;
case kXAlpha_Color:
case kGrayAlpha_Color:
return 2 * fBitsPerComponent;
case kPalette_Color:
return fBitsPerComponent;
case kRGB_Color:
case kBGR_Color:
case kYUV_Color:
case k565_Color:
return 3 * fBitsPerComponent;
case kRGBA_Color:
case kBGRA_Color:
case kBGRX_Color:
case kYUVA_Color:
case kInvertedCMYK_Color:
case kYCCK_Color:
return 4 * fBitsPerComponent;
}
SkASSERT(false);
return 0;
}
SkEncodedInfo(const SkEncodedInfo& orig) = delete;
SkEncodedInfo& operator=(const SkEncodedInfo&) = delete;
SkEncodedInfo(SkEncodedInfo&& orig) = default;
SkEncodedInfo& operator=(SkEncodedInfo&&) = default;
// Explicit copy method, to avoid accidental copying.
SkEncodedInfo copy() const {
return SkEncodedInfo(fWidth,
fHeight,
fColor,
fAlpha,
fBitsPerComponent,
fColorDepth,
fProfile ? std::make_unique<const ICCProfile>(*fProfile) : nullptr,
fHdrMetadata);
}
// Return number of bits of R/G/B channel
uint8_t getColorDepth() const {
return fColorDepth;
}
// Return the HDR metadata associated with this image. Note that even SDR images can include
// HDR metadata (e.g, indicating how to inverse tone map when displayed on an HDR display).
const skhdr::Metadata& getHdrMetadata() const {
return fHdrMetadata;
}
private:
SkEncodedInfo(int width,
int height,
Color color,
Alpha alpha,
uint8_t bitsPerComponent,
uint8_t colorDepth,
std::unique_ptr<const ICCProfile> profile,
const skhdr::Metadata& hdrMetadata)
: fWidth(width)
, fHeight(height)
, fColor(color)
, fAlpha(alpha)
, fBitsPerComponent(bitsPerComponent)
, fColorDepth(colorDepth)
, fProfile(std::move(profile))
, fHdrMetadata(hdrMetadata) {}
static void VerifyColor(Color color, Alpha alpha, int bitsPerComponent) {
// Avoid `-Wunused-parameter` warnings on non-debug builds.
std::ignore = alpha;
std::ignore = bitsPerComponent;
switch (color) {
case kGray_Color:
SkASSERT(kOpaque_Alpha == alpha);
return;
case kGrayAlpha_Color:
SkASSERT(kOpaque_Alpha != alpha);
return;
case kPalette_Color:
SkASSERT(16 != bitsPerComponent);
return;
case kRGB_Color:
case kBGR_Color:
case kBGRX_Color:
SkASSERT(kOpaque_Alpha == alpha);
SkASSERT(bitsPerComponent >= 8);
return;
case kYUV_Color:
case kInvertedCMYK_Color:
case kYCCK_Color:
SkASSERT(kOpaque_Alpha == alpha);
SkASSERT(8 == bitsPerComponent);
return;
case kRGBA_Color:
SkASSERT(bitsPerComponent >= 8);
return;
case kBGRA_Color:
case kYUVA_Color:
SkASSERT(8 == bitsPerComponent);
return;
case kXAlpha_Color:
SkASSERT(kUnpremul_Alpha == alpha);
SkASSERT(8 == bitsPerComponent);
return;
case k565_Color:
SkASSERT(kOpaque_Alpha == alpha);
SkASSERT(8 == bitsPerComponent);
return;
}
SkASSERT(false); // Unrecognized `color` enum value.
}
int fWidth;
int fHeight;
Color fColor;
Alpha fAlpha;
uint8_t fBitsPerComponent;
uint8_t fColorDepth;
std::unique_ptr<const ICCProfile> fProfile;
skhdr::Metadata fHdrMetadata;
};
#endif