Reland "Switch SkCodec to use skcms plus fixes""
This reverts commit 83988edfd3
.
The CTS failure was actually due to another CL.
TBR=brianosman@google.com
TBR=djsollen@google.com
Bug: skia:6839
Bug: skia:8052
Bug: skia:8278
Change-Id: Id9f152ec2c66467d90f49df223cb9b7c168ac2ac
Reviewed-on: https://skia-review.googlesource.com/149483
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
This commit is contained in:
parent
1db86c7cf5
commit
36f7e3298e
1
BUILD.gn
1
BUILD.gn
@ -863,6 +863,7 @@ component("skia") {
|
||||
"src/codec/SkCodec.cpp",
|
||||
"src/codec/SkCodecImageGenerator.cpp",
|
||||
"src/codec/SkColorTable.cpp",
|
||||
"src/codec/SkEncodedInfo.cpp",
|
||||
"src/codec/SkGifCodec.cpp",
|
||||
"src/codec/SkMaskSwizzler.cpp",
|
||||
"src/codec/SkMasks.cpp",
|
||||
|
@ -64,6 +64,7 @@ tests_sources = [
|
||||
"$_tests/EGLImageTest.cpp",
|
||||
"$_tests/EmptyPathTest.cpp",
|
||||
"$_tests/EncodeTest.cpp",
|
||||
"$_tests/EncodedInfoTest.cpp",
|
||||
"$_tests/ExifTest.cpp",
|
||||
"$_tests/F16StagesTest.cpp",
|
||||
"$_tests/FillPathTest.cpp",
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "../private/SkEncodedInfo.h"
|
||||
#include "SkCodecAnimation.h"
|
||||
#include "SkColor.h"
|
||||
#include "SkColorSpaceXform.h"
|
||||
#include "SkEncodedImageFormat.h"
|
||||
#include "SkEncodedOrigin.h"
|
||||
#include "SkImageInfo.h"
|
||||
@ -671,21 +670,9 @@ public:
|
||||
protected:
|
||||
const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; }
|
||||
|
||||
using XformFormat = SkColorSpaceXform::ColorFormat;
|
||||
using XformFormat = skcms_PixelFormat;
|
||||
|
||||
SkCodec(int width,
|
||||
int height,
|
||||
const SkEncodedInfo&,
|
||||
XformFormat srcFormat,
|
||||
std::unique_ptr<SkStream>,
|
||||
sk_sp<SkColorSpace>,
|
||||
SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
|
||||
|
||||
/**
|
||||
* Allows the subclass to set the recommended SkImageInfo
|
||||
*/
|
||||
SkCodec(const SkEncodedInfo&,
|
||||
const SkImageInfo&,
|
||||
SkCodec(SkEncodedInfo&&,
|
||||
XformFormat srcFormat,
|
||||
std::unique_ptr<SkStream>,
|
||||
SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
|
||||
@ -780,16 +767,14 @@ protected:
|
||||
|
||||
virtual int onOutputScanline(int inputScanline) const;
|
||||
|
||||
bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha);
|
||||
// Some classes never need a colorXform e.g.
|
||||
// - ICO uses its embedded codec's colorXform
|
||||
// - WBMP is just Black/White
|
||||
virtual bool usesColorXform() const { return true; }
|
||||
void applyColorXform(void* dst, const void* src, int count, SkAlphaType) const;
|
||||
void applyColorXform(void* dst, const void* src, int count) const;
|
||||
|
||||
SkColorSpaceXform* colorXform() const { return fColorXform.get(); }
|
||||
bool xformOnDecode() const { return fXformOnDecode; }
|
||||
bool colorXform() const { return fXformTime != kNo_XformTime; }
|
||||
bool xformOnDecode() const { return fXformTime == kDecodeRow_XformTime; }
|
||||
|
||||
virtual int onGetFrameCount() {
|
||||
return 1;
|
||||
@ -813,9 +798,16 @@ private:
|
||||
|
||||
SkImageInfo fDstInfo;
|
||||
Options fOptions;
|
||||
|
||||
enum XformTime {
|
||||
kNo_XformTime,
|
||||
kPalette_XformTime,
|
||||
kDecodeRow_XformTime,
|
||||
};
|
||||
XformTime fXformTime;
|
||||
XformFormat fDstXformFormat; // Based on fDstInfo.
|
||||
std::unique_ptr<SkColorSpaceXform> fColorXform;
|
||||
bool fXformOnDecode;
|
||||
skcms_ICCProfile fDstProfile;
|
||||
skcms_AlphaFormat fDstXformAlphaFormat;
|
||||
|
||||
// Only meaningful during scanline decodes.
|
||||
int fCurrScanline;
|
||||
@ -823,12 +815,15 @@ private:
|
||||
bool fStartedIncrementalDecode;
|
||||
|
||||
/**
|
||||
* Return whether {srcColor, srcIsOpaque, srcCS} can convert to dst.
|
||||
* Return whether we can convert to dst.
|
||||
*
|
||||
* Will be called for the appropriate frame, prior to initializing the colorXform.
|
||||
*/
|
||||
virtual bool conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
|
||||
bool srcIsOpaque, const SkColorSpace* srcCS) const;
|
||||
bool srcIsOpaque, bool needsColorXform);
|
||||
|
||||
bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha, bool srcIsOpaque);
|
||||
|
||||
/**
|
||||
* Return whether these dimensions are supported as a scale.
|
||||
*
|
||||
|
@ -8,12 +8,25 @@
|
||||
#ifndef SkEncodedInfo_DEFINED
|
||||
#define SkEncodedInfo_DEFINED
|
||||
|
||||
#include "SkData.h"
|
||||
#include "SkImageInfo.h"
|
||||
|
||||
class SkColorSpace;
|
||||
#include "../../third_party/skcms/skcms.h"
|
||||
|
||||
struct SkEncodedInfo {
|
||||
public:
|
||||
class ICCProfile {
|
||||
public:
|
||||
static std::unique_ptr<ICCProfile> Make(sk_sp<SkData>);
|
||||
static std::unique_ptr<ICCProfile> MakeSRGB();
|
||||
static std::unique_ptr<ICCProfile> Make(const skcms_ICCProfile&);
|
||||
|
||||
const skcms_ICCProfile* profile() const { return &fProfile; }
|
||||
private:
|
||||
ICCProfile(const skcms_ICCProfile&, sk_sp<SkData> = nullptr);
|
||||
|
||||
skcms_ICCProfile fProfile;
|
||||
sk_sp<SkData> fData;
|
||||
};
|
||||
|
||||
enum Alpha {
|
||||
kOpaque_Alpha,
|
||||
@ -39,6 +52,20 @@ public:
|
||||
// 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,
|
||||
|
||||
@ -67,7 +94,18 @@ public:
|
||||
kYCCK_Color,
|
||||
};
|
||||
|
||||
static SkEncodedInfo Make(Color color, Alpha alpha, int bitsPerComponent) {
|
||||
static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha,
|
||||
int bitsPerComponent) {
|
||||
return Make(width, height, color, alpha, bitsPerComponent, nullptr);
|
||||
}
|
||||
|
||||
static SkEncodedInfo MakeSRGB(int width, int height, Color color, Alpha alpha,
|
||||
int bitsPerComponent) {
|
||||
return Make(width, height, color, alpha, bitsPerComponent, ICCProfile::MakeSRGB());
|
||||
}
|
||||
|
||||
static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha,
|
||||
int bitsPerComponent, std::unique_ptr<ICCProfile> profile) {
|
||||
SkASSERT(1 == bitsPerComponent ||
|
||||
2 == bitsPerComponent ||
|
||||
4 == bitsPerComponent ||
|
||||
@ -105,29 +143,51 @@ public:
|
||||
SkASSERT(kOpaque_Alpha != alpha);
|
||||
SkASSERT(8 == bitsPerComponent);
|
||||
break;
|
||||
case kXAlpha_Color:
|
||||
SkASSERT(kUnpremul_Alpha == alpha);
|
||||
SkASSERT(8 == bitsPerComponent);
|
||||
break;
|
||||
case k565_Color:
|
||||
SkASSERT(kOpaque_Alpha == alpha);
|
||||
SkASSERT(8 == bitsPerComponent);
|
||||
break;
|
||||
default:
|
||||
SkASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
return SkEncodedInfo(color, alpha, bitsPerComponent);
|
||||
return SkEncodedInfo(width, height, color, alpha, bitsPerComponent, std::move(profile));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an SkImageInfo with Skia color and alpha types that are the
|
||||
* closest possible match to the encoded info.
|
||||
* Returns a recommended SkImageInfo.
|
||||
*
|
||||
* TODO: Leave this up to the client.
|
||||
*/
|
||||
SkImageInfo makeImageInfo(int width, int height, sk_sp<SkColorSpace> colorSpace) const {
|
||||
auto ct = kGray_Color == fColor ? kGray_8_SkColorType :
|
||||
kN32_SkColorType ;
|
||||
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;
|
||||
return SkImageInfo::Make(width, height, ct, alpha, std::move(colorSpace));
|
||||
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));
|
||||
}
|
||||
|
||||
Color color() const { return fColor; }
|
||||
Alpha alpha() const { return fAlpha; }
|
||||
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();
|
||||
}
|
||||
|
||||
uint8_t bitsPerComponent() const { return fBitsPerComponent; }
|
||||
|
||||
@ -135,6 +195,7 @@ public:
|
||||
switch (fColor) {
|
||||
case kGray_Color:
|
||||
return fBitsPerComponent;
|
||||
case kXAlpha_Color:
|
||||
case kGrayAlpha_Color:
|
||||
return 2 * fBitsPerComponent;
|
||||
case kPalette_Color:
|
||||
@ -142,6 +203,7 @@ public:
|
||||
case kRGB_Color:
|
||||
case kBGR_Color:
|
||||
case kYUV_Color:
|
||||
case k565_Color:
|
||||
return 3 * fBitsPerComponent;
|
||||
case kRGBA_Color:
|
||||
case kBGRA_Color:
|
||||
@ -156,17 +218,38 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SkEncodedInfo(const SkEncodedInfo& orig) = delete;
|
||||
SkEncodedInfo& operator=(const SkEncodedInfo&) = delete;
|
||||
|
||||
SkEncodedInfo(Color color, Alpha alpha, uint8_t bitsPerComponent)
|
||||
: fColor(color)
|
||||
SkEncodedInfo(SkEncodedInfo&& orig) = default;
|
||||
SkEncodedInfo& operator=(SkEncodedInfo&&) = default;
|
||||
|
||||
// Explicit copy method, to avoid accidental copying.
|
||||
SkEncodedInfo copy() const {
|
||||
auto copy = SkEncodedInfo::Make(fWidth, fHeight, fColor, fAlpha, fBitsPerComponent);
|
||||
if (fProfile) {
|
||||
copy.fProfile.reset(new ICCProfile(*fProfile.get()));
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
private:
|
||||
SkEncodedInfo(int width, int height, Color color, Alpha alpha,
|
||||
uint8_t bitsPerComponent, std::unique_ptr<ICCProfile> profile)
|
||||
: fWidth(width)
|
||||
, fHeight(height)
|
||||
, fColor(color)
|
||||
, fAlpha(alpha)
|
||||
, fBitsPerComponent(bitsPerComponent)
|
||||
, fProfile(std::move(profile))
|
||||
{}
|
||||
|
||||
Color fColor;
|
||||
Alpha fAlpha;
|
||||
uint8_t fBitsPerComponent;
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
Color fColor;
|
||||
Alpha fAlpha;
|
||||
uint8_t fBitsPerComponent;
|
||||
std::unique_ptr<ICCProfile> fProfile;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
BIN
resources/images/mandrill_cmyk.jpg
Normal file
BIN
resources/images/mandrill_cmyk.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 575 KiB |
BIN
resources/images/purple-displayprofile.png
Normal file
BIN
resources/images/purple-displayprofile.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
BIN
resources/images/wide-gamut.png
Normal file
BIN
resources/images/wide-gamut.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
@ -23,14 +23,14 @@ static bool is_valid_sample_size(int sampleSize) {
|
||||
/**
|
||||
* Loads the gamut as a set of three points (triangle).
|
||||
*/
|
||||
static void load_gamut(SkPoint rgb[], const SkMatrix44& xyz) {
|
||||
static void load_gamut(SkPoint rgb[], const skcms_Matrix3x3& xyz) {
|
||||
// rx = rX / (rX + rY + rZ)
|
||||
// ry = rY / (rX + rY + rZ)
|
||||
// gx, gy, bx, and gy are calulcated similarly.
|
||||
for (int rgbIdx = 0; rgbIdx < 3; rgbIdx++) {
|
||||
float sum = xyz.get(0, rgbIdx) + xyz.get(1, rgbIdx) + xyz.get(2, rgbIdx);
|
||||
rgb[rgbIdx].fX = xyz.get(0, rgbIdx) / sum;
|
||||
rgb[rgbIdx].fY = xyz.get(1, rgbIdx) / sum;
|
||||
float sum = xyz.vals[rgbIdx][0] + xyz.vals[rgbIdx][1] + xyz.vals[rgbIdx][2];
|
||||
rgb[rgbIdx].fX = xyz.vals[rgbIdx][0] / sum;
|
||||
rgb[rgbIdx].fY = xyz.vals[rgbIdx][1] / sum;
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,13 +46,12 @@ static float calculate_area(SkPoint abc[]) {
|
||||
|
||||
static constexpr float kSRGB_D50_GamutArea = 0.084f;
|
||||
|
||||
static bool is_wide_gamut(const SkColorSpace* colorSpace) {
|
||||
static bool is_wide_gamut(const skcms_ICCProfile& profile) {
|
||||
// Determine if the source image has a gamut that is wider than sRGB. If so, we
|
||||
// will use P3 as the output color space to avoid clipping the gamut.
|
||||
const SkMatrix44* toXYZD50 = colorSpace->toXYZD50();
|
||||
if (toXYZD50) {
|
||||
if (profile.has_toXYZD50) {
|
||||
SkPoint rgb[3];
|
||||
load_gamut(rgb, *toXYZD50);
|
||||
load_gamut(rgb, profile.toXYZD50);
|
||||
return calculate_area(rgb) > kSRGB_D50_GamutArea;
|
||||
}
|
||||
|
||||
@ -177,14 +176,14 @@ sk_sp<SkColorSpace> SkAndroidCodec::computeOutputColorSpace(SkColorType outputCo
|
||||
return prefColorSpace;
|
||||
}
|
||||
|
||||
SkColorSpace* encodedSpace = fCodec->getInfo().colorSpace();
|
||||
if (encodedSpace->isNumericalTransferFn(&fn)) {
|
||||
const skcms_ICCProfile* encodedProfile = fCodec->getEncodedInfo().profile();
|
||||
if (auto encodedSpace = SkColorSpace::Make(*encodedProfile)) {
|
||||
// Leave the pixels in the encoded color space. Color space conversion
|
||||
// will be handled after decode time.
|
||||
return sk_ref_sp(encodedSpace);
|
||||
return encodedSpace;
|
||||
}
|
||||
|
||||
if (is_wide_gamut(encodedSpace)) {
|
||||
if (is_wide_gamut(*encodedProfile)) {
|
||||
return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
|
||||
SkColorSpace::kDCIP3_D65_Gamut);
|
||||
}
|
||||
|
@ -9,9 +9,8 @@
|
||||
|
||||
SkBmpBaseCodec::~SkBmpBaseCodec() {}
|
||||
|
||||
SkBmpBaseCodec::SkBmpBaseCodec(int width, int height, const SkEncodedInfo& info,
|
||||
std::unique_ptr<SkStream> stream,
|
||||
SkBmpBaseCodec::SkBmpBaseCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
|
||||
: INHERITED(width, height, info, std::move(stream), bitsPerPixel, rowOrder)
|
||||
: INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
|
||||
, fSrcBuffer(sk_malloc_canfail(this->srcRowBytes()))
|
||||
{}
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
bool didCreateSrcBuffer() const { return fSrcBuffer != nullptr; }
|
||||
|
||||
protected:
|
||||
SkBmpBaseCodec(int width, int height, const SkEncodedInfo& info, std::unique_ptr<SkStream>,
|
||||
SkBmpBaseCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>,
|
||||
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder);
|
||||
|
||||
uint8_t* srcBuffer() { return reinterpret_cast<uint8_t*>(fSrcBuffer.get()); }
|
||||
|
@ -481,8 +481,8 @@ SkCodec::Result SkBmpCodec::ReadHeader(SkStream* stream, bool inIco,
|
||||
SkASSERT(!inIco || nullptr != stream->getMemoryBase());
|
||||
|
||||
// Set the image info and create a codec.
|
||||
const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, bitsPerComponent);
|
||||
codecOut->reset(new SkBmpStandardCodec(width, height, info,
|
||||
auto info = SkEncodedInfo::MakeSRGB(width, height, color, alpha, bitsPerComponent);
|
||||
codecOut->reset(new SkBmpStandardCodec(std::move(info),
|
||||
std::unique_ptr<SkStream>(stream),
|
||||
bitsPerPixel, numColors, bytesPerColor,
|
||||
offset - bytesRead, rowOrder, isOpaque,
|
||||
@ -539,8 +539,8 @@ SkCodec::Result SkBmpCodec::ReadHeader(SkStream* stream, bool inIco,
|
||||
color = SkEncodedInfo::kBGR_Color;
|
||||
alpha = SkEncodedInfo::kOpaque_Alpha;
|
||||
}
|
||||
const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8);
|
||||
codecOut->reset(new SkBmpMaskCodec(width, height, info,
|
||||
auto info = SkEncodedInfo::MakeSRGB(width, height, color, alpha, 8);
|
||||
codecOut->reset(new SkBmpMaskCodec(std::move(info),
|
||||
std::unique_ptr<SkStream>(stream), bitsPerPixel,
|
||||
masks.release(), rowOrder));
|
||||
return static_cast<SkBmpMaskCodec*>(codecOut->get())->didCreateSrcBuffer()
|
||||
@ -570,9 +570,9 @@ SkCodec::Result SkBmpCodec::ReadHeader(SkStream* stream, bool inIco,
|
||||
// is uncommon, but we cannot be certain that an RLE bmp will be
|
||||
// opaque or that we will be able to represent it with a palette.
|
||||
// For that reason, we always indicate that we are kBGRA.
|
||||
const SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kBGRA_Color,
|
||||
SkEncodedInfo::kBinary_Alpha, 8);
|
||||
codecOut->reset(new SkBmpRLECodec(width, height, info,
|
||||
auto info = SkEncodedInfo::MakeSRGB(width, height, SkEncodedInfo::kBGRA_Color,
|
||||
SkEncodedInfo::kBinary_Alpha, 8);
|
||||
codecOut->reset(new SkBmpRLECodec(std::move(info),
|
||||
std::unique_ptr<SkStream>(stream), bitsPerPixel,
|
||||
numColors, bytesPerColor, offset - bytesRead,
|
||||
rowOrder));
|
||||
@ -600,14 +600,12 @@ std::unique_ptr<SkCodec> SkBmpCodec::MakeFromStream(std::unique_ptr<SkStream> st
|
||||
return kSuccess == *result ? std::move(codec) : nullptr;
|
||||
}
|
||||
|
||||
SkBmpCodec::SkBmpCodec(int width, int height, const SkEncodedInfo& info,
|
||||
std::unique_ptr<SkStream> stream,
|
||||
SkBmpCodec::SkBmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
|
||||
: INHERITED(width, height, info, kXformSrcColorFormat, std::move(stream),
|
||||
SkColorSpace::MakeSRGB())
|
||||
: INHERITED(std::move(info), kXformSrcColorFormat, std::move(stream))
|
||||
, fBitsPerPixel(bitsPerPixel)
|
||||
, fRowOrder(rowOrder)
|
||||
, fSrcRowBytes(SkAlign4(compute_row_bytes(width, fBitsPerPixel)))
|
||||
, fSrcRowBytes(SkAlign4(compute_row_bytes(this->getEncodedInfo().width(), fBitsPerPixel)))
|
||||
, fXformBuffer(nullptr)
|
||||
{}
|
||||
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
SkBmpCodec(int width, int height, const SkEncodedInfo& info, std::unique_ptr<SkStream>,
|
||||
SkBmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>,
|
||||
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder);
|
||||
|
||||
SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kBMP; }
|
||||
@ -103,7 +103,7 @@ protected:
|
||||
* than RGBA.
|
||||
*/
|
||||
static constexpr SkColorType kXformSrcColorType = kBGRA_8888_SkColorType;
|
||||
static constexpr auto kXformSrcColorFormat = SkColorSpaceXform::kBGRA_8888_ColorFormat;
|
||||
static constexpr auto kXformSrcColorFormat = skcms_PixelFormat_BGRA_8888;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -12,11 +12,11 @@
|
||||
/*
|
||||
* Creates an instance of the decoder
|
||||
*/
|
||||
SkBmpMaskCodec::SkBmpMaskCodec(int width, int height, const SkEncodedInfo& info,
|
||||
SkBmpMaskCodec::SkBmpMaskCodec(SkEncodedInfo&& info,
|
||||
std::unique_ptr<SkStream> stream,
|
||||
uint16_t bitsPerPixel, SkMasks* masks,
|
||||
SkCodec::SkScanlineOrder rowOrder)
|
||||
: INHERITED(width, height, info, std::move(stream), bitsPerPixel, rowOrder)
|
||||
: INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
|
||||
, fMasks(masks)
|
||||
, fMaskSwizzler(nullptr)
|
||||
{}
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
* @param masks color masks for certain bmp formats
|
||||
* @param rowOrder indicates whether rows are ordered top-down or bottom-up
|
||||
*/
|
||||
SkBmpMaskCodec(int width, int height, const SkEncodedInfo& info, std::unique_ptr<SkStream>,
|
||||
SkBmpMaskCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>,
|
||||
uint16_t bitsPerPixel, SkMasks* masks,
|
||||
SkCodec::SkScanlineOrder rowOrder);
|
||||
|
||||
|
@ -14,12 +14,12 @@
|
||||
* Creates an instance of the decoder
|
||||
* Called only by NewFromStream
|
||||
*/
|
||||
SkBmpRLECodec::SkBmpRLECodec(int width, int height, const SkEncodedInfo& info,
|
||||
SkBmpRLECodec::SkBmpRLECodec(SkEncodedInfo&& info,
|
||||
std::unique_ptr<SkStream> stream,
|
||||
uint16_t bitsPerPixel, uint32_t numColors,
|
||||
uint32_t bytesPerColor, uint32_t offset,
|
||||
SkCodec::SkScanlineOrder rowOrder)
|
||||
: INHERITED(width, height, info, std::move(stream), bitsPerPixel, rowOrder)
|
||||
: INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
|
||||
, fColorTable(nullptr)
|
||||
, fNumColors(numColors)
|
||||
, fBytesPerColor(bytesPerColor)
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
* headers
|
||||
* @param rowOrder indicates whether rows are ordered top-down or bottom-up
|
||||
*/
|
||||
SkBmpRLECodec(int width, int height, const SkEncodedInfo& info, std::unique_ptr<SkStream>,
|
||||
SkBmpRLECodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>,
|
||||
uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor,
|
||||
uint32_t offset, SkCodec::SkScanlineOrder rowOrder);
|
||||
|
||||
|
@ -14,12 +14,12 @@
|
||||
* Creates an instance of the decoder
|
||||
* Called only by NewFromStream
|
||||
*/
|
||||
SkBmpStandardCodec::SkBmpStandardCodec(int width, int height, const SkEncodedInfo& info,
|
||||
std::unique_ptr<SkStream> stream, uint16_t bitsPerPixel,
|
||||
uint32_t numColors, uint32_t bytesPerColor, uint32_t offset,
|
||||
SkBmpStandardCodec::SkBmpStandardCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||
uint16_t bitsPerPixel, uint32_t numColors,
|
||||
uint32_t bytesPerColor, uint32_t offset,
|
||||
SkCodec::SkScanlineOrder rowOrder,
|
||||
bool isOpaque, bool inIco)
|
||||
: INHERITED(width, height, info, std::move(stream), bitsPerPixel, rowOrder)
|
||||
: INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
|
||||
, fColorTable(nullptr)
|
||||
, fNumColors(numColors)
|
||||
, fBytesPerColor(bytesPerColor)
|
||||
@ -146,20 +146,33 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo,
|
||||
return true;
|
||||
}
|
||||
|
||||
static SkEncodedInfo make_info(SkEncodedInfo::Color color,
|
||||
SkEncodedInfo::Alpha alpha, int bitsPerPixel) {
|
||||
// This is just used for the swizzler, which does not need the width or height.
|
||||
return SkEncodedInfo::Make(0, 0, color, alpha, bitsPerPixel);
|
||||
}
|
||||
|
||||
SkEncodedInfo SkBmpStandardCodec::swizzlerInfo() const {
|
||||
const auto& info = this->getEncodedInfo();
|
||||
if (fInIco) {
|
||||
if (this->bitsPerPixel() <= 8) {
|
||||
return make_info(SkEncodedInfo::kPalette_Color,
|
||||
info.alpha(), this->bitsPerPixel());
|
||||
}
|
||||
if (this->bitsPerPixel() == 24) {
|
||||
return make_info(SkEncodedInfo::kBGR_Color,
|
||||
SkEncodedInfo::kOpaque_Alpha, 8);
|
||||
}
|
||||
}
|
||||
|
||||
return make_info(info.color(), info.alpha(), info.bitsPerComponent());
|
||||
}
|
||||
|
||||
void SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) {
|
||||
// In the case of bmp-in-icos, we will report BGRA to the client,
|
||||
// since we may be required to apply an alpha mask after the decode.
|
||||
// However, the swizzler needs to know the actual format of the bmp.
|
||||
SkEncodedInfo encodedInfo = this->getEncodedInfo();
|
||||
if (fInIco) {
|
||||
if (this->bitsPerPixel() <= 8) {
|
||||
encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color,
|
||||
encodedInfo.alpha(), this->bitsPerPixel());
|
||||
} else if (this->bitsPerPixel() == 24) {
|
||||
encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kBGR_Color,
|
||||
SkEncodedInfo::kOpaque_Alpha, 8);
|
||||
}
|
||||
}
|
||||
SkEncodedInfo encodedInfo = this->swizzlerInfo();
|
||||
|
||||
// Get a pointer to the color table if it exists
|
||||
const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
|
||||
|
@ -39,9 +39,9 @@ public:
|
||||
* the icp mask, if there is one)
|
||||
* @param inIco indicates if the bmp is embedded in an ico file
|
||||
*/
|
||||
SkBmpStandardCodec(int width, int height, const SkEncodedInfo& info,
|
||||
std::unique_ptr<SkStream> stream, uint16_t bitsPerPixel, uint32_t numColors,
|
||||
uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder,
|
||||
SkBmpStandardCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||
uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor,
|
||||
uint32_t offset, SkCodec::SkScanlineOrder rowOrder,
|
||||
bool isOpaque, bool inIco);
|
||||
|
||||
protected:
|
||||
@ -63,12 +63,8 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Creates the color table
|
||||
*/
|
||||
bool createColorTable(SkColorType colorType, SkAlphaType alphaType);
|
||||
|
||||
SkEncodedInfo swizzlerInfo() const;
|
||||
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts);
|
||||
|
||||
int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "SkCodec.h"
|
||||
#include "SkCodecPriv.h"
|
||||
#include "SkColorSpace.h"
|
||||
#include "SkColorSpaceXformPriv.h"
|
||||
#include "SkData.h"
|
||||
#include "SkFrameHolder.h"
|
||||
#include "SkGifCodec.h"
|
||||
@ -126,26 +125,10 @@ std::unique_ptr<SkCodec> SkCodec::MakeFromData(sk_sp<SkData> data, SkPngChunkRea
|
||||
return MakeFromStream(SkMemoryStream::Make(std::move(data)), nullptr, reader);
|
||||
}
|
||||
|
||||
SkCodec::SkCodec(int width, int height, const SkEncodedInfo& info,
|
||||
XformFormat srcFormat, std::unique_ptr<SkStream> stream,
|
||||
sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin)
|
||||
: fEncodedInfo(info)
|
||||
, fSrcInfo(info.makeImageInfo(width, height, std::move(colorSpace)))
|
||||
, fSrcXformFormat(srcFormat)
|
||||
, fStream(std::move(stream))
|
||||
, fNeedsRewind(false)
|
||||
, fOrigin(origin)
|
||||
, fDstInfo()
|
||||
, fOptions()
|
||||
, fCurrScanline(-1)
|
||||
, fStartedIncrementalDecode(false)
|
||||
{}
|
||||
|
||||
SkCodec::SkCodec(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
|
||||
XformFormat srcFormat, std::unique_ptr<SkStream> stream,
|
||||
SkEncodedOrigin origin)
|
||||
: fEncodedInfo(info)
|
||||
, fSrcInfo(imageInfo)
|
||||
SkCodec::SkCodec(SkEncodedInfo&& info, XformFormat srcFormat, std::unique_ptr<SkStream> stream,
|
||||
SkEncodedOrigin origin)
|
||||
: fEncodedInfo(std::move(info))
|
||||
, fSrcInfo(fEncodedInfo.makeImageInfo())
|
||||
, fSrcXformFormat(srcFormat)
|
||||
, fStream(std::move(stream))
|
||||
, fNeedsRewind(false)
|
||||
@ -159,7 +142,7 @@ SkCodec::SkCodec(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
|
||||
SkCodec::~SkCodec() {}
|
||||
|
||||
bool SkCodec::conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
|
||||
bool srcIsOpaque, const SkColorSpace* srcCS) const {
|
||||
bool srcIsOpaque, bool needsColorXform) {
|
||||
if (!valid_alpha(dst.alphaType(), srcIsOpaque)) {
|
||||
return false;
|
||||
}
|
||||
@ -173,8 +156,8 @@ bool SkCodec::conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
|
||||
case kRGB_565_SkColorType:
|
||||
return srcIsOpaque;
|
||||
case kGray_8_SkColorType:
|
||||
return kGray_8_SkColorType == srcColor && srcIsOpaque &&
|
||||
!needs_color_xform(dst, srcCS);
|
||||
SkASSERT(!needsColorXform);
|
||||
return kGray_8_SkColorType == srcColor && srcIsOpaque;
|
||||
case kAlpha_8_SkColorType:
|
||||
// conceptually we can convert anything into alpha_8, but we haven't actually coded
|
||||
// all of those other conversions yet, so only return true for the case we have codec.
|
||||
@ -182,7 +165,6 @@ bool SkCodec::conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool SkCodec::rewindIfNeeded() {
|
||||
@ -245,13 +227,8 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels,
|
||||
const Options& options) {
|
||||
const int index = options.fFrameIndex;
|
||||
if (0 == index) {
|
||||
if (!this->conversionSupported(info, fSrcInfo.colorType(), fEncodedInfo.opaque(),
|
||||
fSrcInfo.colorSpace())
|
||||
|| !this->initializeColorXform(info, fEncodedInfo.alpha()))
|
||||
{
|
||||
return kInvalidConversion;
|
||||
}
|
||||
return kSuccess;
|
||||
return this->initializeColorXform(info, fEncodedInfo.alpha(), fEncodedInfo.opaque())
|
||||
? kSuccess : kInvalidConversion;
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
@ -274,11 +251,6 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels,
|
||||
const auto* frame = frameHolder->getFrame(index);
|
||||
SkASSERT(frame);
|
||||
|
||||
if (!this->conversionSupported(info, fSrcInfo.colorType(), !frame->hasAlpha(),
|
||||
fSrcInfo.colorSpace())) {
|
||||
return kInvalidConversion;
|
||||
}
|
||||
|
||||
const int requiredFrame = frame->getRequiredFrame();
|
||||
if (requiredFrame != kNoFrame) {
|
||||
if (options.fPriorFrame != kNoFrame) {
|
||||
@ -324,7 +296,8 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels,
|
||||
}
|
||||
}
|
||||
|
||||
return this->initializeColorXform(info, frame->reportedAlpha()) ? kSuccess : kInvalidConversion;
|
||||
return this->initializeColorXform(info, frame->reportedAlpha(), !frame->hasAlpha())
|
||||
? kSuccess : kInvalidConversion;
|
||||
}
|
||||
|
||||
SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
|
||||
@ -612,63 +585,80 @@ void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row
|
||||
}
|
||||
}
|
||||
|
||||
static inline SkColorSpaceXform::ColorFormat select_xform_format_ct(SkColorType colorType) {
|
||||
static inline bool select_xform_format(SkColorType colorType, bool forColorTable,
|
||||
skcms_PixelFormat* outFormat) {
|
||||
SkASSERT(outFormat);
|
||||
|
||||
switch (colorType) {
|
||||
case kRGBA_8888_SkColorType:
|
||||
return SkColorSpaceXform::kRGBA_8888_ColorFormat;
|
||||
*outFormat = skcms_PixelFormat_RGBA_8888;
|
||||
break;
|
||||
case kBGRA_8888_SkColorType:
|
||||
return SkColorSpaceXform::kBGRA_8888_ColorFormat;
|
||||
*outFormat = skcms_PixelFormat_BGRA_8888;
|
||||
break;
|
||||
case kRGB_565_SkColorType:
|
||||
if (forColorTable) {
|
||||
#ifdef SK_PMCOLOR_IS_RGBA
|
||||
return SkColorSpaceXform::kRGBA_8888_ColorFormat;
|
||||
*outFormat = skcms_PixelFormat_RGBA_8888;
|
||||
#else
|
||||
return SkColorSpaceXform::kBGRA_8888_ColorFormat;
|
||||
*outFormat = skcms_PixelFormat_BGRA_8888;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
*outFormat = skcms_PixelFormat_BGR_565;
|
||||
break;
|
||||
case kRGBA_F16_SkColorType:
|
||||
*outFormat = skcms_PixelFormat_RGBA_hhhh;
|
||||
break;
|
||||
default:
|
||||
SkASSERT(false);
|
||||
return SkColorSpaceXform::kRGBA_8888_ColorFormat;
|
||||
}
|
||||
}
|
||||
|
||||
bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha encodedAlpha) {
|
||||
fColorXform = nullptr;
|
||||
fXformOnDecode = false;
|
||||
if (!this->usesColorXform()) {
|
||||
return true;
|
||||
}
|
||||
// FIXME: In SkWebpCodec, if a frame is blending with a prior frame, we don't need
|
||||
// a colorXform to do a color correct premul, since the blend step will handle
|
||||
// premultiplication. But there is no way to know whether we need to blend from
|
||||
// inside this call.
|
||||
if (needs_color_xform(dstInfo, fSrcInfo.colorSpace())) {
|
||||
fColorXform = SkMakeColorSpaceXform(fSrcInfo.colorSpace(), dstInfo.colorSpace());
|
||||
if (!fColorXform) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We will apply the color xform when reading the color table unless F16 is requested.
|
||||
fXformOnDecode = SkEncodedInfo::kPalette_Color != fEncodedInfo.color()
|
||||
|| kRGBA_F16_SkColorType == dstInfo.colorType();
|
||||
if (fXformOnDecode) {
|
||||
fDstXformFormat = select_xform_format(dstInfo.colorType());
|
||||
} else {
|
||||
fDstXformFormat = select_xform_format_ct(dstInfo.colorType());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkCodec::applyColorXform(void* dst, const void* src, int count, SkAlphaType at) const {
|
||||
SkASSERT(fColorXform);
|
||||
SkAssertResult(fColorXform->apply(fDstXformFormat, dst,
|
||||
fSrcXformFormat, src,
|
||||
count, at));
|
||||
bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha encodedAlpha,
|
||||
bool srcIsOpaque) {
|
||||
fXformTime = kNo_XformTime;
|
||||
bool needsColorXform = false;
|
||||
if (this->usesColorXform() && dstInfo.colorSpace()) {
|
||||
dstInfo.colorSpace()->toProfile(&fDstProfile);
|
||||
if (kRGBA_F16_SkColorType == dstInfo.colorType()
|
||||
|| !skcms_ApproximatelyEqualProfiles(fEncodedInfo.profile(), &fDstProfile) ) {
|
||||
needsColorXform = true;
|
||||
if (kGray_8_SkColorType == dstInfo.colorType()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->conversionSupported(dstInfo, fSrcInfo.colorType(), srcIsOpaque, needsColorXform)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (needsColorXform) {
|
||||
fXformTime = SkEncodedInfo::kPalette_Color != fEncodedInfo.color()
|
||||
|| kRGBA_F16_SkColorType == dstInfo.colorType()
|
||||
? kDecodeRow_XformTime : kPalette_XformTime;
|
||||
if (!select_xform_format(dstInfo.colorType(), fXformTime == kPalette_XformTime,
|
||||
&fDstXformFormat)) {
|
||||
return false;
|
||||
}
|
||||
if (encodedAlpha == SkEncodedInfo::kUnpremul_Alpha
|
||||
&& dstInfo.alphaType() == kPremul_SkAlphaType) {
|
||||
fDstXformAlphaFormat = skcms_AlphaFormat_PremulAsEncoded;
|
||||
} else {
|
||||
fDstXformAlphaFormat = skcms_AlphaFormat_Unpremul;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkCodec::applyColorXform(void* dst, const void* src, int count) const {
|
||||
auto alphaType = select_xform_alpha(fDstInfo.alphaType(), fSrcInfo.alphaType());
|
||||
this->applyColorXform(dst, src, count, alphaType);
|
||||
const auto* srcProfile = fEncodedInfo.profile();
|
||||
SkASSERT(srcProfile);
|
||||
SkAssertResult(skcms_Transform(src, fSrcXformFormat, skcms_AlphaFormat_Unpremul, srcProfile,
|
||||
dst, fDstXformFormat, fDstXformAlphaFormat, &fDstProfile,
|
||||
count));
|
||||
}
|
||||
|
||||
std::vector<SkCodec::FrameInfo> SkCodec::getFrameInfo() {
|
||||
|
@ -9,8 +9,6 @@
|
||||
#define SkCodecPriv_DEFINED
|
||||
|
||||
#include "SkColorData.h"
|
||||
#include "SkColorSpaceXform.h"
|
||||
#include "SkColorSpaceXformPriv.h"
|
||||
#include "SkColorTable.h"
|
||||
#include "SkEncodedInfo.h"
|
||||
#include "SkEncodedOrigin.h"
|
||||
@ -243,30 +241,6 @@ static inline PackColorProc choose_pack_color_proc(bool isPremul, SkColorType co
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool needs_premul(SkAlphaType dstAT, SkEncodedInfo::Alpha encodedAlpha) {
|
||||
return kPremul_SkAlphaType == dstAT && SkEncodedInfo::kUnpremul_Alpha == encodedAlpha;
|
||||
}
|
||||
|
||||
static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkColorSpace* srcCS) {
|
||||
// We never perform a color xform in legacy mode.
|
||||
if (!dstInfo.colorSpace()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// None of the codecs we have output F16 natively, so if we're trying to decode to F16,
|
||||
// we'll have to use SkColorSpaceXform to get there.
|
||||
bool isF16 = kRGBA_F16_SkColorType == dstInfo.colorType();
|
||||
|
||||
// Need a color xform when dst space does not match the src.
|
||||
bool srcDstNotEqual = !SkColorSpace::Equals(srcCS, dstInfo.colorSpace());
|
||||
|
||||
return isF16 || srcDstNotEqual;
|
||||
}
|
||||
|
||||
static inline SkAlphaType select_xform_alpha(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) {
|
||||
return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlphaType;
|
||||
}
|
||||
|
||||
bool is_orientation_marker(const uint8_t* data, size_t data_length, SkEncodedOrigin* orientation);
|
||||
|
||||
#endif // SkCodecPriv_DEFINED
|
||||
|
@ -5,4 +5,28 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
// Dummy file to assist in landing https://skia-review.googlesource.com/c/skia/+/136062
|
||||
#include "SkEncodedInfo.h"
|
||||
|
||||
std::unique_ptr<SkEncodedInfo::ICCProfile> SkEncodedInfo::ICCProfile::Make(sk_sp<SkData> data) {
|
||||
if (data) {
|
||||
skcms_ICCProfile profile;
|
||||
if (skcms_Parse(data->data(), data->size(), &profile)) {
|
||||
return std::unique_ptr<ICCProfile>(new ICCProfile(profile, std::move(data)));
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<SkEncodedInfo::ICCProfile> SkEncodedInfo::ICCProfile::MakeSRGB() {
|
||||
return std::unique_ptr<ICCProfile>(new ICCProfile(*skcms_sRGB_profile()));
|
||||
}
|
||||
|
||||
std::unique_ptr<SkEncodedInfo::ICCProfile> SkEncodedInfo::ICCProfile::Make(
|
||||
const skcms_ICCProfile& profile) {
|
||||
return std::unique_ptr<ICCProfile>(new ICCProfile(profile));
|
||||
}
|
||||
|
||||
SkEncodedInfo::ICCProfile::ICCProfile(const skcms_ICCProfile& profile, sk_sp<SkData> data)
|
||||
: fProfile(profile)
|
||||
, fData(std::move(data))
|
||||
{}
|
||||
|
@ -91,18 +91,9 @@ std::unique_ptr<SkCodec> SkGifCodec::MakeFromStream(std::unique_ptr<SkStream> st
|
||||
// Use kPalette since Gifs are encoded with a color table.
|
||||
// FIXME: Gifs can actually be encoded with 4-bits per pixel. Using 8 works, but we could skip
|
||||
// expanding to 8 bits and take advantage of the SkSwizzler to work from 4.
|
||||
const auto encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8);
|
||||
|
||||
// The choice of unpremul versus premul is arbitrary, since all colors are either fully
|
||||
// opaque or fully transparent (i.e. kBinary), but we stored the transparent colors as all
|
||||
// zeroes, which is arguably premultiplied.
|
||||
const auto alphaType = reader->firstFrameHasAlpha() ? kUnpremul_SkAlphaType
|
||||
: kOpaque_SkAlphaType;
|
||||
|
||||
const auto imageInfo = SkImageInfo::Make(reader->screenWidth(), reader->screenHeight(),
|
||||
kN32_SkColorType, alphaType,
|
||||
SkColorSpace::MakeSRGB());
|
||||
return std::unique_ptr<SkCodec>(new SkGifCodec(encodedInfo, imageInfo, reader.release()));
|
||||
auto encodedInfo = SkEncodedInfo::MakeSRGB(reader->screenWidth(), reader->screenHeight(),
|
||||
SkEncodedInfo::kPalette_Color, alpha, 8);
|
||||
return std::unique_ptr<SkCodec>(new SkGifCodec(std::move(encodedInfo), reader.release()));
|
||||
}
|
||||
|
||||
bool SkGifCodec::onRewind() {
|
||||
@ -110,9 +101,8 @@ bool SkGifCodec::onRewind() {
|
||||
return true;
|
||||
}
|
||||
|
||||
SkGifCodec::SkGifCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
|
||||
SkGifImageReader* reader)
|
||||
: INHERITED(encodedInfo, imageInfo, SkColorSpaceXform::kRGBA_8888_ColorFormat, nullptr)
|
||||
SkGifCodec::SkGifCodec(SkEncodedInfo&& encodedInfo, SkGifImageReader* reader)
|
||||
: INHERITED(std::move(encodedInfo), skcms_PixelFormat_RGBA_8888, nullptr)
|
||||
, fReader(reader)
|
||||
, fTmpBuffer(nullptr)
|
||||
, fSwizzler(nullptr)
|
||||
@ -157,7 +147,6 @@ int SkGifCodec::onGetRepetitionCount() {
|
||||
}
|
||||
|
||||
static constexpr SkColorType kXformSrcColorType = kRGBA_8888_SkColorType;
|
||||
static constexpr SkAlphaType kXformAlphaType = kUnpremul_SkAlphaType;
|
||||
|
||||
void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, int frameIndex) {
|
||||
SkColorType colorTableColorType = dstInfo.colorType();
|
||||
@ -173,8 +162,8 @@ void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, int frameIndex
|
||||
fCurrColorTable.reset(new SkColorTable(&color, 1));
|
||||
} else if (this->colorXform() && !this->xformOnDecode()) {
|
||||
SkPMColor dstColors[256];
|
||||
this->applyColorXform(dstColors, currColorTable->readColors(), currColorTable->count(),
|
||||
kXformAlphaType);
|
||||
this->applyColorXform(dstColors, currColorTable->readColors(),
|
||||
currColorTable->count());
|
||||
fCurrColorTable.reset(new SkColorTable(dstColors, currColorTable->count()));
|
||||
} else {
|
||||
fCurrColorTable = std::move(currColorTable);
|
||||
@ -402,7 +391,7 @@ void SkGifCodec::applyXformRow(const SkImageInfo& dstInfo, void* dst, const uint
|
||||
fSwizzler->swizzle(fXformBuffer.get(), src);
|
||||
|
||||
const int xformWidth = get_scaled_dimension(dstInfo.width(), fSwizzler->sampleX());
|
||||
this->applyColorXform(dst, fXformBuffer.get(), xformWidth, kXformAlphaType);
|
||||
this->applyColorXform(dst, fXformBuffer.get(), xformWidth);
|
||||
} else {
|
||||
fSwizzler->swizzle(dst, src);
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ private:
|
||||
* Called only by NewFromStream
|
||||
* Takes ownership of the SkGifImageReader
|
||||
*/
|
||||
SkGifCodec(const SkEncodedInfo&, const SkImageInfo&, SkGifImageReader*);
|
||||
SkGifCodec(SkEncodedInfo&&, SkGifImageReader*);
|
||||
|
||||
std::unique_ptr<SkGifImageReader> fReader;
|
||||
std::unique_ptr<uint8_t[]> fTmpBuffer;
|
||||
|
@ -133,40 +133,37 @@ std::unique_ptr<SkCodec> SkHeifCodec::MakeFromStream(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkEncodedInfo info = SkEncodedInfo::Make(
|
||||
SkEncodedInfo::kYUV_Color, SkEncodedInfo::kOpaque_Alpha, 8);
|
||||
std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
|
||||
if ((frameInfo.mIccSize > 0) && (frameInfo.mIccData != nullptr)) {
|
||||
// FIXME: Would it be possible to use MakeWithoutCopy?
|
||||
auto icc = SkData::MakeWithCopy(frameInfo.mIccData.get(), frameInfo.mIccSize);
|
||||
profile = SkEncodedInfo::ICCProfile::Make(std::move(icc));
|
||||
}
|
||||
if (!profile || profile->profile()->data_color_space != skcms_Signature_RGB) {
|
||||
profile = SkEncodedInfo::ICCProfile::MakeSRGB();
|
||||
}
|
||||
|
||||
SkEncodedInfo info = SkEncodedInfo::Make(frameInfo.mWidth, frameInfo.mHeight,
|
||||
SkEncodedInfo::kYUV_Color, SkEncodedInfo::kOpaque_Alpha, 8, std::move(profile));
|
||||
SkEncodedOrigin orientation = get_orientation(frameInfo);
|
||||
|
||||
sk_sp<SkColorSpace> colorSpace = nullptr;
|
||||
if ((frameInfo.mIccSize > 0) && (frameInfo.mIccData != nullptr)) {
|
||||
colorSpace = SkColorSpace::MakeICC(frameInfo.mIccData.get(),
|
||||
frameInfo.mIccSize);
|
||||
}
|
||||
if (!colorSpace || colorSpace->type() != SkColorSpace::kRGB_Type) {
|
||||
colorSpace = SkColorSpace::MakeSRGB();
|
||||
}
|
||||
|
||||
*result = kSuccess;
|
||||
return std::unique_ptr<SkCodec>(new SkHeifCodec(frameInfo.mWidth, frameInfo.mHeight,
|
||||
info, heifDecoder.release(), std::move(colorSpace), orientation));
|
||||
return std::unique_ptr<SkCodec>(new SkHeifCodec(std::move(info), heifDecoder.release(),
|
||||
orientation));
|
||||
}
|
||||
|
||||
SkHeifCodec::SkHeifCodec(int width, int height, const SkEncodedInfo& info,
|
||||
HeifDecoder* heifDecoder, sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin)
|
||||
: INHERITED(width, height, info, SkColorSpaceXform::kRGBA_8888_ColorFormat,
|
||||
nullptr, std::move(colorSpace), origin)
|
||||
SkHeifCodec::SkHeifCodec(SkEncodedInfo&& info, HeifDecoder* heifDecoder, SkEncodedOrigin origin)
|
||||
: INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, nullptr, origin)
|
||||
, fHeifDecoder(heifDecoder)
|
||||
, fSwizzleSrcRow(nullptr)
|
||||
, fColorXformSrcRow(nullptr)
|
||||
{}
|
||||
|
||||
/*
|
||||
* Checks if the conversion between the input image and the requested output
|
||||
* image has been implemented
|
||||
* Sets the output color format
|
||||
*/
|
||||
bool SkHeifCodec::setOutputColorFormat(const SkImageInfo& dstInfo) {
|
||||
|
||||
bool SkHeifCodec::conversionSupported(const SkImageInfo& dstInfo, SkColorType /*srcColorType*/,
|
||||
bool srcIsOpaque, bool needsColorXform) {
|
||||
SkASSERT(srcIsOpaque);
|
||||
|
||||
if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
|
||||
return false;
|
||||
}
|
||||
@ -184,14 +181,14 @@ bool SkHeifCodec::setOutputColorFormat(const SkImageInfo& dstInfo) {
|
||||
return fHeifDecoder->setOutputColor(kHeifColorFormat_BGRA_8888);
|
||||
|
||||
case kRGB_565_SkColorType:
|
||||
if (this->colorXform()) {
|
||||
if (needsColorXform) {
|
||||
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
|
||||
} else {
|
||||
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGB565);
|
||||
}
|
||||
|
||||
case kRGBA_F16_SkColorType:
|
||||
SkASSERT(this->colorXform());
|
||||
SkASSERT(needsColorXform);
|
||||
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
|
||||
|
||||
default:
|
||||
@ -240,7 +237,7 @@ int SkHeifCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes
|
||||
}
|
||||
|
||||
if (this->colorXform()) {
|
||||
this->applyColorXform(dst, swizzleDst, dstWidth, kOpaque_SkAlphaType);
|
||||
this->applyColorXform(dst, swizzleDst, dstWidth);
|
||||
dst = SkTAddOffset<void>(dst, rowBytes);
|
||||
}
|
||||
|
||||
@ -265,11 +262,6 @@ SkCodec::Result SkHeifCodec::onGetPixels(const SkImageInfo& dstInfo,
|
||||
return kUnimplemented;
|
||||
}
|
||||
|
||||
// Check if we can decode to the requested destination and set the output color space
|
||||
if (!this->setOutputColorFormat(dstInfo)) {
|
||||
return kInvalidConversion;
|
||||
}
|
||||
|
||||
if (!fHeifDecoder->decode(&fFrameInfo)) {
|
||||
return kInvalidInput;
|
||||
}
|
||||
@ -313,15 +305,13 @@ void SkHeifCodec::allocateStorage(const SkImageInfo& dstInfo) {
|
||||
|
||||
void SkHeifCodec::initializeSwizzler(
|
||||
const SkImageInfo& dstInfo, const Options& options) {
|
||||
SkEncodedInfo swizzlerInfo = this->getEncodedInfo();
|
||||
|
||||
SkImageInfo swizzlerDstInfo = dstInfo;
|
||||
if (this->colorXform()) {
|
||||
// The color xform will be expecting RGBA 8888 input.
|
||||
swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType);
|
||||
}
|
||||
|
||||
fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr,
|
||||
fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), nullptr,
|
||||
swizzlerDstInfo, options, nullptr, true));
|
||||
SkASSERT(fSwizzler);
|
||||
}
|
||||
@ -339,11 +329,6 @@ SkSampler* SkHeifCodec::getSampler(bool createIfNecessary) {
|
||||
|
||||
SkCodec::Result SkHeifCodec::onStartScanlineDecode(
|
||||
const SkImageInfo& dstInfo, const Options& options) {
|
||||
// Check if we can decode to the requested destination and set the output color space
|
||||
if (!this->setOutputColorFormat(dstInfo)) {
|
||||
return kInvalidConversion;
|
||||
}
|
||||
|
||||
// TODO: For now, just decode the whole thing even when there is a subset.
|
||||
// If the heif image has tiles, we could potentially do this much faster,
|
||||
// but the tile configuration needs to be retrieved from the metadata.
|
||||
|
@ -9,8 +9,6 @@
|
||||
#define SkHeifCodec_DEFINED
|
||||
|
||||
#include "SkCodec.h"
|
||||
#include "SkColorSpace.h"
|
||||
#include "SkColorSpaceXform.h"
|
||||
#include "SkEncodedOrigin.h"
|
||||
#include "SkImageInfo.h"
|
||||
#include "SkSwizzler.h"
|
||||
@ -43,27 +41,14 @@ protected:
|
||||
return SkEncodedImageFormat::kHEIF;
|
||||
}
|
||||
|
||||
bool conversionSupported(const SkImageInfo&, SkColorType, bool,
|
||||
const SkColorSpace*) const override {
|
||||
// This class checks for conversion after creating colorXform.
|
||||
return true;
|
||||
}
|
||||
bool conversionSupported(const SkImageInfo&, SkColorType, bool, bool) override;
|
||||
|
||||
private:
|
||||
/*
|
||||
* Creates an instance of the decoder
|
||||
* Called only by NewFromStream
|
||||
*/
|
||||
SkHeifCodec(int width, int height, const SkEncodedInfo&,
|
||||
HeifDecoder*, sk_sp<SkColorSpace>, SkEncodedOrigin);
|
||||
|
||||
/*
|
||||
* Checks if the conversion between the input image and the requested output
|
||||
* image has been implemented.
|
||||
*
|
||||
* Sets the output color format.
|
||||
*/
|
||||
bool setOutputColorFormat(const SkImageInfo& dst);
|
||||
SkHeifCodec(SkEncodedInfo&&, HeifDecoder*, SkEncodedOrigin);
|
||||
|
||||
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options);
|
||||
void allocateStorage(const SkImageInfo& dstInfo);
|
||||
|
@ -179,29 +179,19 @@ std::unique_ptr<SkCodec> SkIcoCodec::MakeFromStream(std::unique_ptr<SkStream> st
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
int width = codecs->operator[](maxIndex)->getInfo().width();
|
||||
int height = codecs->operator[](maxIndex)->getInfo().height();
|
||||
SkEncodedInfo info = codecs->operator[](maxIndex)->getEncodedInfo();
|
||||
SkColorSpace* colorSpace = codecs->operator[](maxIndex)->getInfo().colorSpace();
|
||||
|
||||
auto maxInfo = codecs->operator[](maxIndex)->getEncodedInfo().copy();
|
||||
|
||||
*result = kSuccess;
|
||||
// The original stream is no longer needed, because the embedded codecs own their
|
||||
// own streams.
|
||||
return std::unique_ptr<SkCodec>(new SkIcoCodec(width, height, info, codecs.release(),
|
||||
sk_ref_sp(colorSpace)));
|
||||
return std::unique_ptr<SkCodec>(new SkIcoCodec(std::move(maxInfo), codecs.release()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates an instance of the decoder
|
||||
* Called only by NewFromStream
|
||||
*/
|
||||
SkIcoCodec::SkIcoCodec(int width, int height, const SkEncodedInfo& info,
|
||||
SkTArray<std::unique_ptr<SkCodec>, true>* codecs,
|
||||
sk_sp<SkColorSpace> colorSpace)
|
||||
// The source SkColorSpaceXform::ColorFormat will not be used. The embedded
|
||||
SkIcoCodec::SkIcoCodec(SkEncodedInfo&& info, SkTArray<std::unique_ptr<SkCodec>, true>* codecs)
|
||||
// The source skcms_PixelFormat will not be used. The embedded
|
||||
// codec's will be used instead.
|
||||
: INHERITED(width, height, info, SkColorSpaceXform::ColorFormat(), nullptr,
|
||||
std::move(colorSpace))
|
||||
: INHERITED(std::move(info), skcms_PixelFormat(), nullptr)
|
||||
, fEmbeddedCodecs(codecs)
|
||||
, fCurrCodec(nullptr)
|
||||
{}
|
||||
|
@ -48,8 +48,7 @@ protected:
|
||||
|
||||
SkScanlineOrder onGetScanlineOrder() const override;
|
||||
|
||||
bool conversionSupported(const SkImageInfo&, SkColorType, bool,
|
||||
const SkColorSpace*) const override {
|
||||
bool conversionSupported(const SkImageInfo&, SkColorType, bool, bool) override {
|
||||
// This will be checked by the embedded codec.
|
||||
return true;
|
||||
}
|
||||
@ -87,8 +86,7 @@ private:
|
||||
* Constructor called by NewFromStream
|
||||
* @param embeddedCodecs codecs for the embedded images, takes ownership
|
||||
*/
|
||||
SkIcoCodec(int width, int height, const SkEncodedInfo& info,
|
||||
SkTArray<std::unique_ptr<SkCodec>, true>* embeddedCodecs, sk_sp<SkColorSpace> colorSpace);
|
||||
SkIcoCodec(SkEncodedInfo&& info, SkTArray<std::unique_ptr<SkCodec>, true>* embeddedCodecs);
|
||||
|
||||
std::unique_ptr<SkTArray<std::unique_ptr<SkCodec>, true>> fEmbeddedCodecs;
|
||||
|
||||
|
@ -131,7 +131,8 @@ static bool is_icc_marker(jpeg_marker_struct* marker) {
|
||||
* (1) Discover all ICC profile markers and verify that they are numbered properly.
|
||||
* (2) Copy the data from each marker into a contiguous ICC profile.
|
||||
*/
|
||||
static sk_sp<SkColorSpace> read_color_space(jpeg_decompress_struct* dinfo) {
|
||||
static std::unique_ptr<SkEncodedInfo::ICCProfile> read_color_profile(jpeg_decompress_struct* dinfo)
|
||||
{
|
||||
// Note that 256 will be enough storage space since each markerIndex is stored in 8-bits.
|
||||
jpeg_marker_struct* markerSequence[256];
|
||||
memset(markerSequence, 0, sizeof(markerSequence));
|
||||
@ -191,11 +192,12 @@ static sk_sp<SkColorSpace> read_color_space(jpeg_decompress_struct* dinfo) {
|
||||
dst = SkTAddOffset<void>(dst, bytes);
|
||||
}
|
||||
|
||||
return SkColorSpace::MakeICC(iccData->data(), iccData->size());
|
||||
return SkEncodedInfo::ICCProfile::Make(std::move(iccData));
|
||||
}
|
||||
|
||||
SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
|
||||
JpegDecoderMgr** decoderMgrOut, sk_sp<SkColorSpace> defaultColorSpace) {
|
||||
JpegDecoderMgr** decoderMgrOut,
|
||||
std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) {
|
||||
|
||||
// Create a JpegDecoderMgr to own all of the decompress information
|
||||
std::unique_ptr<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
|
||||
@ -208,17 +210,18 @@ SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
|
||||
|
||||
// Initialize the decompress info and the source manager
|
||||
decoderMgr->init();
|
||||
auto* dinfo = decoderMgr->dinfo();
|
||||
|
||||
// Instruct jpeg library to save the markers that we care about. Since
|
||||
// the orientation and color profile will not change, we can skip this
|
||||
// step on rewinds.
|
||||
if (codecOut) {
|
||||
jpeg_save_markers(decoderMgr->dinfo(), kExifMarker, 0xFFFF);
|
||||
jpeg_save_markers(decoderMgr->dinfo(), kICCMarker, 0xFFFF);
|
||||
jpeg_save_markers(dinfo, kExifMarker, 0xFFFF);
|
||||
jpeg_save_markers(dinfo, kICCMarker, 0xFFFF);
|
||||
}
|
||||
|
||||
// Read the jpeg header
|
||||
switch (jpeg_read_header(decoderMgr->dinfo(), true)) {
|
||||
switch (jpeg_read_header(dinfo, true)) {
|
||||
case JPEG_HEADER_OK:
|
||||
break;
|
||||
case JPEG_SUSPENDED:
|
||||
@ -234,42 +237,41 @@ SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
|
||||
return kInvalidInput;
|
||||
}
|
||||
|
||||
// Create image info object and the codec
|
||||
SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_Alpha, 8);
|
||||
|
||||
SkEncodedOrigin orientation = get_exif_orientation(decoderMgr->dinfo());
|
||||
sk_sp<SkColorSpace> colorSpace = read_color_space(decoderMgr->dinfo());
|
||||
if (colorSpace) {
|
||||
SkEncodedOrigin orientation = get_exif_orientation(dinfo);
|
||||
auto profile = read_color_profile(dinfo);
|
||||
if (profile) {
|
||||
auto type = profile->profile()->data_color_space;
|
||||
switch (decoderMgr->dinfo()->jpeg_color_space) {
|
||||
case JCS_CMYK:
|
||||
case JCS_YCCK:
|
||||
if (colorSpace->type() != SkColorSpace::kCMYK_Type) {
|
||||
colorSpace = nullptr;
|
||||
if (type != skcms_Signature_CMYK) {
|
||||
profile = nullptr;
|
||||
}
|
||||
break;
|
||||
case JCS_GRAYSCALE:
|
||||
if (colorSpace->type() != SkColorSpace::kGray_Type &&
|
||||
colorSpace->type() != SkColorSpace::kRGB_Type)
|
||||
if (type != skcms_Signature_Gray &&
|
||||
type != skcms_Signature_RGB)
|
||||
{
|
||||
colorSpace = nullptr;
|
||||
profile = nullptr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (colorSpace->type() != SkColorSpace::kRGB_Type) {
|
||||
colorSpace = nullptr;
|
||||
if (type != skcms_Signature_RGB) {
|
||||
profile = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!colorSpace) {
|
||||
colorSpace = defaultColorSpace;
|
||||
if (!profile) {
|
||||
profile = std::move(defaultColorProfile);
|
||||
}
|
||||
|
||||
const int width = decoderMgr->dinfo()->image_width;
|
||||
const int height = decoderMgr->dinfo()->image_height;
|
||||
SkJpegCodec* codec = new SkJpegCodec(width, height, info, std::unique_ptr<SkStream>(stream),
|
||||
decoderMgr.release(), std::move(colorSpace),
|
||||
orientation);
|
||||
SkEncodedInfo info = SkEncodedInfo::Make(dinfo->image_width, dinfo->image_height,
|
||||
color, SkEncodedInfo::kOpaque_Alpha, 8,
|
||||
std::move(profile));
|
||||
|
||||
SkJpegCodec* codec = new SkJpegCodec(std::move(info), std::unique_ptr<SkStream>(stream),
|
||||
decoderMgr.release(), orientation);
|
||||
*codecOut = codec;
|
||||
} else {
|
||||
SkASSERT(nullptr != decoderMgrOut);
|
||||
@ -280,14 +282,15 @@ SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
|
||||
|
||||
std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
|
||||
Result* result) {
|
||||
return SkJpegCodec::MakeFromStream(std::move(stream), result, SkColorSpace::MakeSRGB());
|
||||
return SkJpegCodec::MakeFromStream(std::move(stream), result,
|
||||
// FIXME: This may not be used. Can we skip creating it?
|
||||
SkEncodedInfo::ICCProfile::MakeSRGB());
|
||||
}
|
||||
|
||||
std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
|
||||
Result* result,
|
||||
sk_sp<SkColorSpace> defaultColorSpace) {
|
||||
Result* result, std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) {
|
||||
SkCodec* codec = nullptr;
|
||||
*result = ReadHeader(stream.get(), &codec, nullptr, std::move(defaultColorSpace));
|
||||
*result = ReadHeader(stream.get(), &codec, nullptr, std::move(defaultColorProfile));
|
||||
if (kSuccess == *result) {
|
||||
// Codec has taken ownership of the stream, we do not need to delete it
|
||||
SkASSERT(codec);
|
||||
@ -297,11 +300,10 @@ std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> s
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info,
|
||||
std::unique_ptr<SkStream> stream, JpegDecoderMgr* decoderMgr,
|
||||
sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin)
|
||||
: INHERITED(width, height, info, SkColorSpaceXform::kRGBA_8888_ColorFormat, std::move(stream),
|
||||
std::move(colorSpace), origin)
|
||||
SkJpegCodec::SkJpegCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||
JpegDecoderMgr* decoderMgr, SkEncodedOrigin origin)
|
||||
: INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, std::move(stream),
|
||||
origin)
|
||||
, fDecoderMgr(decoderMgr)
|
||||
, fReadyState(decoderMgr->dinfo()->global_state)
|
||||
, fSwizzleSrcRow(nullptr)
|
||||
@ -386,12 +388,10 @@ bool SkJpegCodec::onRewind() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the conversion between the input image and the requested output
|
||||
* image has been implemented
|
||||
* Sets the output color space
|
||||
*/
|
||||
bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) {
|
||||
bool SkJpegCodec::conversionSupported(const SkImageInfo& dstInfo, SkColorType srcCT,
|
||||
bool srcIsOpaque, bool needsColorXform) {
|
||||
SkASSERT(srcIsOpaque);
|
||||
|
||||
if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
|
||||
return false;
|
||||
}
|
||||
@ -409,7 +409,7 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) {
|
||||
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
||||
break;
|
||||
case kBGRA_8888_SkColorType:
|
||||
if (this->colorXform()) {
|
||||
if (needsColorXform) {
|
||||
// Always using RGBA as the input format for color xforms makes the
|
||||
// implementation a little simpler.
|
||||
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
||||
@ -418,7 +418,7 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) {
|
||||
}
|
||||
break;
|
||||
case kRGB_565_SkColorType:
|
||||
if (this->colorXform()) {
|
||||
if (needsColorXform) {
|
||||
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
||||
} else {
|
||||
fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
|
||||
@ -426,14 +426,15 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) {
|
||||
}
|
||||
break;
|
||||
case kGray_8_SkColorType:
|
||||
if (this->colorXform() || JCS_GRAYSCALE != encodedColorType) {
|
||||
SkASSERT(!needsColorXform);
|
||||
if (JCS_GRAYSCALE != encodedColorType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
|
||||
break;
|
||||
case kRGBA_F16_SkColorType:
|
||||
SkASSERT(this->colorXform());
|
||||
SkASSERT(needsColorXform);
|
||||
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
||||
break;
|
||||
default:
|
||||
@ -539,7 +540,7 @@ int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes
|
||||
}
|
||||
|
||||
if (this->colorXform()) {
|
||||
this->applyColorXform(dst, swizzleDst, dstWidth, kOpaque_SkAlphaType);
|
||||
this->applyColorXform(dst, swizzleDst, dstWidth);
|
||||
dst = SkTAddOffset<void>(dst, rowBytes);
|
||||
}
|
||||
|
||||
@ -553,16 +554,17 @@ int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes
|
||||
/*
|
||||
* This is a bit tricky. We only need the swizzler to do format conversion if the jpeg is
|
||||
* encoded as CMYK.
|
||||
* And even then we still may not need it. If the jpeg has a CMYK color space and a color
|
||||
* And even then we still may not need it. If the jpeg has a CMYK color profile and a color
|
||||
* xform, the color xform will handle the CMYK->RGB conversion.
|
||||
*/
|
||||
static inline bool needs_swizzler_to_convert_from_cmyk(J_COLOR_SPACE jpegColorType,
|
||||
const SkImageInfo& srcInfo, bool hasColorSpaceXform) {
|
||||
const skcms_ICCProfile* srcProfile,
|
||||
bool hasColorSpaceXform) {
|
||||
if (JCS_CMYK != jpegColorType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasCMYKColorSpace = SkColorSpace::kCMYK_Type == srcInfo.colorSpace()->type();
|
||||
bool hasCMYKColorSpace = srcProfile && srcProfile->data_color_space == skcms_Signature_CMYK;
|
||||
return !hasCMYKColorSpace || !hasColorSpaceXform;
|
||||
}
|
||||
|
||||
@ -587,11 +589,6 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
|
||||
return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
|
||||
}
|
||||
|
||||
// Check if we can decode to the requested destination and set the output color space
|
||||
if (!this->setOutputColorSpace(dstInfo)) {
|
||||
return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion);
|
||||
}
|
||||
|
||||
if (!jpeg_start_decompress(dinfo)) {
|
||||
return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
|
||||
}
|
||||
@ -600,8 +597,8 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
|
||||
// If it's not, we want to know because it means our strategy is not optimal.
|
||||
SkASSERT(1 == dinfo->rec_outbuf_height);
|
||||
|
||||
if (needs_swizzler_to_convert_from_cmyk(dinfo->out_color_space, this->getInfo(),
|
||||
this->colorXform())) {
|
||||
if (needs_swizzler_to_convert_from_cmyk(dinfo->out_color_space,
|
||||
this->getEncodedInfo().profile(), this->colorXform())) {
|
||||
this->initializeSwizzler(dstInfo, options, true);
|
||||
}
|
||||
|
||||
@ -641,14 +638,16 @@ void SkJpegCodec::allocateStorage(const SkImageInfo& dstInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
static SkEncodedInfo make_info(const SkEncodedInfo& orig, bool needsCMYKToRGB) {
|
||||
auto color = needsCMYKToRGB ? SkEncodedInfo::kInvertedCMYK_Color
|
||||
: orig.color();
|
||||
// The swizzler does not need the width or height
|
||||
return SkEncodedInfo::Make(0, 0, color, orig.alpha(), orig.bitsPerComponent());
|
||||
}
|
||||
|
||||
void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
|
||||
bool needsCMYKToRGB) {
|
||||
SkEncodedInfo swizzlerInfo = this->getEncodedInfo();
|
||||
if (needsCMYKToRGB) {
|
||||
swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Color,
|
||||
swizzlerInfo.alpha(),
|
||||
swizzlerInfo.bitsPerComponent());
|
||||
}
|
||||
SkEncodedInfo swizzlerInfo = make_info(this->getEncodedInfo(), needsCMYKToRGB);
|
||||
|
||||
Options swizzlerOptions = options;
|
||||
if (options.fSubset) {
|
||||
@ -678,7 +677,8 @@ SkSampler* SkJpegCodec::getSampler(bool createIfNecessary) {
|
||||
}
|
||||
|
||||
bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk(
|
||||
fDecoderMgr->dinfo()->out_color_space, this->getInfo(), this->colorXform());
|
||||
fDecoderMgr->dinfo()->out_color_space, this->getEncodedInfo().profile(),
|
||||
this->colorXform());
|
||||
this->initializeSwizzler(this->dstInfo(), this->options(), needsCMYKToRGB);
|
||||
this->allocateStorage(this->dstInfo());
|
||||
return fSwizzler.get();
|
||||
@ -693,18 +693,14 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
|
||||
return kInvalidInput;
|
||||
}
|
||||
|
||||
// Check if we can decode to the requested destination and set the output color space
|
||||
if (!this->setOutputColorSpace(dstInfo)) {
|
||||
return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion);
|
||||
}
|
||||
|
||||
if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
|
||||
SkCodecPrintf("start decompress failed\n");
|
||||
return kInvalidInput;
|
||||
}
|
||||
|
||||
bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk(
|
||||
fDecoderMgr->dinfo()->out_color_space, this->getInfo(), this->colorXform());
|
||||
fDecoderMgr->dinfo()->out_color_space, this->getEncodedInfo().profile(),
|
||||
this->colorXform());
|
||||
if (options.fSubset) {
|
||||
uint32_t startX = options.fSubset->x();
|
||||
uint32_t width = options.fSubset->width();
|
||||
|
@ -9,8 +9,6 @@
|
||||
#define SkJpegCodec_DEFINED
|
||||
|
||||
#include "SkCodec.h"
|
||||
#include "SkColorSpace.h"
|
||||
#include "SkColorSpaceXform.h"
|
||||
#include "SkImageInfo.h"
|
||||
#include "SkSwizzler.h"
|
||||
#include "SkStream.h"
|
||||
@ -58,19 +56,14 @@ protected:
|
||||
|
||||
bool onDimensionsSupported(const SkISize&) override;
|
||||
|
||||
bool conversionSupported(const SkImageInfo&, SkColorType, bool,
|
||||
const SkColorSpace*) const override {
|
||||
// This class checks for conversion after creating colorXform.
|
||||
return true;
|
||||
}
|
||||
bool conversionSupported(const SkImageInfo&, SkColorType, bool, bool) override;
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Allows SkRawCodec to communicate the color space from the exif data.
|
||||
* Allows SkRawCodec to communicate the color profile from the exif data.
|
||||
*/
|
||||
static std::unique_ptr<SkCodec> MakeFromStream(std::unique_ptr<SkStream>, Result*,
|
||||
sk_sp<SkColorSpace> defaultColorSpace);
|
||||
std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile);
|
||||
|
||||
/*
|
||||
* Read enough of the stream to initialize the SkJpegCodec.
|
||||
@ -90,12 +83,13 @@ private:
|
||||
* codecOut will take ownership of it in the case where we created a codec.
|
||||
* Ownership is unchanged when we set decoderMgrOut.
|
||||
*
|
||||
* @param defaultColorSpace
|
||||
* If the jpeg does not have an embedded color space, the image data should
|
||||
* be tagged with this color space.
|
||||
* @param defaultColorProfile
|
||||
* If the jpeg does not have an embedded color profile, the image data should
|
||||
* be tagged with this color profile.
|
||||
*/
|
||||
static Result ReadHeader(SkStream* stream, SkCodec** codecOut,
|
||||
JpegDecoderMgr** decoderMgrOut, sk_sp<SkColorSpace> defaultColorSpace);
|
||||
JpegDecoderMgr** decoderMgrOut,
|
||||
std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile);
|
||||
|
||||
/*
|
||||
* Creates an instance of the decoder
|
||||
@ -106,16 +100,8 @@ private:
|
||||
* @param decoderMgr holds decompress struct, src manager, and error manager
|
||||
* takes ownership
|
||||
*/
|
||||
SkJpegCodec(int width, int height, const SkEncodedInfo& info, std::unique_ptr<SkStream> stream,
|
||||
JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin);
|
||||
|
||||
/*
|
||||
* Checks if the conversion between the input image and the requested output
|
||||
* image has been implemented.
|
||||
*
|
||||
* Sets the output color space.
|
||||
*/
|
||||
bool setOutputColorSpace(const SkImageInfo& dst);
|
||||
SkJpegCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||
JpegDecoderMgr* decoderMgr, SkEncodedOrigin origin);
|
||||
|
||||
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
|
||||
bool needsCMYKToRGB);
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "SkCodecPriv.h"
|
||||
#include "SkColorData.h"
|
||||
#include "SkColorSpace.h"
|
||||
#include "SkColorSpacePriv.h"
|
||||
#include "SkColorTable.h"
|
||||
#include "SkMacros.h"
|
||||
#include "SkMath.h"
|
||||
@ -248,6 +247,10 @@ bool SkPngCodec::processData() {
|
||||
|
||||
static constexpr SkColorType kXformSrcColorType = kRGBA_8888_SkColorType;
|
||||
|
||||
static inline bool needs_premul(SkAlphaType dstAT, SkEncodedInfo::Alpha encodedAlpha) {
|
||||
return kPremul_SkAlphaType == dstAT && SkEncodedInfo::kUnpremul_Alpha == encodedAlpha;
|
||||
}
|
||||
|
||||
// Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here.
|
||||
bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) {
|
||||
|
||||
@ -265,10 +268,7 @@ bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) {
|
||||
png_bytep alphas;
|
||||
int numColorsWithAlpha = 0;
|
||||
if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) {
|
||||
// If we are performing a color xform, it will handle the premultiply. Otherwise,
|
||||
// we'll do it here.
|
||||
bool premultiply = !this->colorXform() && needs_premul(dstInfo.alphaType(),
|
||||
this->getEncodedInfo().alpha());
|
||||
bool premultiply = needs_premul(dstInfo.alphaType(), this->getEncodedInfo().alpha());
|
||||
|
||||
// Choose which function to use to create the color table. If the final destination's
|
||||
// colortype is unpremultiplied, the color table will store unpremultiplied colors.
|
||||
@ -342,13 +342,11 @@ static float png_inverted_fixed_point_to_float(png_fixed_point x) {
|
||||
|
||||
#endif // LIBPNG >= 1.6
|
||||
|
||||
// Returns a colorSpace object that represents any color space information in
|
||||
// the encoded data. If the encoded data contains an invalid/unsupported color space,
|
||||
// this will return NULL. If there is no color space information, it will guess sRGB
|
||||
sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) {
|
||||
// If there is no color profile information, it will use sRGB.
|
||||
std::unique_ptr<SkEncodedInfo::ICCProfile> read_color_profile(png_structp png_ptr,
|
||||
png_infop info_ptr) {
|
||||
|
||||
#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
|
||||
|
||||
// First check for an ICC profile
|
||||
png_bytep profile;
|
||||
png_uint_32 length;
|
||||
@ -362,74 +360,70 @@ sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) {
|
||||
int compression;
|
||||
if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile,
|
||||
&length)) {
|
||||
return SkColorSpace::MakeICC(profile, length);
|
||||
auto data = SkData::MakeWithCopy(profile, length);
|
||||
return SkEncodedInfo::ICCProfile::Make(std::move(data));
|
||||
}
|
||||
|
||||
// Second, check for sRGB.
|
||||
// Note that Blink does this first. This code checks ICC first, with the thinking that
|
||||
// an image has both truly wants the potentially more specific ICC chunk, with sRGB as a
|
||||
// backup in case the decoder does not support full color management.
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
|
||||
|
||||
// sRGB chunks also store a rendering intent: Absolute, Relative,
|
||||
// Perceptual, and Saturation.
|
||||
// FIXME (msarett): Extract this information from the sRGB chunk once
|
||||
// we are able to handle this information in
|
||||
// SkColorSpace.
|
||||
return SkColorSpace::MakeSRGB();
|
||||
return SkEncodedInfo::ICCProfile::MakeSRGB();
|
||||
}
|
||||
|
||||
// Default to SRGB gamut.
|
||||
skcms_Matrix3x3 toXYZD50 = skcms_sRGB_profile()->toXYZD50;
|
||||
// Next, check for chromaticities.
|
||||
png_fixed_point chrm[8];
|
||||
png_fixed_point gamma;
|
||||
if (png_get_cHRM_fixed(png_ptr, info_ptr, &chrm[0], &chrm[1], &chrm[2], &chrm[3], &chrm[4],
|
||||
&chrm[5], &chrm[6], &chrm[7]))
|
||||
{
|
||||
SkColorSpacePrimaries primaries;
|
||||
primaries.fRX = png_fixed_point_to_float(chrm[2]);
|
||||
primaries.fRY = png_fixed_point_to_float(chrm[3]);
|
||||
primaries.fGX = png_fixed_point_to_float(chrm[4]);
|
||||
primaries.fGY = png_fixed_point_to_float(chrm[5]);
|
||||
primaries.fBX = png_fixed_point_to_float(chrm[6]);
|
||||
primaries.fBY = png_fixed_point_to_float(chrm[7]);
|
||||
primaries.fWX = png_fixed_point_to_float(chrm[0]);
|
||||
primaries.fWY = png_fixed_point_to_float(chrm[1]);
|
||||
float rx = png_fixed_point_to_float(chrm[2]);
|
||||
float ry = png_fixed_point_to_float(chrm[3]);
|
||||
float gx = png_fixed_point_to_float(chrm[4]);
|
||||
float gy = png_fixed_point_to_float(chrm[5]);
|
||||
float bx = png_fixed_point_to_float(chrm[6]);
|
||||
float by = png_fixed_point_to_float(chrm[7]);
|
||||
float wx = png_fixed_point_to_float(chrm[0]);
|
||||
float wy = png_fixed_point_to_float(chrm[1]);
|
||||
|
||||
SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
|
||||
if (!primaries.toXYZD50(&toXYZD50)) {
|
||||
toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
|
||||
}
|
||||
|
||||
if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
|
||||
SkColorSpaceTransferFn fn;
|
||||
fn.fA = 1.0f;
|
||||
fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f;
|
||||
fn.fG = png_inverted_fixed_point_to_float(gamma);
|
||||
|
||||
return SkColorSpace::MakeRGB(fn, toXYZD50);
|
||||
skcms_Matrix3x3 tmp;
|
||||
if (skcms_PrimariesToXYZD50(rx, ry, gx, gy, bx, by, wx, wy, &tmp)) {
|
||||
toXYZD50 = tmp;
|
||||
} else {
|
||||
// Note that Blink simply returns nullptr in this case. We'll fall
|
||||
// back to srgb.
|
||||
}
|
||||
}
|
||||
|
||||
skcms_TransferFunction fn;
|
||||
if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
|
||||
fn.a = 1.0f;
|
||||
fn.b = fn.c = fn.d = fn.e = fn.f = 0.0f;
|
||||
fn.g = png_inverted_fixed_point_to_float(gamma);
|
||||
} else {
|
||||
// Default to sRGB gamma if the image has color space information,
|
||||
// but does not specify gamma.
|
||||
return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50);
|
||||
// Note that Blink would again return nullptr in this case.
|
||||
fn = *skcms_sRGB_TransferFunction();
|
||||
}
|
||||
|
||||
// Last, check for gamma.
|
||||
if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
|
||||
SkColorSpaceTransferFn fn;
|
||||
fn.fA = 1.0f;
|
||||
fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f;
|
||||
fn.fG = png_inverted_fixed_point_to_float(gamma);
|
||||
|
||||
// Since there is no cHRM, we will guess sRGB gamut.
|
||||
SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
|
||||
toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
|
||||
|
||||
return SkColorSpace::MakeRGB(fn, toXYZD50);
|
||||
}
|
||||
skcms_ICCProfile skcmsProfile;
|
||||
skcms_Init(&skcmsProfile);
|
||||
skcms_SetTransferFunction(&skcmsProfile, &fn);
|
||||
skcms_SetXYZD50(&skcmsProfile, &toXYZD50);
|
||||
|
||||
return SkEncodedInfo::ICCProfile::Make(skcmsProfile);
|
||||
#else // LIBPNG >= 1.6
|
||||
return SkEncodedInfo::ICCProfile::MakeSRGB();
|
||||
#endif // LIBPNG >= 1.6
|
||||
|
||||
// Report that there is no color space information in the PNG.
|
||||
// Guess sRGB in this case.
|
||||
return SkColorSpace::MakeSRGB();
|
||||
}
|
||||
|
||||
void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) {
|
||||
@ -454,17 +448,17 @@ void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
static SkColorSpaceXform::ColorFormat png_select_xform_format(const SkEncodedInfo& info) {
|
||||
static skcms_PixelFormat png_select_xform_format(const SkEncodedInfo& info) {
|
||||
// We use kRGB and kRGBA formats because color PNGs are always RGB or RGBA.
|
||||
if (16 == info.bitsPerComponent()) {
|
||||
if (SkEncodedInfo::kRGBA_Color == info.color()) {
|
||||
return SkColorSpaceXform::kRGBA_U16_BE_ColorFormat;
|
||||
return skcms_PixelFormat_RGBA_16161616;
|
||||
} else if (SkEncodedInfo::kRGB_Color == info.color()) {
|
||||
return SkColorSpaceXform::kRGB_U16_BE_ColorFormat;
|
||||
return skcms_PixelFormat_RGB_161616;
|
||||
}
|
||||
}
|
||||
|
||||
return SkColorSpaceXform::kRGBA_8888_ColorFormat;
|
||||
return skcms_PixelFormat_RGBA_8888;
|
||||
}
|
||||
|
||||
void SkPngCodec::applyXformRow(void* dst, const void* src) {
|
||||
@ -484,10 +478,9 @@ void SkPngCodec::applyXformRow(void* dst, const void* src) {
|
||||
|
||||
class SkPngNormalDecoder : public SkPngCodec {
|
||||
public:
|
||||
SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
|
||||
std::unique_ptr<SkStream> stream, SkPngChunkReader* reader,
|
||||
png_structp png_ptr, png_infop info_ptr, int bitDepth)
|
||||
: INHERITED(info, imageInfo, std::move(stream), reader, png_ptr, info_ptr, bitDepth)
|
||||
SkPngNormalDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||
SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, int bitDepth)
|
||||
: INHERITED(std::move(info), std::move(stream), reader, png_ptr, info_ptr, bitDepth)
|
||||
, fRowsWrittenToOutput(0)
|
||||
, fDst(nullptr)
|
||||
, fRowBytes(0)
|
||||
@ -607,10 +600,10 @@ private:
|
||||
|
||||
class SkPngInterlacedDecoder : public SkPngCodec {
|
||||
public:
|
||||
SkPngInterlacedDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
|
||||
std::unique_ptr<SkStream> stream, SkPngChunkReader* reader, png_structp png_ptr,
|
||||
SkPngInterlacedDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||
SkPngChunkReader* reader, png_structp png_ptr,
|
||||
png_infop info_ptr, int bitDepth, int numberPasses)
|
||||
: INHERITED(info, imageInfo, std::move(stream), reader, png_ptr, info_ptr, bitDepth)
|
||||
: INHERITED(std::move(info), std::move(stream), reader, png_ptr, info_ptr, bitDepth)
|
||||
, fNumberPasses(numberPasses)
|
||||
, fFirstRow(0)
|
||||
, fLastRow(0)
|
||||
@ -918,36 +911,33 @@ void AutoCleanPng::infoCallback(size_t idatLength) {
|
||||
|
||||
if (fOutCodec) {
|
||||
SkASSERT(nullptr == *fOutCodec);
|
||||
sk_sp<SkColorSpace> colorSpace = read_color_space(fPng_ptr, fInfo_ptr);
|
||||
if (colorSpace) {
|
||||
switch (colorSpace->type()) {
|
||||
case SkColorSpace::kCMYK_Type:
|
||||
colorSpace = nullptr;
|
||||
auto profile = read_color_profile(fPng_ptr, fInfo_ptr);
|
||||
if (profile) {
|
||||
switch (profile->profile()->data_color_space) {
|
||||
case skcms_Signature_CMYK:
|
||||
profile = nullptr;
|
||||
break;
|
||||
case SkColorSpace::kGray_Type:
|
||||
case skcms_Signature_Gray:
|
||||
if (SkEncodedInfo::kGray_Color != color &&
|
||||
SkEncodedInfo::kGrayAlpha_Color != color)
|
||||
{
|
||||
colorSpace = nullptr;
|
||||
profile = nullptr;
|
||||
}
|
||||
break;
|
||||
case SkColorSpace::kRGB_Type:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!colorSpace) {
|
||||
if (!profile) {
|
||||
// Treat unsupported/invalid color spaces as sRGB.
|
||||
colorSpace = SkColorSpace::MakeSRGB();
|
||||
profile = SkEncodedInfo::ICCProfile::MakeSRGB();
|
||||
}
|
||||
|
||||
SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, bitDepth);
|
||||
SkImageInfo imageInfo = encodedInfo.makeImageInfo(origWidth, origHeight, colorSpace);
|
||||
|
||||
if (encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||
png_color_8p sigBits;
|
||||
if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
|
||||
if (8 == sigBits->alpha && kGraySigBit_GrayAlphaIsJustAlpha == sigBits->gray) {
|
||||
imageInfo = imageInfo.makeColorType(kAlpha_8_SkColorType);
|
||||
color = SkEncodedInfo::kXAlpha_Color;
|
||||
}
|
||||
}
|
||||
} else if (SkEncodedInfo::kOpaque_Alpha == alpha) {
|
||||
@ -955,16 +945,18 @@ void AutoCleanPng::infoCallback(size_t idatLength) {
|
||||
if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
|
||||
if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) {
|
||||
// Recommend a decode to 565 if the sBIT indicates 565.
|
||||
imageInfo = imageInfo.makeColorType(kRGB_565_SkColorType);
|
||||
color = SkEncodedInfo::k565_Color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SkEncodedInfo encodedInfo = SkEncodedInfo::Make(origWidth, origHeight, color, alpha,
|
||||
bitDepth, std::move(profile));
|
||||
if (1 == numberPasses) {
|
||||
*fOutCodec = new SkPngNormalDecoder(encodedInfo, imageInfo,
|
||||
*fOutCodec = new SkPngNormalDecoder(std::move(encodedInfo),
|
||||
std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth);
|
||||
} else {
|
||||
*fOutCodec = new SkPngInterlacedDecoder(encodedInfo, imageInfo,
|
||||
*fOutCodec = new SkPngInterlacedDecoder(std::move(encodedInfo),
|
||||
std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth,
|
||||
numberPasses);
|
||||
}
|
||||
@ -976,10 +968,9 @@ void AutoCleanPng::infoCallback(size_t idatLength) {
|
||||
this->releasePngPtrs();
|
||||
}
|
||||
|
||||
SkPngCodec::SkPngCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
|
||||
std::unique_ptr<SkStream> stream, SkPngChunkReader* chunkReader,
|
||||
void* png_ptr, void* info_ptr, int bitDepth)
|
||||
: INHERITED(encodedInfo, imageInfo, png_select_xform_format(encodedInfo), std::move(stream))
|
||||
SkPngCodec::SkPngCodec(SkEncodedInfo&& encodedInfo, std::unique_ptr<SkStream> stream,
|
||||
SkPngChunkReader* chunkReader, void* png_ptr, void* info_ptr, int bitDepth)
|
||||
: INHERITED(std::move(encodedInfo), png_select_xform_format(encodedInfo), std::move(stream))
|
||||
, fPngChunkReader(SkSafeRef(chunkReader))
|
||||
, fPng_ptr(png_ptr)
|
||||
, fInfo_ptr(info_ptr)
|
||||
|
@ -8,7 +8,6 @@
|
||||
#define SkPngCodec_DEFINED
|
||||
|
||||
#include "SkCodec.h"
|
||||
#include "SkColorSpaceXform.h"
|
||||
#include "SkColorTable.h"
|
||||
#include "SkPngChunkReader.h"
|
||||
#include "SkEncodedImageFormat.h"
|
||||
@ -45,8 +44,8 @@ protected:
|
||||
void* fPtr;
|
||||
};
|
||||
|
||||
SkPngCodec(const SkEncodedInfo&, const SkImageInfo&, std::unique_ptr<SkStream>,
|
||||
SkPngChunkReader*, void* png_ptr, void* info_ptr, int bitDepth);
|
||||
SkPngCodec(SkEncodedInfo&&, std::unique_ptr<SkStream>, SkPngChunkReader*,
|
||||
void* png_ptr, void* info_ptr, int bitDepth);
|
||||
|
||||
Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, int*)
|
||||
override;
|
||||
|
@ -504,10 +504,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
const SkEncodedInfo& getEncodedInfo() const {
|
||||
return fEncodedInfo;
|
||||
}
|
||||
|
||||
int width() const {
|
||||
return fWidth;
|
||||
}
|
||||
@ -602,8 +598,6 @@ private:
|
||||
|
||||
SkDngImage(SkRawStream* stream)
|
||||
: fStream(stream)
|
||||
, fEncodedInfo(SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color,
|
||||
SkEncodedInfo::kOpaque_Alpha, 8))
|
||||
{}
|
||||
|
||||
dng_memory_allocator fAllocator;
|
||||
@ -615,11 +609,21 @@ private:
|
||||
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
SkEncodedInfo fEncodedInfo;
|
||||
bool fIsScalable;
|
||||
bool fIsXtransImage;
|
||||
};
|
||||
|
||||
static constexpr skcms_Matrix3x3 gAdobe_RGB_to_XYZD50 = {{
|
||||
// ICC fixed-point (16.16) repesentation of:
|
||||
// 0.60974, 0.20528, 0.14919,
|
||||
// 0.31111, 0.62567, 0.06322,
|
||||
// 0.01947, 0.06087, 0.74457,
|
||||
{ SkFixedToFloat(0x9c18), SkFixedToFloat(0x348d), SkFixedToFloat(0x2631) }, // Rx, Gx, Bx
|
||||
{ SkFixedToFloat(0x4fa5), SkFixedToFloat(0xa02c), SkFixedToFloat(0x102f) }, // Ry, Gy, By
|
||||
{ SkFixedToFloat(0x04fc), SkFixedToFloat(0x0f95), SkFixedToFloat(0xbe9c) }, // Rz, Gz, Bz
|
||||
}};
|
||||
|
||||
|
||||
/*
|
||||
* Tries to handle the image with PIEX. If PIEX returns kOk and finds the preview image, create a
|
||||
* SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases,
|
||||
@ -644,15 +648,21 @@ std::unique_ptr<SkCodec> SkRawCodec::MakeFromStream(std::unique_ptr<SkStream> st
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sk_sp<SkColorSpace> colorSpace;
|
||||
std::unique_ptr<SkEncodedInfo::ICCProfile> profile;
|
||||
switch (imageData.color_space) {
|
||||
case ::piex::PreviewImageData::kSrgb:
|
||||
colorSpace = SkColorSpace::MakeSRGB();
|
||||
profile = SkEncodedInfo::ICCProfile::MakeSRGB();
|
||||
break;
|
||||
case ::piex::PreviewImageData::kAdobeRgb:
|
||||
colorSpace = SkColorSpace::MakeRGB(g2Dot2_TransferFn,
|
||||
SkColorSpace::kAdobeRGB_Gamut);
|
||||
case ::piex::PreviewImageData::kAdobeRgb: {
|
||||
constexpr skcms_TransferFunction twoDotTwo =
|
||||
{ 2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
skcms_ICCProfile skcmsProfile;
|
||||
skcms_Init(&skcmsProfile);
|
||||
skcms_SetTransferFunction(&skcmsProfile, &twoDotTwo);
|
||||
skcms_SetXYZD50(&skcmsProfile, &gAdobe_RGB_to_XYZD50);
|
||||
profile = SkEncodedInfo::ICCProfile::Make(skcmsProfile);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Theoretically PIEX can return JPEG compressed image or uncompressed RGB image. We only
|
||||
@ -670,7 +680,7 @@ std::unique_ptr<SkCodec> SkRawCodec::MakeFromStream(std::unique_ptr<SkStream> st
|
||||
return nullptr;
|
||||
}
|
||||
return SkJpegCodec::MakeFromStream(std::move(memoryStream), result,
|
||||
std::move(colorSpace));
|
||||
std::move(profile));
|
||||
}
|
||||
}
|
||||
|
||||
@ -746,7 +756,7 @@ SkCodec::Result SkRawCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
|
||||
if (this->colorXform()) {
|
||||
swizzler->swizzle(xformBuffer.get(), &srcRow[0]);
|
||||
|
||||
this->applyColorXform(dstRow, xformBuffer.get(), dstInfo.width(), kOpaque_SkAlphaType);
|
||||
this->applyColorXform(dstRow, xformBuffer.get(), dstInfo.width());
|
||||
} else {
|
||||
swizzler->swizzle(dstRow, &srcRow[0]);
|
||||
}
|
||||
@ -796,7 +806,8 @@ bool SkRawCodec::onDimensionsSupported(const SkISize& dim) {
|
||||
SkRawCodec::~SkRawCodec() {}
|
||||
|
||||
SkRawCodec::SkRawCodec(SkDngImage* dngImage)
|
||||
: INHERITED(dngImage->width(), dngImage->height(), dngImage->getEncodedInfo(),
|
||||
SkColorSpaceXform::kRGBA_8888_ColorFormat, nullptr,
|
||||
SkColorSpace::MakeSRGB())
|
||||
: INHERITED(SkEncodedInfo::MakeSRGB(dngImage->width(), dngImage->height(),
|
||||
SkEncodedInfo::kRGB_Color,
|
||||
SkEncodedInfo::kOpaque_Alpha, 8),
|
||||
skcms_PixelFormat_RGBA_8888, nullptr)
|
||||
, fDngImage(dngImage) {}
|
||||
|
@ -890,6 +890,7 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo,
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
case SkEncodedInfo::kXAlpha_Color:
|
||||
case SkEncodedInfo::kGrayAlpha_Color:
|
||||
switch (dstInfo.colorType()) {
|
||||
case kRGBA_8888_SkColorType:
|
||||
@ -963,6 +964,10 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo,
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
case SkEncodedInfo::k565_Color:
|
||||
// Treat 565 exactly like RGB (since it's still encoded as 8 bits per component).
|
||||
// We just mark as 565 when we have a hint that there are only 5/6/5 "significant"
|
||||
// bits in each channel.
|
||||
case SkEncodedInfo::kRGB_Color:
|
||||
switch (dstInfo.colorType()) {
|
||||
case kRGBA_8888_SkColorType:
|
||||
|
@ -97,11 +97,10 @@ bool SkWbmpCodec::readRow(uint8_t* row) {
|
||||
return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes;
|
||||
}
|
||||
|
||||
SkWbmpCodec::SkWbmpCodec(int width, int height, const SkEncodedInfo& info,
|
||||
std::unique_ptr<SkStream> stream)
|
||||
SkWbmpCodec::SkWbmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream)
|
||||
// Wbmp does not need a colorXform, so choose an arbitrary srcFormat.
|
||||
: INHERITED(width, height, info, SkColorSpaceXform::ColorFormat(),
|
||||
std::move(stream), SkColorSpace::MakeSRGB())
|
||||
: INHERITED(std::move(info), skcms_PixelFormat(),
|
||||
std::move(stream))
|
||||
, fSrcRowBytes(get_src_row_bytes(this->getInfo().width()))
|
||||
, fSwizzler(nullptr)
|
||||
{}
|
||||
@ -111,7 +110,7 @@ SkEncodedImageFormat SkWbmpCodec::onGetEncodedFormat() const {
|
||||
}
|
||||
|
||||
bool SkWbmpCodec::conversionSupported(const SkImageInfo& dst, SkColorType /*srcColor*/,
|
||||
bool srcIsOpaque, const SkColorSpace* srcCS) const {
|
||||
bool srcIsOpaque, bool /*needsXform*/) {
|
||||
return valid_color_type(dst) && valid_alpha(dst.alphaType(), srcIsOpaque);
|
||||
}
|
||||
|
||||
@ -159,10 +158,9 @@ std::unique_ptr<SkCodec> SkWbmpCodec::MakeFromStream(std::unique_ptr<SkStream> s
|
||||
return nullptr;
|
||||
}
|
||||
*result = kSuccess;
|
||||
SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kGray_Color,
|
||||
SkEncodedInfo::kOpaque_Alpha, 1);
|
||||
return std::unique_ptr<SkCodec>(new SkWbmpCodec(size.width(), size.height(), info,
|
||||
std::move(stream)));
|
||||
auto info = SkEncodedInfo::Make(size.width(), size.height(), SkEncodedInfo::kGray_Color,
|
||||
SkEncodedInfo::kOpaque_Alpha, 1);
|
||||
return std::unique_ptr<SkCodec>(new SkWbmpCodec(std::move(info), std::move(stream)));
|
||||
}
|
||||
|
||||
int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
|
||||
|
@ -29,7 +29,7 @@ protected:
|
||||
const Options&, int*) override;
|
||||
bool onRewind() override;
|
||||
bool conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
|
||||
bool srcIsOpaque, const SkColorSpace* srcCS) const override;
|
||||
bool srcIsOpaque, bool needsXform) override;
|
||||
// No need to Xform; all pixels are either black or white.
|
||||
bool usesColorXform() const override { return false; }
|
||||
private:
|
||||
@ -48,7 +48,7 @@ private:
|
||||
*/
|
||||
bool readRow(uint8_t* row);
|
||||
|
||||
SkWbmpCodec(int width, int height, const SkEncodedInfo&, std::unique_ptr<SkStream>);
|
||||
SkWbmpCodec(SkEncodedInfo&&, std::unique_ptr<SkStream>);
|
||||
|
||||
const size_t fSrcRowBytes;
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "SkCodecAnimation.h"
|
||||
#include "SkCodecAnimationPriv.h"
|
||||
#include "SkCodecPriv.h"
|
||||
#include "SkColorSpaceXform.h"
|
||||
#include "SkMakeUnique.h"
|
||||
#include "SkRasterPipeline.h"
|
||||
#include "SkSampler.h"
|
||||
@ -89,15 +88,17 @@ std::unique_ptr<SkCodec> SkWebpCodec::MakeFromStream(std::unique_ptr<SkStream> s
|
||||
}
|
||||
}
|
||||
|
||||
sk_sp<SkColorSpace> colorSpace = nullptr;
|
||||
std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
|
||||
{
|
||||
WebPChunkIterator chunkIterator;
|
||||
SkAutoTCallVProc<WebPChunkIterator, WebPDemuxReleaseChunkIterator> autoCI(&chunkIterator);
|
||||
if (WebPDemuxGetChunk(demux, "ICCP", 1, &chunkIterator)) {
|
||||
colorSpace = SkColorSpace::MakeICC(chunkIterator.chunk.bytes, chunkIterator.chunk.size);
|
||||
// FIXME: I think this could be MakeWithoutCopy
|
||||
auto chunk = SkData::MakeWithCopy(chunkIterator.chunk.bytes, chunkIterator.chunk.size);
|
||||
profile = SkEncodedInfo::ICCProfile::Make(std::move(chunk));
|
||||
}
|
||||
if (!colorSpace || colorSpace->type() != SkColorSpace::kRGB_Type) {
|
||||
colorSpace = SkColorSpace::MakeSRGB();
|
||||
if (!profile || profile->profile()->data_color_space != skcms_Signature_RGB) {
|
||||
profile = SkEncodedInfo::ICCProfile::MakeSRGB();
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,10 +172,9 @@ std::unique_ptr<SkCodec> SkWebpCodec::MakeFromStream(std::unique_ptr<SkStream> s
|
||||
|
||||
|
||||
*result = kSuccess;
|
||||
SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8);
|
||||
return std::unique_ptr<SkCodec>(new SkWebpCodec(width, height, info, std::move(colorSpace),
|
||||
std::move(stream), demux.release(), std::move(data),
|
||||
origin));
|
||||
SkEncodedInfo info = SkEncodedInfo::Make(width, height, color, alpha, 8, std::move(profile));
|
||||
return std::unique_ptr<SkCodec>(new SkWebpCodec(std::move(info), std::move(stream),
|
||||
demux.release(), std::move(data), origin));
|
||||
}
|
||||
|
||||
SkISize SkWebpCodec::onGetScaledDimensions(float desiredScale) const {
|
||||
@ -543,35 +543,8 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
|
||||
webpDst.installPixels(webpInfo, dst, rowBytes);
|
||||
}
|
||||
|
||||
// Choose the step when we will perform premultiplication.
|
||||
enum {
|
||||
kNoPremul,
|
||||
kBlendLine,
|
||||
kColorXform,
|
||||
kLibwebp,
|
||||
};
|
||||
auto choose_premul_step = [&]() {
|
||||
if (!frame.has_alpha) {
|
||||
// None necessary.
|
||||
return kNoPremul;
|
||||
}
|
||||
if (blendWithPrevFrame) {
|
||||
// Premultiply in blend_line, in a linear space.
|
||||
return kBlendLine;
|
||||
}
|
||||
if (dstInfo.alphaType() != kPremul_SkAlphaType) {
|
||||
// No blending is necessary, so we only need to premultiply if the
|
||||
// client requested it.
|
||||
return kNoPremul;
|
||||
}
|
||||
if (this->colorXform()) {
|
||||
// Premultiply in the colorXform, in a linear space.
|
||||
return kColorXform;
|
||||
}
|
||||
return kLibwebp;
|
||||
};
|
||||
const auto premulStep = choose_premul_step();
|
||||
config.output.colorspace = webp_decode_mode(webpInfo.colorType(), premulStep == kLibwebp);
|
||||
config.output.colorspace = webp_decode_mode(webpInfo.colorType(),
|
||||
frame.has_alpha && dstInfo.alphaType() == kPremul_SkAlphaType && !this->colorXform());
|
||||
config.output.is_external_memory = 1;
|
||||
|
||||
config.output.u.RGBA.rgba = reinterpret_cast<uint8_t*>(webpDst.getAddr(dstX, dstY));
|
||||
@ -620,11 +593,8 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
|
||||
xformDst = dst;
|
||||
}
|
||||
|
||||
const auto xformAlphaType = (premulStep == kColorXform) ? kPremul_SkAlphaType :
|
||||
( frame.has_alpha) ? kUnpremul_SkAlphaType :
|
||||
kOpaque_SkAlphaType ;
|
||||
for (int y = 0; y < rowsDecoded; y++) {
|
||||
this->applyColorXform(xformDst, xformSrc, scaledWidth, xformAlphaType);
|
||||
this->applyColorXform(xformDst, xformSrc, scaledWidth);
|
||||
if (blendWithPrevFrame) {
|
||||
blend_line(dstCT, dst, dstCT, xformDst,
|
||||
dstInfo.alphaType(), frame.has_alpha, scaledWidth);
|
||||
@ -648,14 +618,14 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
|
||||
return result;
|
||||
}
|
||||
|
||||
SkWebpCodec::SkWebpCodec(int width, int height, const SkEncodedInfo& info,
|
||||
sk_sp<SkColorSpace> colorSpace, std::unique_ptr<SkStream> stream,
|
||||
SkWebpCodec::SkWebpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||
WebPDemuxer* demux, sk_sp<SkData> data, SkEncodedOrigin origin)
|
||||
: INHERITED(width, height, info, SkColorSpaceXform::kBGRA_8888_ColorFormat, std::move(stream),
|
||||
std::move(colorSpace), origin)
|
||||
: INHERITED(std::move(info), skcms_PixelFormat_BGRA_8888, std::move(stream),
|
||||
origin)
|
||||
, fDemux(demux)
|
||||
, fData(std::move(data))
|
||||
, fFailed(false)
|
||||
{
|
||||
fFrameHolder.setScreenSize(width, height);
|
||||
const auto& eInfo = this->getEncodedInfo();
|
||||
fFrameHolder.setScreenSize(eInfo.width(), eInfo.height());
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
#define SkWebpCodec_DEFINED
|
||||
|
||||
#include "SkCodec.h"
|
||||
#include "SkColorSpace.h"
|
||||
#include "SkEncodedImageFormat.h"
|
||||
#include "SkFrameHolder.h"
|
||||
#include "SkImageInfo.h"
|
||||
@ -47,8 +46,8 @@ protected:
|
||||
}
|
||||
|
||||
private:
|
||||
SkWebpCodec(int width, int height, const SkEncodedInfo&, sk_sp<SkColorSpace>,
|
||||
std::unique_ptr<SkStream>, WebPDemuxer*, sk_sp<SkData>, SkEncodedOrigin);
|
||||
SkWebpCodec(SkEncodedInfo&&, std::unique_ptr<SkStream>, WebPDemuxer*, sk_sp<SkData>,
|
||||
SkEncodedOrigin);
|
||||
|
||||
SkAutoTCallVProc<WebPDemuxer, WebPDemuxDelete> fDemux;
|
||||
|
||||
|
@ -134,7 +134,11 @@ sk_sp<SkColorSpace> SkColorSpace::Make(const skcms_ICCProfile& profile) {
|
||||
trc[1].table_entries ||
|
||||
trc[2].table_entries ||
|
||||
memcmp(&trc[0].parametric, &trc[1].parametric, sizeof(trc[0].parametric)) ||
|
||||
memcmp(&trc[0].parametric, &trc[2].parametric, sizeof(trc[0].parametric))) {
|
||||
memcmp(&trc[0].parametric, &trc[2].parametric, sizeof(trc[0].parametric)))
|
||||
{
|
||||
if (skcms_TRCs_AreApproximateInverse(&profile, skcms_sRGB_Inverse_TransferFunction())) {
|
||||
return SkColorSpace::MakeRGB(kSRGB_SkGammaNamed, toXYZD50);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "SkEncodedImageFormat.h"
|
||||
#include "SkImageGenerator.h"
|
||||
#include "SkImageInfo.h"
|
||||
#include "SkMatrix44.h"
|
||||
#include "SkPixmapPriv.h"
|
||||
#include "SkRefCnt.h"
|
||||
#include "SkSize.h"
|
||||
@ -131,6 +132,76 @@ DEF_TEST(AndroidCodec_computeSampleSize, r) {
|
||||
}
|
||||
}
|
||||
|
||||
DEF_TEST(AndroidCodec_wide, r) {
|
||||
if (GetResourcePath().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* path = "images/wide-gamut.png";
|
||||
auto data = GetResourceAsData(path);
|
||||
if (!data) {
|
||||
ERRORF(r, "Missing file %s", path);
|
||||
return;
|
||||
}
|
||||
|
||||
auto codec = SkAndroidCodec::MakeFromCodec(SkCodec::MakeFromData(std::move(data)));
|
||||
if (!codec) {
|
||||
ERRORF(r, "Failed to create codec from %s", path);
|
||||
return;
|
||||
}
|
||||
|
||||
auto info = codec->getInfo();
|
||||
auto cs = codec->computeOutputColorSpace(info.colorType(), nullptr);
|
||||
if (!cs) {
|
||||
ERRORF(r, "%s should have a color space", path);
|
||||
return;
|
||||
}
|
||||
|
||||
auto expected = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
|
||||
SkColorSpace::kDCIP3_D65_Gamut);
|
||||
REPORTER_ASSERT(r, SkColorSpace::Equals(cs.get(), expected.get()));
|
||||
}
|
||||
|
||||
DEF_TEST(AndroidCodec_P3, r) {
|
||||
if (GetResourcePath().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* path = "images/purple-displayprofile.png";
|
||||
auto data = GetResourceAsData(path);
|
||||
if (!data) {
|
||||
ERRORF(r, "Missing file %s", path);
|
||||
return;
|
||||
}
|
||||
|
||||
auto codec = SkAndroidCodec::MakeFromCodec(SkCodec::MakeFromData(std::move(data)));
|
||||
if (!codec) {
|
||||
ERRORF(r, "Failed to create codec from %s", path);
|
||||
return;
|
||||
}
|
||||
|
||||
auto info = codec->getInfo();
|
||||
auto cs = codec->computeOutputColorSpace(info.colorType(), nullptr);
|
||||
if (!cs) {
|
||||
ERRORF(r, "%s should have a color space", path);
|
||||
return;
|
||||
}
|
||||
|
||||
REPORTER_ASSERT(r, !cs->isSRGB());
|
||||
REPORTER_ASSERT(r, cs->gammaCloseToSRGB());
|
||||
|
||||
const SkMatrix44* matrix = cs->toXYZD50();
|
||||
SkMatrix44 expected(SkMatrix44::kUninitialized_Constructor);
|
||||
static constexpr float kExpected[] = {
|
||||
0.426254272f, 0.369018555f, 0.168914795f,
|
||||
0.226013184f, 0.685974121f, 0.0880126953f,
|
||||
0.0116729736f, 0.0950927734f, 0.71812439f,
|
||||
};
|
||||
|
||||
expected.set3x3RowMajorf(kExpected);
|
||||
REPORTER_ASSERT(r, *matrix == expected);
|
||||
}
|
||||
|
||||
DEF_TEST(AndroidCodec_orientation, r) {
|
||||
if (GetResourcePath().isEmpty()) {
|
||||
return;
|
||||
|
@ -1608,6 +1608,25 @@ DEF_TEST(Codec_78329453, r) {
|
||||
}
|
||||
}
|
||||
|
||||
DEF_TEST(Codec_A8, r) {
|
||||
if (GetResourcePath().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char* file = "images/mandrill_cmyk.jpg";
|
||||
auto data = GetResourceAsData(file);
|
||||
if (!data) {
|
||||
ERRORF(r, "missing %s", file);
|
||||
return;
|
||||
}
|
||||
|
||||
auto codec = SkCodec::MakeFromData(std::move(data));
|
||||
auto info = codec->getInfo().makeColorType(kAlpha_8_SkColorType);
|
||||
SkBitmap bm;
|
||||
bm.allocPixels(info);
|
||||
REPORTER_ASSERT(r, codec->getPixels(bm.pixmap()) == SkCodec::kInvalidConversion);
|
||||
}
|
||||
|
||||
DEF_TEST(Codec_crbug807324, r) {
|
||||
if (GetResourcePath().isEmpty()) {
|
||||
return;
|
||||
|
42
tests/EncodedInfoTest.cpp
Normal file
42
tests/EncodedInfoTest.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "Resources.h"
|
||||
#include "Test.h"
|
||||
#include "sk_tool_utils.h"
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkCodec.h"
|
||||
#include "SkData.h"
|
||||
#include "SkEncodedImageFormat.h"
|
||||
#include "SkImageInfo.h"
|
||||
#include "SkImageEncoder.h"
|
||||
|
||||
DEF_TEST(AlphaEncodedInfo, r) {
|
||||
auto codec = SkCodec::MakeFromStream(GetResourceAsStream("images/grayscale.jpg"));
|
||||
REPORTER_ASSERT(r, codec->getInfo().colorType() == kGray_8_SkColorType);
|
||||
|
||||
SkBitmap bm;
|
||||
bm.allocPixels(codec->getInfo().makeColorType(kAlpha_8_SkColorType).makeColorSpace(nullptr));
|
||||
auto result = codec->getPixels(codec->getInfo(), bm.getPixels(), bm.rowBytes());
|
||||
REPORTER_ASSERT(r, result == SkCodec::kSuccess);
|
||||
|
||||
auto data = SkEncodeBitmap(bm, SkEncodedImageFormat::kPNG, 100);
|
||||
REPORTER_ASSERT(r, data);
|
||||
|
||||
codec = SkCodec::MakeFromData(std::move(data));
|
||||
REPORTER_ASSERT(r, codec);
|
||||
// TODO: Make SkEncodedInfo public and compare to its version of kAlpha_8.
|
||||
REPORTER_ASSERT(r, codec->getInfo().colorType() == kAlpha_8_SkColorType);
|
||||
|
||||
SkBitmap bm2;
|
||||
bm2.allocPixels(codec->getInfo().makeColorSpace(nullptr));
|
||||
result = codec->getPixels(bm2.pixmap());
|
||||
REPORTER_ASSERT(r, result == SkCodec::kSuccess);
|
||||
|
||||
REPORTER_ASSERT(r, sk_tool_utils::equal_pixels(bm.pixmap(), bm2.pixmap(), 0, true));
|
||||
}
|
Loading…
Reference in New Issue
Block a user