Switch SkCodec to use skcms
Bug: skia:6839 Bug: skia:8052 Create an skcms_Profile instead of an SkColorSpace when creating an SkCodec. Eventually we'll move the SkImageInfo (and its SkColorSpace) entirely to clients (e.g. SkAndroidCodec, SkCodecImageGenerator), but for now, create it with SkEncodedInfo::makeImageInfo. Create new SkEncodedInfo::Colors for the special PNG cases that we want to map to specific SkColorTypes. SkEncodedInfo: - Add ICCProfile, which owns an skcms_ICCProfile - FIXME: maybe we should have a single instance for SRGB like SkColorSpace? - Add kXAlpha_Color, for kAlpha_8. Since I'm not longer creating an SkImageInfo (at least in SkPngCodec), it needs a way to pass this info to the caller. - Add k565_Color, for the same reason. Matt originally had this in https://codereview.chromium.org/2212563003/#ps120001, but didn't land that version. I like it though. Mike didn't like the bits per component for 565, but it seems like a sensible hack, much like the existing one for kAlpha_8 - Add width and height. These were removed for redundancy with SkImageInfo, but it makes sense to have them here without it. BUILD.gn: - Build the new SkEncodedInfo.cpp SkCodec: - Remove the constructor with an SkImageInfo. Edit the other one to drop width and height (now in SkEncodedInfo) and take a RHS reference to SkEncodedInfo - Create the SkImageInfo from fEncodedInfo (for now) - Consolidate choosing skcms_AlphaFormat for Transform here - Call conversionSupported from initializeColorXform, with a new parameter for whether there is a color Xform, allowing SkJpegCodec and SkHeifCodec to override that method instead of having another method. SkBmpCodec (etc) - Adapt to the changes above - Create a new SkEncodedInfo w/o profile for the swizzler. SkPngCodec: - use the new SkEncodedInfo::Colors rather than a custom SkImageInfo SkRawCodec: - Remove SkEncodedInfo from SkDngImage, which doesn't actually need it. This is helpful since we don't know all the info yet. - Rewrite gAdobeRGB_toXYZD50 as an skcms_Matrix3x3 SkWebpCodec: - Remove premul_step computation, and simplify to just rely on the base class' handling of applying the transform. SkSwizzler: - Add cases for the new SkEncodedInfo::Colors TBR=reed@google.com No public API changes. Only private/public members of SkCodec.h are modified. Change-Id: Ic0d3bb752b03f13be886b80331987aa5a5713fc0 Reviewed-on: https://skia-review.googlesource.com/136062 Commit-Queue: Leon Scroggins <scroggo@google.com> Reviewed-by: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
82cf64a0d3
commit
81886e8f94
3
BUILD.gn
3
BUILD.gn
@ -863,6 +863,7 @@ component("skia") {
|
|||||||
"src/codec/SkCodec.cpp",
|
"src/codec/SkCodec.cpp",
|
||||||
"src/codec/SkCodecImageGenerator.cpp",
|
"src/codec/SkCodecImageGenerator.cpp",
|
||||||
"src/codec/SkColorTable.cpp",
|
"src/codec/SkColorTable.cpp",
|
||||||
|
"src/codec/SkEncodedInfo.cpp",
|
||||||
"src/codec/SkGifCodec.cpp",
|
"src/codec/SkGifCodec.cpp",
|
||||||
"src/codec/SkMaskSwizzler.cpp",
|
"src/codec/SkMaskSwizzler.cpp",
|
||||||
"src/codec/SkMasks.cpp",
|
"src/codec/SkMasks.cpp",
|
||||||
@ -2021,8 +2022,8 @@ if (skia_enable_tools) {
|
|||||||
"tools/viewer/SlideDir.cpp",
|
"tools/viewer/SlideDir.cpp",
|
||||||
"tools/viewer/StatsLayer.cpp",
|
"tools/viewer/StatsLayer.cpp",
|
||||||
"tools/viewer/SvgSlide.cpp",
|
"tools/viewer/SvgSlide.cpp",
|
||||||
"tools/viewer/TouchGesture.h",
|
|
||||||
"tools/viewer/TouchGesture.cpp",
|
"tools/viewer/TouchGesture.cpp",
|
||||||
|
"tools/viewer/TouchGesture.h",
|
||||||
"tools/viewer/Viewer.cpp",
|
"tools/viewer/Viewer.cpp",
|
||||||
]
|
]
|
||||||
libs = []
|
libs = []
|
||||||
|
@ -64,6 +64,7 @@ tests_sources = [
|
|||||||
"$_tests/EGLImageTest.cpp",
|
"$_tests/EGLImageTest.cpp",
|
||||||
"$_tests/EmptyPathTest.cpp",
|
"$_tests/EmptyPathTest.cpp",
|
||||||
"$_tests/EncodeTest.cpp",
|
"$_tests/EncodeTest.cpp",
|
||||||
|
"$_tests/EncodedInfoTest.cpp",
|
||||||
"$_tests/ExifTest.cpp",
|
"$_tests/ExifTest.cpp",
|
||||||
"$_tests/F16StagesTest.cpp",
|
"$_tests/F16StagesTest.cpp",
|
||||||
"$_tests/FillPathTest.cpp",
|
"$_tests/FillPathTest.cpp",
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "../private/SkEncodedInfo.h"
|
#include "../private/SkEncodedInfo.h"
|
||||||
#include "SkCodecAnimation.h"
|
#include "SkCodecAnimation.h"
|
||||||
#include "SkColor.h"
|
#include "SkColor.h"
|
||||||
#include "SkColorSpaceXform.h"
|
|
||||||
#include "SkEncodedImageFormat.h"
|
#include "SkEncodedImageFormat.h"
|
||||||
#include "SkEncodedOrigin.h"
|
#include "SkEncodedOrigin.h"
|
||||||
#include "SkImageInfo.h"
|
#include "SkImageInfo.h"
|
||||||
@ -671,21 +670,9 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; }
|
const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; }
|
||||||
|
|
||||||
using XformFormat = SkColorSpaceXform::ColorFormat;
|
using XformFormat = skcms_PixelFormat;
|
||||||
|
|
||||||
SkCodec(int width,
|
SkCodec(SkEncodedInfo&&,
|
||||||
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&,
|
|
||||||
XformFormat srcFormat,
|
XformFormat srcFormat,
|
||||||
std::unique_ptr<SkStream>,
|
std::unique_ptr<SkStream>,
|
||||||
SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
|
SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
|
||||||
@ -780,16 +767,14 @@ protected:
|
|||||||
|
|
||||||
virtual int onOutputScanline(int inputScanline) const;
|
virtual int onOutputScanline(int inputScanline) const;
|
||||||
|
|
||||||
bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha);
|
|
||||||
// Some classes never need a colorXform e.g.
|
// Some classes never need a colorXform e.g.
|
||||||
// - ICO uses its embedded codec's colorXform
|
// - ICO uses its embedded codec's colorXform
|
||||||
// - WBMP is just Black/White
|
// - WBMP is just Black/White
|
||||||
virtual bool usesColorXform() const { return true; }
|
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;
|
void applyColorXform(void* dst, const void* src, int count) const;
|
||||||
|
|
||||||
SkColorSpaceXform* colorXform() const { return fColorXform.get(); }
|
bool colorXform() const { return fXformTime != kNo_XformTime; }
|
||||||
bool xformOnDecode() const { return fXformOnDecode; }
|
bool xformOnDecode() const { return fXformTime == kDecodeRow_XformTime; }
|
||||||
|
|
||||||
virtual int onGetFrameCount() {
|
virtual int onGetFrameCount() {
|
||||||
return 1;
|
return 1;
|
||||||
@ -813,9 +798,16 @@ private:
|
|||||||
|
|
||||||
SkImageInfo fDstInfo;
|
SkImageInfo fDstInfo;
|
||||||
Options fOptions;
|
Options fOptions;
|
||||||
|
|
||||||
|
enum XformTime {
|
||||||
|
kNo_XformTime,
|
||||||
|
kPalette_XformTime,
|
||||||
|
kDecodeRow_XformTime,
|
||||||
|
};
|
||||||
|
XformTime fXformTime;
|
||||||
XformFormat fDstXformFormat; // Based on fDstInfo.
|
XformFormat fDstXformFormat; // Based on fDstInfo.
|
||||||
std::unique_ptr<SkColorSpaceXform> fColorXform;
|
skcms_ICCProfile fDstProfile;
|
||||||
bool fXformOnDecode;
|
skcms_AlphaFormat fDstXformAlphaFormat;
|
||||||
|
|
||||||
// Only meaningful during scanline decodes.
|
// Only meaningful during scanline decodes.
|
||||||
int fCurrScanline;
|
int fCurrScanline;
|
||||||
@ -823,12 +815,15 @@ private:
|
|||||||
bool fStartedIncrementalDecode;
|
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.
|
* Will be called for the appropriate frame, prior to initializing the colorXform.
|
||||||
*/
|
*/
|
||||||
virtual bool conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
|
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.
|
* Return whether these dimensions are supported as a scale.
|
||||||
*
|
*
|
||||||
|
@ -8,12 +8,25 @@
|
|||||||
#ifndef SkEncodedInfo_DEFINED
|
#ifndef SkEncodedInfo_DEFINED
|
||||||
#define SkEncodedInfo_DEFINED
|
#define SkEncodedInfo_DEFINED
|
||||||
|
|
||||||
|
#include "SkData.h"
|
||||||
#include "SkImageInfo.h"
|
#include "SkImageInfo.h"
|
||||||
|
#include "../../third_party/skcms/skcms.h"
|
||||||
class SkColorSpace;
|
|
||||||
|
|
||||||
struct SkEncodedInfo {
|
struct SkEncodedInfo {
|
||||||
public:
|
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 {
|
enum Alpha {
|
||||||
kOpaque_Alpha,
|
kOpaque_Alpha,
|
||||||
@ -39,6 +52,20 @@ public:
|
|||||||
// PNG
|
// PNG
|
||||||
kGrayAlpha_Color,
|
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
|
// PNG, GIF, BMP
|
||||||
kPalette_Color,
|
kPalette_Color,
|
||||||
|
|
||||||
@ -67,7 +94,18 @@ public:
|
|||||||
kYCCK_Color,
|
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 ||
|
SkASSERT(1 == bitsPerComponent ||
|
||||||
2 == bitsPerComponent ||
|
2 == bitsPerComponent ||
|
||||||
4 == bitsPerComponent ||
|
4 == bitsPerComponent ||
|
||||||
@ -105,29 +143,51 @@ public:
|
|||||||
SkASSERT(kOpaque_Alpha != alpha);
|
SkASSERT(kOpaque_Alpha != alpha);
|
||||||
SkASSERT(8 == bitsPerComponent);
|
SkASSERT(8 == bitsPerComponent);
|
||||||
break;
|
break;
|
||||||
|
case kXAlpha_Color:
|
||||||
|
SkASSERT(kUnpremul_Alpha == alpha);
|
||||||
|
SkASSERT(8 == bitsPerComponent);
|
||||||
|
break;
|
||||||
|
case k565_Color:
|
||||||
|
SkASSERT(kOpaque_Alpha == alpha);
|
||||||
|
SkASSERT(8 == bitsPerComponent);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
SkASSERT(false);
|
SkASSERT(false);
|
||||||
break;
|
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
|
* Returns a recommended SkImageInfo.
|
||||||
* closest possible match to the encoded info.
|
*
|
||||||
|
* TODO: Leave this up to the client.
|
||||||
*/
|
*/
|
||||||
SkImageInfo makeImageInfo(int width, int height, sk_sp<SkColorSpace> colorSpace) const {
|
SkImageInfo makeImageInfo() const {
|
||||||
auto ct = kGray_Color == fColor ? kGray_8_SkColorType :
|
auto ct = kGray_Color == fColor ? kGray_8_SkColorType :
|
||||||
|
kXAlpha_Color == fColor ? kAlpha_8_SkColorType :
|
||||||
|
k565_Color == fColor ? kRGB_565_SkColorType :
|
||||||
kN32_SkColorType ;
|
kN32_SkColorType ;
|
||||||
auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType
|
auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType
|
||||||
: kUnpremul_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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int width() const { return fWidth; }
|
||||||
|
int height() const { return fHeight; }
|
||||||
Color color() const { return fColor; }
|
Color color() const { return fColor; }
|
||||||
Alpha alpha() const { return fAlpha; }
|
Alpha alpha() const { return fAlpha; }
|
||||||
bool opaque() const { return fAlpha == kOpaque_Alpha; }
|
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; }
|
uint8_t bitsPerComponent() const { return fBitsPerComponent; }
|
||||||
|
|
||||||
@ -135,6 +195,7 @@ public:
|
|||||||
switch (fColor) {
|
switch (fColor) {
|
||||||
case kGray_Color:
|
case kGray_Color:
|
||||||
return fBitsPerComponent;
|
return fBitsPerComponent;
|
||||||
|
case kXAlpha_Color:
|
||||||
case kGrayAlpha_Color:
|
case kGrayAlpha_Color:
|
||||||
return 2 * fBitsPerComponent;
|
return 2 * fBitsPerComponent;
|
||||||
case kPalette_Color:
|
case kPalette_Color:
|
||||||
@ -142,6 +203,7 @@ public:
|
|||||||
case kRGB_Color:
|
case kRGB_Color:
|
||||||
case kBGR_Color:
|
case kBGR_Color:
|
||||||
case kYUV_Color:
|
case kYUV_Color:
|
||||||
|
case k565_Color:
|
||||||
return 3 * fBitsPerComponent;
|
return 3 * fBitsPerComponent;
|
||||||
case kRGBA_Color:
|
case kRGBA_Color:
|
||||||
case kBGRA_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)
|
SkEncodedInfo(SkEncodedInfo&& orig) = default;
|
||||||
: fColor(color)
|
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)
|
, fAlpha(alpha)
|
||||||
, fBitsPerComponent(bitsPerComponent)
|
, fBitsPerComponent(bitsPerComponent)
|
||||||
|
, fProfile(std::move(profile))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
int fWidth;
|
||||||
|
int fHeight;
|
||||||
Color fColor;
|
Color fColor;
|
||||||
Alpha fAlpha;
|
Alpha fAlpha;
|
||||||
uint8_t fBitsPerComponent;
|
uint8_t fBitsPerComponent;
|
||||||
|
std::unique_ptr<ICCProfile> fProfile;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#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 |
@ -9,9 +9,8 @@
|
|||||||
|
|
||||||
SkBmpBaseCodec::~SkBmpBaseCodec() {}
|
SkBmpBaseCodec::~SkBmpBaseCodec() {}
|
||||||
|
|
||||||
SkBmpBaseCodec::SkBmpBaseCodec(int width, int height, const SkEncodedInfo& info,
|
SkBmpBaseCodec::SkBmpBaseCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||||
std::unique_ptr<SkStream> stream,
|
|
||||||
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
|
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()))
|
, fSrcBuffer(sk_malloc_canfail(this->srcRowBytes()))
|
||||||
{}
|
{}
|
||||||
|
@ -25,7 +25,7 @@ public:
|
|||||||
bool didCreateSrcBuffer() const { return fSrcBuffer != nullptr; }
|
bool didCreateSrcBuffer() const { return fSrcBuffer != nullptr; }
|
||||||
|
|
||||||
protected:
|
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);
|
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder);
|
||||||
|
|
||||||
uint8_t* srcBuffer() { return reinterpret_cast<uint8_t*>(fSrcBuffer.get()); }
|
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());
|
SkASSERT(!inIco || nullptr != stream->getMemoryBase());
|
||||||
|
|
||||||
// Set the image info and create a codec.
|
// Set the image info and create a codec.
|
||||||
const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, bitsPerComponent);
|
auto info = SkEncodedInfo::MakeSRGB(width, height, color, alpha, bitsPerComponent);
|
||||||
codecOut->reset(new SkBmpStandardCodec(width, height, info,
|
codecOut->reset(new SkBmpStandardCodec(std::move(info),
|
||||||
std::unique_ptr<SkStream>(stream),
|
std::unique_ptr<SkStream>(stream),
|
||||||
bitsPerPixel, numColors, bytesPerColor,
|
bitsPerPixel, numColors, bytesPerColor,
|
||||||
offset - bytesRead, rowOrder, isOpaque,
|
offset - bytesRead, rowOrder, isOpaque,
|
||||||
@ -539,8 +539,8 @@ SkCodec::Result SkBmpCodec::ReadHeader(SkStream* stream, bool inIco,
|
|||||||
color = SkEncodedInfo::kBGR_Color;
|
color = SkEncodedInfo::kBGR_Color;
|
||||||
alpha = SkEncodedInfo::kOpaque_Alpha;
|
alpha = SkEncodedInfo::kOpaque_Alpha;
|
||||||
}
|
}
|
||||||
const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8);
|
auto info = SkEncodedInfo::MakeSRGB(width, height, color, alpha, 8);
|
||||||
codecOut->reset(new SkBmpMaskCodec(width, height, info,
|
codecOut->reset(new SkBmpMaskCodec(std::move(info),
|
||||||
std::unique_ptr<SkStream>(stream), bitsPerPixel,
|
std::unique_ptr<SkStream>(stream), bitsPerPixel,
|
||||||
masks.release(), rowOrder));
|
masks.release(), rowOrder));
|
||||||
return static_cast<SkBmpMaskCodec*>(codecOut->get())->didCreateSrcBuffer()
|
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
|
// 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.
|
// opaque or that we will be able to represent it with a palette.
|
||||||
// For that reason, we always indicate that we are kBGRA.
|
// For that reason, we always indicate that we are kBGRA.
|
||||||
const SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kBGRA_Color,
|
auto info = SkEncodedInfo::MakeSRGB(width, height, SkEncodedInfo::kBGRA_Color,
|
||||||
SkEncodedInfo::kBinary_Alpha, 8);
|
SkEncodedInfo::kBinary_Alpha, 8);
|
||||||
codecOut->reset(new SkBmpRLECodec(width, height, info,
|
codecOut->reset(new SkBmpRLECodec(std::move(info),
|
||||||
std::unique_ptr<SkStream>(stream), bitsPerPixel,
|
std::unique_ptr<SkStream>(stream), bitsPerPixel,
|
||||||
numColors, bytesPerColor, offset - bytesRead,
|
numColors, bytesPerColor, offset - bytesRead,
|
||||||
rowOrder));
|
rowOrder));
|
||||||
@ -600,14 +600,12 @@ std::unique_ptr<SkCodec> SkBmpCodec::MakeFromStream(std::unique_ptr<SkStream> st
|
|||||||
return kSuccess == *result ? std::move(codec) : nullptr;
|
return kSuccess == *result ? std::move(codec) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkBmpCodec::SkBmpCodec(int width, int height, const SkEncodedInfo& info,
|
SkBmpCodec::SkBmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||||
std::unique_ptr<SkStream> stream,
|
|
||||||
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
|
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
|
||||||
: INHERITED(width, height, info, kXformSrcColorFormat, std::move(stream),
|
: INHERITED(std::move(info), kXformSrcColorFormat, std::move(stream))
|
||||||
SkColorSpace::MakeSRGB())
|
|
||||||
, fBitsPerPixel(bitsPerPixel)
|
, fBitsPerPixel(bitsPerPixel)
|
||||||
, fRowOrder(rowOrder)
|
, fRowOrder(rowOrder)
|
||||||
, fSrcRowBytes(SkAlign4(compute_row_bytes(width, fBitsPerPixel)))
|
, fSrcRowBytes(SkAlign4(compute_row_bytes(this->getEncodedInfo().width(), fBitsPerPixel)))
|
||||||
, fXformBuffer(nullptr)
|
, fXformBuffer(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
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);
|
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder);
|
||||||
|
|
||||||
SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kBMP; }
|
SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kBMP; }
|
||||||
@ -103,7 +103,7 @@ protected:
|
|||||||
* than RGBA.
|
* than RGBA.
|
||||||
*/
|
*/
|
||||||
static constexpr SkColorType kXformSrcColorType = kBGRA_8888_SkColorType;
|
static constexpr SkColorType kXformSrcColorType = kBGRA_8888_SkColorType;
|
||||||
static constexpr auto kXformSrcColorFormat = SkColorSpaceXform::kBGRA_8888_ColorFormat;
|
static constexpr auto kXformSrcColorFormat = skcms_PixelFormat_BGRA_8888;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -12,11 +12,11 @@
|
|||||||
/*
|
/*
|
||||||
* Creates an instance of the decoder
|
* Creates an instance of the decoder
|
||||||
*/
|
*/
|
||||||
SkBmpMaskCodec::SkBmpMaskCodec(int width, int height, const SkEncodedInfo& info,
|
SkBmpMaskCodec::SkBmpMaskCodec(SkEncodedInfo&& info,
|
||||||
std::unique_ptr<SkStream> stream,
|
std::unique_ptr<SkStream> stream,
|
||||||
uint16_t bitsPerPixel, SkMasks* masks,
|
uint16_t bitsPerPixel, SkMasks* masks,
|
||||||
SkCodec::SkScanlineOrder rowOrder)
|
SkCodec::SkScanlineOrder rowOrder)
|
||||||
: INHERITED(width, height, info, std::move(stream), bitsPerPixel, rowOrder)
|
: INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
|
||||||
, fMasks(masks)
|
, fMasks(masks)
|
||||||
, fMaskSwizzler(nullptr)
|
, fMaskSwizzler(nullptr)
|
||||||
{}
|
{}
|
||||||
|
@ -31,7 +31,7 @@ public:
|
|||||||
* @param masks color masks for certain bmp formats
|
* @param masks color masks for certain bmp formats
|
||||||
* @param rowOrder indicates whether rows are ordered top-down or bottom-up
|
* @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,
|
uint16_t bitsPerPixel, SkMasks* masks,
|
||||||
SkCodec::SkScanlineOrder rowOrder);
|
SkCodec::SkScanlineOrder rowOrder);
|
||||||
|
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
* Creates an instance of the decoder
|
* Creates an instance of the decoder
|
||||||
* Called only by NewFromStream
|
* Called only by NewFromStream
|
||||||
*/
|
*/
|
||||||
SkBmpRLECodec::SkBmpRLECodec(int width, int height, const SkEncodedInfo& info,
|
SkBmpRLECodec::SkBmpRLECodec(SkEncodedInfo&& info,
|
||||||
std::unique_ptr<SkStream> stream,
|
std::unique_ptr<SkStream> stream,
|
||||||
uint16_t bitsPerPixel, uint32_t numColors,
|
uint16_t bitsPerPixel, uint32_t numColors,
|
||||||
uint32_t bytesPerColor, uint32_t offset,
|
uint32_t bytesPerColor, uint32_t offset,
|
||||||
SkCodec::SkScanlineOrder rowOrder)
|
SkCodec::SkScanlineOrder rowOrder)
|
||||||
: INHERITED(width, height, info, std::move(stream), bitsPerPixel, rowOrder)
|
: INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
|
||||||
, fColorTable(nullptr)
|
, fColorTable(nullptr)
|
||||||
, fNumColors(numColors)
|
, fNumColors(numColors)
|
||||||
, fBytesPerColor(bytesPerColor)
|
, fBytesPerColor(bytesPerColor)
|
||||||
|
@ -35,7 +35,7 @@ public:
|
|||||||
* headers
|
* headers
|
||||||
* @param rowOrder indicates whether rows are ordered top-down or bottom-up
|
* @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,
|
uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor,
|
||||||
uint32_t offset, SkCodec::SkScanlineOrder rowOrder);
|
uint32_t offset, SkCodec::SkScanlineOrder rowOrder);
|
||||||
|
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
* Creates an instance of the decoder
|
* Creates an instance of the decoder
|
||||||
* Called only by NewFromStream
|
* Called only by NewFromStream
|
||||||
*/
|
*/
|
||||||
SkBmpStandardCodec::SkBmpStandardCodec(int width, int height, const SkEncodedInfo& info,
|
SkBmpStandardCodec::SkBmpStandardCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||||
std::unique_ptr<SkStream> stream, uint16_t bitsPerPixel,
|
uint16_t bitsPerPixel, uint32_t numColors,
|
||||||
uint32_t numColors, uint32_t bytesPerColor, uint32_t offset,
|
uint32_t bytesPerColor, uint32_t offset,
|
||||||
SkCodec::SkScanlineOrder rowOrder,
|
SkCodec::SkScanlineOrder rowOrder,
|
||||||
bool isOpaque, bool inIco)
|
bool isOpaque, bool inIco)
|
||||||
: INHERITED(width, height, info, std::move(stream), bitsPerPixel, rowOrder)
|
: INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
|
||||||
, fColorTable(nullptr)
|
, fColorTable(nullptr)
|
||||||
, fNumColors(numColors)
|
, fNumColors(numColors)
|
||||||
, fBytesPerColor(bytesPerColor)
|
, fBytesPerColor(bytesPerColor)
|
||||||
@ -146,20 +146,33 @@ SkCodec::Result SkBmpStandardCodec::onGetPixels(const SkImageInfo& dstInfo,
|
|||||||
return true;
|
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) {
|
void SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) {
|
||||||
// In the case of bmp-in-icos, we will report BGRA to the client,
|
// 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.
|
// 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.
|
// However, the swizzler needs to know the actual format of the bmp.
|
||||||
SkEncodedInfo encodedInfo = this->getEncodedInfo();
|
SkEncodedInfo encodedInfo = this->swizzlerInfo();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a pointer to the color table if it exists
|
// Get a pointer to the color table if it exists
|
||||||
const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
|
const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
|
||||||
|
@ -39,9 +39,9 @@ public:
|
|||||||
* the icp mask, if there is one)
|
* the icp mask, if there is one)
|
||||||
* @param inIco indicates if the bmp is embedded in an ico file
|
* @param inIco indicates if the bmp is embedded in an ico file
|
||||||
*/
|
*/
|
||||||
SkBmpStandardCodec(int width, int height, const SkEncodedInfo& info,
|
SkBmpStandardCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||||
std::unique_ptr<SkStream> stream, uint16_t bitsPerPixel, uint32_t numColors,
|
uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor,
|
||||||
uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder,
|
uint32_t offset, SkCodec::SkScanlineOrder rowOrder,
|
||||||
bool isOpaque, bool inIco);
|
bool isOpaque, bool inIco);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -63,12 +63,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates the color table
|
|
||||||
*/
|
|
||||||
bool createColorTable(SkColorType colorType, SkAlphaType alphaType);
|
bool createColorTable(SkColorType colorType, SkAlphaType alphaType);
|
||||||
|
SkEncodedInfo swizzlerInfo() const;
|
||||||
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts);
|
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts);
|
||||||
|
|
||||||
int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
|
int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "SkCodec.h"
|
#include "SkCodec.h"
|
||||||
#include "SkCodecPriv.h"
|
#include "SkCodecPriv.h"
|
||||||
#include "SkColorSpace.h"
|
#include "SkColorSpace.h"
|
||||||
#include "SkColorSpaceXformPriv.h"
|
|
||||||
#include "SkData.h"
|
#include "SkData.h"
|
||||||
#include "SkFrameHolder.h"
|
#include "SkFrameHolder.h"
|
||||||
#include "SkGifCodec.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);
|
return MakeFromStream(SkMemoryStream::Make(std::move(data)), nullptr, reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
SkCodec::SkCodec(int width, int height, const SkEncodedInfo& info,
|
SkCodec::SkCodec(SkEncodedInfo&& info, XformFormat srcFormat, std::unique_ptr<SkStream> stream,
|
||||||
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)
|
SkEncodedOrigin origin)
|
||||||
: fEncodedInfo(info)
|
: fEncodedInfo(std::move(info))
|
||||||
, fSrcInfo(imageInfo)
|
, fSrcInfo(fEncodedInfo.makeImageInfo())
|
||||||
, fSrcXformFormat(srcFormat)
|
, fSrcXformFormat(srcFormat)
|
||||||
, fStream(std::move(stream))
|
, fStream(std::move(stream))
|
||||||
, fNeedsRewind(false)
|
, fNeedsRewind(false)
|
||||||
@ -159,7 +142,7 @@ SkCodec::SkCodec(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
|
|||||||
SkCodec::~SkCodec() {}
|
SkCodec::~SkCodec() {}
|
||||||
|
|
||||||
bool SkCodec::conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
|
bool SkCodec::conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
|
||||||
bool srcIsOpaque, const SkColorSpace* srcCS) const {
|
bool srcIsOpaque, bool needsColorXform) {
|
||||||
if (!valid_alpha(dst.alphaType(), srcIsOpaque)) {
|
if (!valid_alpha(dst.alphaType(), srcIsOpaque)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -173,8 +156,8 @@ bool SkCodec::conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
|
|||||||
case kRGB_565_SkColorType:
|
case kRGB_565_SkColorType:
|
||||||
return srcIsOpaque;
|
return srcIsOpaque;
|
||||||
case kGray_8_SkColorType:
|
case kGray_8_SkColorType:
|
||||||
return kGray_8_SkColorType == srcColor && srcIsOpaque &&
|
SkASSERT(!needsColorXform);
|
||||||
!needs_color_xform(dst, srcCS);
|
return kGray_8_SkColorType == srcColor && srcIsOpaque;
|
||||||
case kAlpha_8_SkColorType:
|
case kAlpha_8_SkColorType:
|
||||||
// conceptually we can convert anything into alpha_8, but we haven't actually coded
|
// 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.
|
// 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:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkCodec::rewindIfNeeded() {
|
bool SkCodec::rewindIfNeeded() {
|
||||||
@ -245,13 +227,8 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels,
|
|||||||
const Options& options) {
|
const Options& options) {
|
||||||
const int index = options.fFrameIndex;
|
const int index = options.fFrameIndex;
|
||||||
if (0 == index) {
|
if (0 == index) {
|
||||||
if (!this->conversionSupported(info, fSrcInfo.colorType(), fEncodedInfo.opaque(),
|
return this->initializeColorXform(info, fEncodedInfo.alpha(), fEncodedInfo.opaque())
|
||||||
fSrcInfo.colorSpace())
|
? kSuccess : kInvalidConversion;
|
||||||
|| !this->initializeColorXform(info, fEncodedInfo.alpha()))
|
|
||||||
{
|
|
||||||
return kInvalidConversion;
|
|
||||||
}
|
|
||||||
return kSuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
@ -274,11 +251,6 @@ SkCodec::Result SkCodec::handleFrameIndex(const SkImageInfo& info, void* pixels,
|
|||||||
const auto* frame = frameHolder->getFrame(index);
|
const auto* frame = frameHolder->getFrame(index);
|
||||||
SkASSERT(frame);
|
SkASSERT(frame);
|
||||||
|
|
||||||
if (!this->conversionSupported(info, fSrcInfo.colorType(), !frame->hasAlpha(),
|
|
||||||
fSrcInfo.colorSpace())) {
|
|
||||||
return kInvalidConversion;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int requiredFrame = frame->getRequiredFrame();
|
const int requiredFrame = frame->getRequiredFrame();
|
||||||
if (requiredFrame != kNoFrame) {
|
if (requiredFrame != kNoFrame) {
|
||||||
if (options.fPriorFrame != 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,
|
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) {
|
switch (colorType) {
|
||||||
case kRGBA_8888_SkColorType:
|
case kRGBA_8888_SkColorType:
|
||||||
return SkColorSpaceXform::kRGBA_8888_ColorFormat;
|
*outFormat = skcms_PixelFormat_RGBA_8888;
|
||||||
|
break;
|
||||||
case kBGRA_8888_SkColorType:
|
case kBGRA_8888_SkColorType:
|
||||||
return SkColorSpaceXform::kBGRA_8888_ColorFormat;
|
*outFormat = skcms_PixelFormat_BGRA_8888;
|
||||||
|
break;
|
||||||
case kRGB_565_SkColorType:
|
case kRGB_565_SkColorType:
|
||||||
|
if (forColorTable) {
|
||||||
#ifdef SK_PMCOLOR_IS_RGBA
|
#ifdef SK_PMCOLOR_IS_RGBA
|
||||||
return SkColorSpaceXform::kRGBA_8888_ColorFormat;
|
*outFormat = skcms_PixelFormat_RGBA_8888;
|
||||||
#else
|
#else
|
||||||
return SkColorSpaceXform::kBGRA_8888_ColorFormat;
|
*outFormat = skcms_PixelFormat_BGRA_8888;
|
||||||
#endif
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*outFormat = skcms_PixelFormat_BGR_565;
|
||||||
|
break;
|
||||||
|
case kRGBA_F16_SkColorType:
|
||||||
|
*outFormat = skcms_PixelFormat_RGBA_hhhh;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
SkASSERT(false);
|
return false;
|
||||||
return SkColorSpaceXform::kRGBA_8888_ColorFormat;
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha encodedAlpha) {
|
if (!this->conversionSupported(dstInfo, fSrcInfo.colorType(), srcIsOpaque, needsColorXform)) {
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We will apply the color xform when reading the color table unless F16 is requested.
|
if (needsColorXform) {
|
||||||
fXformOnDecode = SkEncodedInfo::kPalette_Color != fEncodedInfo.color()
|
fXformTime = SkEncodedInfo::kPalette_Color != fEncodedInfo.color()
|
||||||
|| kRGBA_F16_SkColorType == dstInfo.colorType();
|
|| kRGBA_F16_SkColorType == dstInfo.colorType()
|
||||||
if (fXformOnDecode) {
|
? kDecodeRow_XformTime : kPalette_XformTime;
|
||||||
fDstXformFormat = select_xform_format(dstInfo.colorType());
|
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 {
|
} else {
|
||||||
fDstXformFormat = select_xform_format_ct(dstInfo.colorType());
|
fDstXformAlphaFormat = skcms_AlphaFormat_Unpremul;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkCodec::applyColorXform(void* dst, const void* src, int count) const {
|
void SkCodec::applyColorXform(void* dst, const void* src, int count) const {
|
||||||
auto alphaType = select_xform_alpha(fDstInfo.alphaType(), fSrcInfo.alphaType());
|
const auto* srcProfile = fEncodedInfo.profile();
|
||||||
this->applyColorXform(dst, src, count, alphaType);
|
SkASSERT(srcProfile);
|
||||||
|
SkAssertResult(skcms_Transform(src, fSrcXformFormat, skcms_AlphaFormat_Unpremul, srcProfile,
|
||||||
|
dst, fDstXformFormat, fDstXformAlphaFormat, &fDstProfile,
|
||||||
|
count));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<SkCodec::FrameInfo> SkCodec::getFrameInfo() {
|
std::vector<SkCodec::FrameInfo> SkCodec::getFrameInfo() {
|
||||||
|
@ -9,8 +9,6 @@
|
|||||||
#define SkCodecPriv_DEFINED
|
#define SkCodecPriv_DEFINED
|
||||||
|
|
||||||
#include "SkColorData.h"
|
#include "SkColorData.h"
|
||||||
#include "SkColorSpaceXform.h"
|
|
||||||
#include "SkColorSpaceXformPriv.h"
|
|
||||||
#include "SkColorTable.h"
|
#include "SkColorTable.h"
|
||||||
#include "SkEncodedInfo.h"
|
#include "SkEncodedInfo.h"
|
||||||
#include "SkEncodedOrigin.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);
|
bool is_orientation_marker(const uint8_t* data, size_t data_length, SkEncodedOrigin* orientation);
|
||||||
|
|
||||||
#endif // SkCodecPriv_DEFINED
|
#endif // SkCodecPriv_DEFINED
|
||||||
|
@ -5,4 +5,28 @@
|
|||||||
* found in the LICENSE file.
|
* 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.
|
// 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
|
// 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.
|
// expanding to 8 bits and take advantage of the SkSwizzler to work from 4.
|
||||||
const auto encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8);
|
auto encodedInfo = SkEncodedInfo::MakeSRGB(reader->screenWidth(), reader->screenHeight(),
|
||||||
|
SkEncodedInfo::kPalette_Color, alpha, 8);
|
||||||
// The choice of unpremul versus premul is arbitrary, since all colors are either fully
|
return std::unique_ptr<SkCodec>(new SkGifCodec(std::move(encodedInfo), reader.release()));
|
||||||
// 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()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkGifCodec::onRewind() {
|
bool SkGifCodec::onRewind() {
|
||||||
@ -110,9 +101,8 @@ bool SkGifCodec::onRewind() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkGifCodec::SkGifCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
|
SkGifCodec::SkGifCodec(SkEncodedInfo&& encodedInfo, SkGifImageReader* reader)
|
||||||
SkGifImageReader* reader)
|
: INHERITED(std::move(encodedInfo), skcms_PixelFormat_RGBA_8888, nullptr)
|
||||||
: INHERITED(encodedInfo, imageInfo, SkColorSpaceXform::kRGBA_8888_ColorFormat, nullptr)
|
|
||||||
, fReader(reader)
|
, fReader(reader)
|
||||||
, fTmpBuffer(nullptr)
|
, fTmpBuffer(nullptr)
|
||||||
, fSwizzler(nullptr)
|
, fSwizzler(nullptr)
|
||||||
@ -157,7 +147,6 @@ int SkGifCodec::onGetRepetitionCount() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static constexpr SkColorType kXformSrcColorType = kRGBA_8888_SkColorType;
|
static constexpr SkColorType kXformSrcColorType = kRGBA_8888_SkColorType;
|
||||||
static constexpr SkAlphaType kXformAlphaType = kUnpremul_SkAlphaType;
|
|
||||||
|
|
||||||
void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, int frameIndex) {
|
void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, int frameIndex) {
|
||||||
SkColorType colorTableColorType = dstInfo.colorType();
|
SkColorType colorTableColorType = dstInfo.colorType();
|
||||||
@ -173,8 +162,8 @@ void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, int frameIndex
|
|||||||
fCurrColorTable.reset(new SkColorTable(&color, 1));
|
fCurrColorTable.reset(new SkColorTable(&color, 1));
|
||||||
} else if (this->colorXform() && !this->xformOnDecode()) {
|
} else if (this->colorXform() && !this->xformOnDecode()) {
|
||||||
SkPMColor dstColors[256];
|
SkPMColor dstColors[256];
|
||||||
this->applyColorXform(dstColors, currColorTable->readColors(), currColorTable->count(),
|
this->applyColorXform(dstColors, currColorTable->readColors(),
|
||||||
kXformAlphaType);
|
currColorTable->count());
|
||||||
fCurrColorTable.reset(new SkColorTable(dstColors, currColorTable->count()));
|
fCurrColorTable.reset(new SkColorTable(dstColors, currColorTable->count()));
|
||||||
} else {
|
} else {
|
||||||
fCurrColorTable = std::move(currColorTable);
|
fCurrColorTable = std::move(currColorTable);
|
||||||
@ -402,7 +391,7 @@ void SkGifCodec::applyXformRow(const SkImageInfo& dstInfo, void* dst, const uint
|
|||||||
fSwizzler->swizzle(fXformBuffer.get(), src);
|
fSwizzler->swizzle(fXformBuffer.get(), src);
|
||||||
|
|
||||||
const int xformWidth = get_scaled_dimension(dstInfo.width(), fSwizzler->sampleX());
|
const int xformWidth = get_scaled_dimension(dstInfo.width(), fSwizzler->sampleX());
|
||||||
this->applyColorXform(dst, fXformBuffer.get(), xformWidth, kXformAlphaType);
|
this->applyColorXform(dst, fXformBuffer.get(), xformWidth);
|
||||||
} else {
|
} else {
|
||||||
fSwizzler->swizzle(dst, src);
|
fSwizzler->swizzle(dst, src);
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ private:
|
|||||||
* Called only by NewFromStream
|
* Called only by NewFromStream
|
||||||
* Takes ownership of the SkGifImageReader
|
* Takes ownership of the SkGifImageReader
|
||||||
*/
|
*/
|
||||||
SkGifCodec(const SkEncodedInfo&, const SkImageInfo&, SkGifImageReader*);
|
SkGifCodec(SkEncodedInfo&&, SkGifImageReader*);
|
||||||
|
|
||||||
std::unique_ptr<SkGifImageReader> fReader;
|
std::unique_ptr<SkGifImageReader> fReader;
|
||||||
std::unique_ptr<uint8_t[]> fTmpBuffer;
|
std::unique_ptr<uint8_t[]> fTmpBuffer;
|
||||||
|
@ -133,40 +133,37 @@ std::unique_ptr<SkCodec> SkHeifCodec::MakeFromStream(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkEncodedInfo info = SkEncodedInfo::Make(
|
std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
|
||||||
SkEncodedInfo::kYUV_Color, SkEncodedInfo::kOpaque_Alpha, 8);
|
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);
|
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;
|
*result = kSuccess;
|
||||||
return std::unique_ptr<SkCodec>(new SkHeifCodec(frameInfo.mWidth, frameInfo.mHeight,
|
return std::unique_ptr<SkCodec>(new SkHeifCodec(std::move(info), heifDecoder.release(),
|
||||||
info, heifDecoder.release(), std::move(colorSpace), orientation));
|
orientation));
|
||||||
}
|
}
|
||||||
|
|
||||||
SkHeifCodec::SkHeifCodec(int width, int height, const SkEncodedInfo& info,
|
SkHeifCodec::SkHeifCodec(SkEncodedInfo&& info, HeifDecoder* heifDecoder, SkEncodedOrigin origin)
|
||||||
HeifDecoder* heifDecoder, sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin)
|
: INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, nullptr, origin)
|
||||||
: INHERITED(width, height, info, SkColorSpaceXform::kRGBA_8888_ColorFormat,
|
|
||||||
nullptr, std::move(colorSpace), origin)
|
|
||||||
, fHeifDecoder(heifDecoder)
|
, fHeifDecoder(heifDecoder)
|
||||||
, fSwizzleSrcRow(nullptr)
|
, fSwizzleSrcRow(nullptr)
|
||||||
, fColorXformSrcRow(nullptr)
|
, fColorXformSrcRow(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/*
|
|
||||||
* Checks if the conversion between the input image and the requested output
|
bool SkHeifCodec::conversionSupported(const SkImageInfo& dstInfo, SkColorType /*srcColorType*/,
|
||||||
* image has been implemented
|
bool srcIsOpaque, bool needsColorXform) {
|
||||||
* Sets the output color format
|
SkASSERT(srcIsOpaque);
|
||||||
*/
|
|
||||||
bool SkHeifCodec::setOutputColorFormat(const SkImageInfo& dstInfo) {
|
|
||||||
if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
|
if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -184,14 +181,14 @@ bool SkHeifCodec::setOutputColorFormat(const SkImageInfo& dstInfo) {
|
|||||||
return fHeifDecoder->setOutputColor(kHeifColorFormat_BGRA_8888);
|
return fHeifDecoder->setOutputColor(kHeifColorFormat_BGRA_8888);
|
||||||
|
|
||||||
case kRGB_565_SkColorType:
|
case kRGB_565_SkColorType:
|
||||||
if (this->colorXform()) {
|
if (needsColorXform) {
|
||||||
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
|
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
|
||||||
} else {
|
} else {
|
||||||
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGB565);
|
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGB565);
|
||||||
}
|
}
|
||||||
|
|
||||||
case kRGBA_F16_SkColorType:
|
case kRGBA_F16_SkColorType:
|
||||||
SkASSERT(this->colorXform());
|
SkASSERT(needsColorXform);
|
||||||
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
|
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -240,7 +237,7 @@ int SkHeifCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this->colorXform()) {
|
if (this->colorXform()) {
|
||||||
this->applyColorXform(dst, swizzleDst, dstWidth, kOpaque_SkAlphaType);
|
this->applyColorXform(dst, swizzleDst, dstWidth);
|
||||||
dst = SkTAddOffset<void>(dst, rowBytes);
|
dst = SkTAddOffset<void>(dst, rowBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,11 +262,6 @@ SkCodec::Result SkHeifCodec::onGetPixels(const SkImageInfo& dstInfo,
|
|||||||
return kUnimplemented;
|
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)) {
|
if (!fHeifDecoder->decode(&fFrameInfo)) {
|
||||||
return kInvalidInput;
|
return kInvalidInput;
|
||||||
}
|
}
|
||||||
@ -313,15 +305,13 @@ void SkHeifCodec::allocateStorage(const SkImageInfo& dstInfo) {
|
|||||||
|
|
||||||
void SkHeifCodec::initializeSwizzler(
|
void SkHeifCodec::initializeSwizzler(
|
||||||
const SkImageInfo& dstInfo, const Options& options) {
|
const SkImageInfo& dstInfo, const Options& options) {
|
||||||
SkEncodedInfo swizzlerInfo = this->getEncodedInfo();
|
|
||||||
|
|
||||||
SkImageInfo swizzlerDstInfo = dstInfo;
|
SkImageInfo swizzlerDstInfo = dstInfo;
|
||||||
if (this->colorXform()) {
|
if (this->colorXform()) {
|
||||||
// The color xform will be expecting RGBA 8888 input.
|
// The color xform will be expecting RGBA 8888 input.
|
||||||
swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType);
|
swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType);
|
||||||
}
|
}
|
||||||
|
|
||||||
fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr,
|
fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), nullptr,
|
||||||
swizzlerDstInfo, options, nullptr, true));
|
swizzlerDstInfo, options, nullptr, true));
|
||||||
SkASSERT(fSwizzler);
|
SkASSERT(fSwizzler);
|
||||||
}
|
}
|
||||||
@ -339,11 +329,6 @@ SkSampler* SkHeifCodec::getSampler(bool createIfNecessary) {
|
|||||||
|
|
||||||
SkCodec::Result SkHeifCodec::onStartScanlineDecode(
|
SkCodec::Result SkHeifCodec::onStartScanlineDecode(
|
||||||
const SkImageInfo& dstInfo, const Options& options) {
|
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.
|
// 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,
|
// If the heif image has tiles, we could potentially do this much faster,
|
||||||
// but the tile configuration needs to be retrieved from the metadata.
|
// but the tile configuration needs to be retrieved from the metadata.
|
||||||
|
@ -9,8 +9,6 @@
|
|||||||
#define SkHeifCodec_DEFINED
|
#define SkHeifCodec_DEFINED
|
||||||
|
|
||||||
#include "SkCodec.h"
|
#include "SkCodec.h"
|
||||||
#include "SkColorSpace.h"
|
|
||||||
#include "SkColorSpaceXform.h"
|
|
||||||
#include "SkEncodedOrigin.h"
|
#include "SkEncodedOrigin.h"
|
||||||
#include "SkImageInfo.h"
|
#include "SkImageInfo.h"
|
||||||
#include "SkSwizzler.h"
|
#include "SkSwizzler.h"
|
||||||
@ -43,27 +41,14 @@ protected:
|
|||||||
return SkEncodedImageFormat::kHEIF;
|
return SkEncodedImageFormat::kHEIF;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool conversionSupported(const SkImageInfo&, SkColorType, bool,
|
bool conversionSupported(const SkImageInfo&, SkColorType, bool, bool) override;
|
||||||
const SkColorSpace*) const override {
|
|
||||||
// This class checks for conversion after creating colorXform.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
* Creates an instance of the decoder
|
* Creates an instance of the decoder
|
||||||
* Called only by NewFromStream
|
* Called only by NewFromStream
|
||||||
*/
|
*/
|
||||||
SkHeifCodec(int width, int height, const SkEncodedInfo&,
|
SkHeifCodec(SkEncodedInfo&&, HeifDecoder*, SkEncodedOrigin);
|
||||||
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);
|
|
||||||
|
|
||||||
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options);
|
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options);
|
||||||
void allocateStorage(const SkImageInfo& dstInfo);
|
void allocateStorage(const SkImageInfo& dstInfo);
|
||||||
|
@ -179,29 +179,19 @@ std::unique_ptr<SkCodec> SkIcoCodec::MakeFromStream(std::unique_ptr<SkStream> st
|
|||||||
maxIndex = i;
|
maxIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int width = codecs->operator[](maxIndex)->getInfo().width();
|
|
||||||
int height = codecs->operator[](maxIndex)->getInfo().height();
|
auto maxInfo = codecs->operator[](maxIndex)->getEncodedInfo().copy();
|
||||||
SkEncodedInfo info = codecs->operator[](maxIndex)->getEncodedInfo();
|
|
||||||
SkColorSpace* colorSpace = codecs->operator[](maxIndex)->getInfo().colorSpace();
|
|
||||||
|
|
||||||
*result = kSuccess;
|
*result = kSuccess;
|
||||||
// The original stream is no longer needed, because the embedded codecs own their
|
// The original stream is no longer needed, because the embedded codecs own their
|
||||||
// own streams.
|
// own streams.
|
||||||
return std::unique_ptr<SkCodec>(new SkIcoCodec(width, height, info, codecs.release(),
|
return std::unique_ptr<SkCodec>(new SkIcoCodec(std::move(maxInfo), codecs.release()));
|
||||||
sk_ref_sp(colorSpace)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
SkIcoCodec::SkIcoCodec(SkEncodedInfo&& info, SkTArray<std::unique_ptr<SkCodec>, true>* codecs)
|
||||||
* Creates an instance of the decoder
|
// The source skcms_PixelFormat will not be used. The embedded
|
||||||
* 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
|
|
||||||
// codec's will be used instead.
|
// codec's will be used instead.
|
||||||
: INHERITED(width, height, info, SkColorSpaceXform::ColorFormat(), nullptr,
|
: INHERITED(std::move(info), skcms_PixelFormat(), nullptr)
|
||||||
std::move(colorSpace))
|
|
||||||
, fEmbeddedCodecs(codecs)
|
, fEmbeddedCodecs(codecs)
|
||||||
, fCurrCodec(nullptr)
|
, fCurrCodec(nullptr)
|
||||||
{}
|
{}
|
||||||
|
@ -48,8 +48,7 @@ protected:
|
|||||||
|
|
||||||
SkScanlineOrder onGetScanlineOrder() const override;
|
SkScanlineOrder onGetScanlineOrder() const override;
|
||||||
|
|
||||||
bool conversionSupported(const SkImageInfo&, SkColorType, bool,
|
bool conversionSupported(const SkImageInfo&, SkColorType, bool, bool) override {
|
||||||
const SkColorSpace*) const override {
|
|
||||||
// This will be checked by the embedded codec.
|
// This will be checked by the embedded codec.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -87,8 +86,7 @@ private:
|
|||||||
* Constructor called by NewFromStream
|
* Constructor called by NewFromStream
|
||||||
* @param embeddedCodecs codecs for the embedded images, takes ownership
|
* @param embeddedCodecs codecs for the embedded images, takes ownership
|
||||||
*/
|
*/
|
||||||
SkIcoCodec(int width, int height, const SkEncodedInfo& info,
|
SkIcoCodec(SkEncodedInfo&& info, SkTArray<std::unique_ptr<SkCodec>, true>* embeddedCodecs);
|
||||||
SkTArray<std::unique_ptr<SkCodec>, true>* embeddedCodecs, sk_sp<SkColorSpace> colorSpace);
|
|
||||||
|
|
||||||
std::unique_ptr<SkTArray<std::unique_ptr<SkCodec>, true>> fEmbeddedCodecs;
|
std::unique_ptr<SkTArray<std::unique_ptr<SkCodec>, true>> fEmbeddedCodecs;
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "SkCodec.h"
|
#include "SkCodec.h"
|
||||||
#include "SkCodecPriv.h"
|
#include "SkCodecPriv.h"
|
||||||
#include "SkColorData.h"
|
#include "SkColorData.h"
|
||||||
|
#include "SkColorSpace.h"
|
||||||
#include "SkJpegDecoderMgr.h"
|
#include "SkJpegDecoderMgr.h"
|
||||||
#include "SkJpegInfo.h"
|
#include "SkJpegInfo.h"
|
||||||
#include "SkStream.h"
|
#include "SkStream.h"
|
||||||
@ -131,7 +132,8 @@ static bool is_icc_marker(jpeg_marker_struct* marker) {
|
|||||||
* (1) Discover all ICC profile markers and verify that they are numbered properly.
|
* (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.
|
* (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.
|
// Note that 256 will be enough storage space since each markerIndex is stored in 8-bits.
|
||||||
jpeg_marker_struct* markerSequence[256];
|
jpeg_marker_struct* markerSequence[256];
|
||||||
memset(markerSequence, 0, sizeof(markerSequence));
|
memset(markerSequence, 0, sizeof(markerSequence));
|
||||||
@ -191,11 +193,12 @@ static sk_sp<SkColorSpace> read_color_space(jpeg_decompress_struct* dinfo) {
|
|||||||
dst = SkTAddOffset<void>(dst, bytes);
|
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,
|
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
|
// Create a JpegDecoderMgr to own all of the decompress information
|
||||||
std::unique_ptr<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
|
std::unique_ptr<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
|
||||||
@ -208,17 +211,18 @@ SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
|
|||||||
|
|
||||||
// Initialize the decompress info and the source manager
|
// Initialize the decompress info and the source manager
|
||||||
decoderMgr->init();
|
decoderMgr->init();
|
||||||
|
auto* dinfo = decoderMgr->dinfo();
|
||||||
|
|
||||||
// Instruct jpeg library to save the markers that we care about. Since
|
// Instruct jpeg library to save the markers that we care about. Since
|
||||||
// the orientation and color profile will not change, we can skip this
|
// the orientation and color profile will not change, we can skip this
|
||||||
// step on rewinds.
|
// step on rewinds.
|
||||||
if (codecOut) {
|
if (codecOut) {
|
||||||
jpeg_save_markers(decoderMgr->dinfo(), kExifMarker, 0xFFFF);
|
jpeg_save_markers(dinfo, kExifMarker, 0xFFFF);
|
||||||
jpeg_save_markers(decoderMgr->dinfo(), kICCMarker, 0xFFFF);
|
jpeg_save_markers(dinfo, kICCMarker, 0xFFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the jpeg header
|
// Read the jpeg header
|
||||||
switch (jpeg_read_header(decoderMgr->dinfo(), true)) {
|
switch (jpeg_read_header(dinfo, true)) {
|
||||||
case JPEG_HEADER_OK:
|
case JPEG_HEADER_OK:
|
||||||
break;
|
break;
|
||||||
case JPEG_SUSPENDED:
|
case JPEG_SUSPENDED:
|
||||||
@ -234,42 +238,41 @@ SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
|
|||||||
return kInvalidInput;
|
return kInvalidInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create image info object and the codec
|
SkEncodedOrigin orientation = get_exif_orientation(dinfo);
|
||||||
SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_Alpha, 8);
|
auto profile = read_color_profile(dinfo);
|
||||||
|
if (profile) {
|
||||||
SkEncodedOrigin orientation = get_exif_orientation(decoderMgr->dinfo());
|
auto type = profile->profile()->data_color_space;
|
||||||
sk_sp<SkColorSpace> colorSpace = read_color_space(decoderMgr->dinfo());
|
|
||||||
if (colorSpace) {
|
|
||||||
switch (decoderMgr->dinfo()->jpeg_color_space) {
|
switch (decoderMgr->dinfo()->jpeg_color_space) {
|
||||||
case JCS_CMYK:
|
case JCS_CMYK:
|
||||||
case JCS_YCCK:
|
case JCS_YCCK:
|
||||||
if (colorSpace->type() != SkColorSpace::kCMYK_Type) {
|
if (type != skcms_Signature_CMYK) {
|
||||||
colorSpace = nullptr;
|
profile = nullptr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case JCS_GRAYSCALE:
|
case JCS_GRAYSCALE:
|
||||||
if (colorSpace->type() != SkColorSpace::kGray_Type &&
|
if (type != skcms_Signature_Gray &&
|
||||||
colorSpace->type() != SkColorSpace::kRGB_Type)
|
type != skcms_Signature_RGB)
|
||||||
{
|
{
|
||||||
colorSpace = nullptr;
|
profile = nullptr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (colorSpace->type() != SkColorSpace::kRGB_Type) {
|
if (type != skcms_Signature_RGB) {
|
||||||
colorSpace = nullptr;
|
profile = nullptr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!colorSpace) {
|
if (!profile) {
|
||||||
colorSpace = defaultColorSpace;
|
profile = std::move(defaultColorProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int width = decoderMgr->dinfo()->image_width;
|
SkEncodedInfo info = SkEncodedInfo::Make(dinfo->image_width, dinfo->image_height,
|
||||||
const int height = decoderMgr->dinfo()->image_height;
|
color, SkEncodedInfo::kOpaque_Alpha, 8,
|
||||||
SkJpegCodec* codec = new SkJpegCodec(width, height, info, std::unique_ptr<SkStream>(stream),
|
std::move(profile));
|
||||||
decoderMgr.release(), std::move(colorSpace),
|
|
||||||
orientation);
|
SkJpegCodec* codec = new SkJpegCodec(std::move(info), std::unique_ptr<SkStream>(stream),
|
||||||
|
decoderMgr.release(), orientation);
|
||||||
*codecOut = codec;
|
*codecOut = codec;
|
||||||
} else {
|
} else {
|
||||||
SkASSERT(nullptr != decoderMgrOut);
|
SkASSERT(nullptr != decoderMgrOut);
|
||||||
@ -280,14 +283,15 @@ SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
|
|||||||
|
|
||||||
std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
|
std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
|
||||||
Result* result) {
|
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,
|
std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
|
||||||
Result* result,
|
Result* result, std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) {
|
||||||
sk_sp<SkColorSpace> defaultColorSpace) {
|
|
||||||
SkCodec* codec = nullptr;
|
SkCodec* codec = nullptr;
|
||||||
*result = ReadHeader(stream.get(), &codec, nullptr, std::move(defaultColorSpace));
|
*result = ReadHeader(stream.get(), &codec, nullptr, std::move(defaultColorProfile));
|
||||||
if (kSuccess == *result) {
|
if (kSuccess == *result) {
|
||||||
// Codec has taken ownership of the stream, we do not need to delete it
|
// Codec has taken ownership of the stream, we do not need to delete it
|
||||||
SkASSERT(codec);
|
SkASSERT(codec);
|
||||||
@ -297,11 +301,10 @@ std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> s
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info,
|
SkJpegCodec::SkJpegCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||||
std::unique_ptr<SkStream> stream, JpegDecoderMgr* decoderMgr,
|
JpegDecoderMgr* decoderMgr, SkEncodedOrigin origin)
|
||||||
sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin)
|
: INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, std::move(stream),
|
||||||
: INHERITED(width, height, info, SkColorSpaceXform::kRGBA_8888_ColorFormat, std::move(stream),
|
origin)
|
||||||
std::move(colorSpace), origin)
|
|
||||||
, fDecoderMgr(decoderMgr)
|
, fDecoderMgr(decoderMgr)
|
||||||
, fReadyState(decoderMgr->dinfo()->global_state)
|
, fReadyState(decoderMgr->dinfo()->global_state)
|
||||||
, fSwizzleSrcRow(nullptr)
|
, fSwizzleSrcRow(nullptr)
|
||||||
@ -386,12 +389,10 @@ bool SkJpegCodec::onRewind() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
bool SkJpegCodec::conversionSupported(const SkImageInfo& dstInfo, SkColorType srcCT,
|
||||||
* Checks if the conversion between the input image and the requested output
|
bool srcIsOpaque, bool needsColorXform) {
|
||||||
* image has been implemented
|
SkASSERT(srcIsOpaque);
|
||||||
* Sets the output color space
|
|
||||||
*/
|
|
||||||
bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) {
|
|
||||||
if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
|
if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -409,7 +410,7 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) {
|
|||||||
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
||||||
break;
|
break;
|
||||||
case kBGRA_8888_SkColorType:
|
case kBGRA_8888_SkColorType:
|
||||||
if (this->colorXform()) {
|
if (needsColorXform) {
|
||||||
// Always using RGBA as the input format for color xforms makes the
|
// Always using RGBA as the input format for color xforms makes the
|
||||||
// implementation a little simpler.
|
// implementation a little simpler.
|
||||||
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
||||||
@ -418,7 +419,7 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kRGB_565_SkColorType:
|
case kRGB_565_SkColorType:
|
||||||
if (this->colorXform()) {
|
if (needsColorXform) {
|
||||||
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
||||||
} else {
|
} else {
|
||||||
fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
|
fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
|
||||||
@ -426,14 +427,15 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kGray_8_SkColorType:
|
case kGray_8_SkColorType:
|
||||||
if (this->colorXform() || JCS_GRAYSCALE != encodedColorType) {
|
SkASSERT(!needsColorXform);
|
||||||
|
if (JCS_GRAYSCALE != encodedColorType) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
|
fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
|
||||||
break;
|
break;
|
||||||
case kRGBA_F16_SkColorType:
|
case kRGBA_F16_SkColorType:
|
||||||
SkASSERT(this->colorXform());
|
SkASSERT(needsColorXform);
|
||||||
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -539,7 +541,7 @@ int SkJpegCodec::readRows(const SkImageInfo& dstInfo, void* dst, size_t rowBytes
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this->colorXform()) {
|
if (this->colorXform()) {
|
||||||
this->applyColorXform(dst, swizzleDst, dstWidth, kOpaque_SkAlphaType);
|
this->applyColorXform(dst, swizzleDst, dstWidth);
|
||||||
dst = SkTAddOffset<void>(dst, rowBytes);
|
dst = SkTAddOffset<void>(dst, rowBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,11 +589,6 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
|
|||||||
return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
|
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)) {
|
if (!jpeg_start_decompress(dinfo)) {
|
||||||
return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
|
return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
|
||||||
}
|
}
|
||||||
@ -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,
|
void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
|
||||||
bool needsCMYKToRGB) {
|
bool needsCMYKToRGB) {
|
||||||
SkEncodedInfo swizzlerInfo = this->getEncodedInfo();
|
SkEncodedInfo swizzlerInfo = make_info(this->getEncodedInfo(), needsCMYKToRGB);
|
||||||
if (needsCMYKToRGB) {
|
|
||||||
swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Color,
|
|
||||||
swizzlerInfo.alpha(),
|
|
||||||
swizzlerInfo.bitsPerComponent());
|
|
||||||
}
|
|
||||||
|
|
||||||
Options swizzlerOptions = options;
|
Options swizzlerOptions = options;
|
||||||
if (options.fSubset) {
|
if (options.fSubset) {
|
||||||
@ -693,11 +692,6 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
|
|||||||
return kInvalidInput;
|
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())) {
|
if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
|
||||||
SkCodecPrintf("start decompress failed\n");
|
SkCodecPrintf("start decompress failed\n");
|
||||||
return kInvalidInput;
|
return kInvalidInput;
|
||||||
|
@ -9,14 +9,13 @@
|
|||||||
#define SkJpegCodec_DEFINED
|
#define SkJpegCodec_DEFINED
|
||||||
|
|
||||||
#include "SkCodec.h"
|
#include "SkCodec.h"
|
||||||
#include "SkColorSpace.h"
|
|
||||||
#include "SkColorSpaceXform.h"
|
|
||||||
#include "SkImageInfo.h"
|
#include "SkImageInfo.h"
|
||||||
#include "SkSwizzler.h"
|
#include "SkSwizzler.h"
|
||||||
#include "SkStream.h"
|
#include "SkStream.h"
|
||||||
#include "SkTemplates.h"
|
#include "SkTemplates.h"
|
||||||
|
|
||||||
class JpegDecoderMgr;
|
class JpegDecoderMgr;
|
||||||
|
class SkColorSpace;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
@ -58,19 +57,14 @@ protected:
|
|||||||
|
|
||||||
bool onDimensionsSupported(const SkISize&) override;
|
bool onDimensionsSupported(const SkISize&) override;
|
||||||
|
|
||||||
bool conversionSupported(const SkImageInfo&, SkColorType, bool,
|
bool conversionSupported(const SkImageInfo&, SkColorType, bool, bool) override;
|
||||||
const SkColorSpace*) const override {
|
|
||||||
// This class checks for conversion after creating colorXform.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
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*,
|
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.
|
* Read enough of the stream to initialize the SkJpegCodec.
|
||||||
@ -90,12 +84,13 @@ private:
|
|||||||
* codecOut will take ownership of it in the case where we created a codec.
|
* codecOut will take ownership of it in the case where we created a codec.
|
||||||
* Ownership is unchanged when we set decoderMgrOut.
|
* Ownership is unchanged when we set decoderMgrOut.
|
||||||
*
|
*
|
||||||
* @param defaultColorSpace
|
* @param defaultColorProfile
|
||||||
* If the jpeg does not have an embedded color space, the image data should
|
* If the jpeg does not have an embedded color profile, the image data should
|
||||||
* be tagged with this color space.
|
* be tagged with this color profile.
|
||||||
*/
|
*/
|
||||||
static Result ReadHeader(SkStream* stream, SkCodec** codecOut,
|
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
|
* Creates an instance of the decoder
|
||||||
@ -106,16 +101,8 @@ private:
|
|||||||
* @param decoderMgr holds decompress struct, src manager, and error manager
|
* @param decoderMgr holds decompress struct, src manager, and error manager
|
||||||
* takes ownership
|
* takes ownership
|
||||||
*/
|
*/
|
||||||
SkJpegCodec(int width, int height, const SkEncodedInfo& info, std::unique_ptr<SkStream> stream,
|
SkJpegCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||||
JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin);
|
JpegDecoderMgr* decoderMgr, 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);
|
|
||||||
|
|
||||||
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
|
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
|
||||||
bool needsCMYKToRGB);
|
bool needsCMYKToRGB);
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#include "SkCodecPriv.h"
|
#include "SkCodecPriv.h"
|
||||||
#include "SkColorData.h"
|
#include "SkColorData.h"
|
||||||
#include "SkColorSpace.h"
|
#include "SkColorSpace.h"
|
||||||
#include "SkColorSpacePriv.h"
|
|
||||||
#include "SkColorTable.h"
|
#include "SkColorTable.h"
|
||||||
#include "SkMacros.h"
|
#include "SkMacros.h"
|
||||||
#include "SkMath.h"
|
#include "SkMath.h"
|
||||||
@ -248,6 +247,10 @@ bool SkPngCodec::processData() {
|
|||||||
|
|
||||||
static constexpr SkColorType kXformSrcColorType = kRGBA_8888_SkColorType;
|
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.
|
// Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here.
|
||||||
bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) {
|
bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) {
|
||||||
|
|
||||||
@ -265,10 +268,7 @@ bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) {
|
|||||||
png_bytep alphas;
|
png_bytep alphas;
|
||||||
int numColorsWithAlpha = 0;
|
int numColorsWithAlpha = 0;
|
||||||
if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) {
|
if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) {
|
||||||
// If we are performing a color xform, it will handle the premultiply. Otherwise,
|
bool premultiply = needs_premul(dstInfo.alphaType(), this->getEncodedInfo().alpha());
|
||||||
// we'll do it here.
|
|
||||||
bool premultiply = !this->colorXform() && needs_premul(dstInfo.alphaType(),
|
|
||||||
this->getEncodedInfo().alpha());
|
|
||||||
|
|
||||||
// Choose which function to use to create the color table. If the final destination's
|
// 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.
|
// 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
|
#endif // LIBPNG >= 1.6
|
||||||
|
|
||||||
// Returns a colorSpace object that represents any color space information in
|
// If there is no color profile information, it will use sRGB.
|
||||||
// the encoded data. If the encoded data contains an invalid/unsupported color space,
|
std::unique_ptr<SkEncodedInfo::ICCProfile> read_color_profile(png_structp png_ptr,
|
||||||
// this will return NULL. If there is no color space information, it will guess sRGB
|
png_infop info_ptr) {
|
||||||
sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) {
|
|
||||||
|
|
||||||
#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
|
#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
|
||||||
|
|
||||||
// First check for an ICC profile
|
// First check for an ICC profile
|
||||||
png_bytep profile;
|
png_bytep profile;
|
||||||
png_uint_32 length;
|
png_uint_32 length;
|
||||||
@ -362,74 +360,70 @@ sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) {
|
|||||||
int compression;
|
int compression;
|
||||||
if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile,
|
if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile,
|
||||||
&length)) {
|
&length)) {
|
||||||
return SkColorSpace::MakeICC(profile, length);
|
auto data = SkData::MakeWithCopy(profile, length);
|
||||||
|
return SkEncodedInfo::ICCProfile::Make(std::move(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second, check for sRGB.
|
// 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)) {
|
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
|
||||||
|
|
||||||
// sRGB chunks also store a rendering intent: Absolute, Relative,
|
// sRGB chunks also store a rendering intent: Absolute, Relative,
|
||||||
// Perceptual, and Saturation.
|
// Perceptual, and Saturation.
|
||||||
// FIXME (msarett): Extract this information from the sRGB chunk once
|
// FIXME (msarett): Extract this information from the sRGB chunk once
|
||||||
// we are able to handle this information in
|
// we are able to handle this information in
|
||||||
// SkColorSpace.
|
// SkColorSpace.
|
||||||
return SkColorSpace::MakeSRGB();
|
return SkEncodedInfo::ICCProfile::MakeSRGB();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default to SRGB gamut.
|
||||||
|
skcms_Matrix3x3 toXYZD50 = skcms_sRGB_profile()->toXYZD50;
|
||||||
// Next, check for chromaticities.
|
// Next, check for chromaticities.
|
||||||
png_fixed_point chrm[8];
|
png_fixed_point chrm[8];
|
||||||
png_fixed_point gamma;
|
png_fixed_point gamma;
|
||||||
if (png_get_cHRM_fixed(png_ptr, info_ptr, &chrm[0], &chrm[1], &chrm[2], &chrm[3], &chrm[4],
|
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]))
|
&chrm[5], &chrm[6], &chrm[7]))
|
||||||
{
|
{
|
||||||
SkColorSpacePrimaries primaries;
|
float rx = png_fixed_point_to_float(chrm[2]);
|
||||||
primaries.fRX = png_fixed_point_to_float(chrm[2]);
|
float ry = png_fixed_point_to_float(chrm[3]);
|
||||||
primaries.fRY = png_fixed_point_to_float(chrm[3]);
|
float gx = png_fixed_point_to_float(chrm[4]);
|
||||||
primaries.fGX = png_fixed_point_to_float(chrm[4]);
|
float gy = png_fixed_point_to_float(chrm[5]);
|
||||||
primaries.fGY = png_fixed_point_to_float(chrm[5]);
|
float bx = png_fixed_point_to_float(chrm[6]);
|
||||||
primaries.fBX = png_fixed_point_to_float(chrm[6]);
|
float by = png_fixed_point_to_float(chrm[7]);
|
||||||
primaries.fBY = png_fixed_point_to_float(chrm[7]);
|
float wx = png_fixed_point_to_float(chrm[0]);
|
||||||
primaries.fWX = png_fixed_point_to_float(chrm[0]);
|
float wy = png_fixed_point_to_float(chrm[1]);
|
||||||
primaries.fWY = png_fixed_point_to_float(chrm[1]);
|
|
||||||
|
|
||||||
SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
|
skcms_Matrix3x3 tmp;
|
||||||
if (!primaries.toXYZD50(&toXYZD50)) {
|
if (skcms_PrimariesToXYZD50(rx, ry, gx, gy, bx, by, wx, wy, &tmp)) {
|
||||||
toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
|
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)) {
|
if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
|
||||||
SkColorSpaceTransferFn fn;
|
fn.a = 1.0f;
|
||||||
fn.fA = 1.0f;
|
fn.b = fn.c = fn.d = fn.e = fn.f = 0.0f;
|
||||||
fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f;
|
fn.g = png_inverted_fixed_point_to_float(gamma);
|
||||||
fn.fG = png_inverted_fixed_point_to_float(gamma);
|
} else {
|
||||||
|
|
||||||
return SkColorSpace::MakeRGB(fn, toXYZD50);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to sRGB gamma if the image has color space information,
|
// Default to sRGB gamma if the image has color space information,
|
||||||
// but does not specify gamma.
|
// 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.
|
skcms_ICCProfile skcmsProfile;
|
||||||
if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
|
skcms_Init(&skcmsProfile);
|
||||||
SkColorSpaceTransferFn fn;
|
skcms_SetTransferFunction(&skcmsProfile, &fn);
|
||||||
fn.fA = 1.0f;
|
skcms_SetXYZD50(&skcmsProfile, &toXYZD50);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return SkEncodedInfo::ICCProfile::Make(skcmsProfile);
|
||||||
|
#else // LIBPNG >= 1.6
|
||||||
|
return SkEncodedInfo::ICCProfile::MakeSRGB();
|
||||||
#endif // LIBPNG >= 1.6
|
#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) {
|
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.
|
// We use kRGB and kRGBA formats because color PNGs are always RGB or RGBA.
|
||||||
if (16 == info.bitsPerComponent()) {
|
if (16 == info.bitsPerComponent()) {
|
||||||
if (SkEncodedInfo::kRGBA_Color == info.color()) {
|
if (SkEncodedInfo::kRGBA_Color == info.color()) {
|
||||||
return SkColorSpaceXform::kRGBA_U16_BE_ColorFormat;
|
return skcms_PixelFormat_RGBA_16161616;
|
||||||
} else if (SkEncodedInfo::kRGB_Color == info.color()) {
|
} 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) {
|
void SkPngCodec::applyXformRow(void* dst, const void* src) {
|
||||||
@ -484,10 +478,9 @@ void SkPngCodec::applyXformRow(void* dst, const void* src) {
|
|||||||
|
|
||||||
class SkPngNormalDecoder : public SkPngCodec {
|
class SkPngNormalDecoder : public SkPngCodec {
|
||||||
public:
|
public:
|
||||||
SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
|
SkPngNormalDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||||
std::unique_ptr<SkStream> stream, SkPngChunkReader* reader,
|
SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, int bitDepth)
|
||||||
png_structp png_ptr, png_infop info_ptr, int bitDepth)
|
: INHERITED(std::move(info), std::move(stream), reader, png_ptr, info_ptr, bitDepth)
|
||||||
: INHERITED(info, imageInfo, std::move(stream), reader, png_ptr, info_ptr, bitDepth)
|
|
||||||
, fRowsWrittenToOutput(0)
|
, fRowsWrittenToOutput(0)
|
||||||
, fDst(nullptr)
|
, fDst(nullptr)
|
||||||
, fRowBytes(0)
|
, fRowBytes(0)
|
||||||
@ -607,10 +600,10 @@ private:
|
|||||||
|
|
||||||
class SkPngInterlacedDecoder : public SkPngCodec {
|
class SkPngInterlacedDecoder : public SkPngCodec {
|
||||||
public:
|
public:
|
||||||
SkPngInterlacedDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
|
SkPngInterlacedDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||||
std::unique_ptr<SkStream> stream, SkPngChunkReader* reader, png_structp png_ptr,
|
SkPngChunkReader* reader, png_structp png_ptr,
|
||||||
png_infop info_ptr, int bitDepth, int numberPasses)
|
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)
|
, fNumberPasses(numberPasses)
|
||||||
, fFirstRow(0)
|
, fFirstRow(0)
|
||||||
, fLastRow(0)
|
, fLastRow(0)
|
||||||
@ -918,36 +911,33 @@ void AutoCleanPng::infoCallback(size_t idatLength) {
|
|||||||
|
|
||||||
if (fOutCodec) {
|
if (fOutCodec) {
|
||||||
SkASSERT(nullptr == *fOutCodec);
|
SkASSERT(nullptr == *fOutCodec);
|
||||||
sk_sp<SkColorSpace> colorSpace = read_color_space(fPng_ptr, fInfo_ptr);
|
auto profile = read_color_profile(fPng_ptr, fInfo_ptr);
|
||||||
if (colorSpace) {
|
if (profile) {
|
||||||
switch (colorSpace->type()) {
|
switch (profile->profile()->data_color_space) {
|
||||||
case SkColorSpace::kCMYK_Type:
|
case skcms_Signature_CMYK:
|
||||||
colorSpace = nullptr;
|
profile = nullptr;
|
||||||
break;
|
break;
|
||||||
case SkColorSpace::kGray_Type:
|
case skcms_Signature_Gray:
|
||||||
if (SkEncodedInfo::kGray_Color != color &&
|
if (SkEncodedInfo::kGray_Color != color &&
|
||||||
SkEncodedInfo::kGrayAlpha_Color != color)
|
SkEncodedInfo::kGrayAlpha_Color != color)
|
||||||
{
|
{
|
||||||
colorSpace = nullptr;
|
profile = nullptr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SkColorSpace::kRGB_Type:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!colorSpace) {
|
if (!profile) {
|
||||||
// Treat unsupported/invalid color spaces as sRGB.
|
// 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) {
|
if (encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||||
png_color_8p sigBits;
|
png_color_8p sigBits;
|
||||||
if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
|
if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
|
||||||
if (8 == sigBits->alpha && kGraySigBit_GrayAlphaIsJustAlpha == sigBits->gray) {
|
if (8 == sigBits->alpha && kGraySigBit_GrayAlphaIsJustAlpha == sigBits->gray) {
|
||||||
imageInfo = imageInfo.makeColorType(kAlpha_8_SkColorType);
|
color = SkEncodedInfo::kXAlpha_Color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (SkEncodedInfo::kOpaque_Alpha == alpha) {
|
} 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 (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
|
||||||
if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) {
|
if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) {
|
||||||
// Recommend a decode to 565 if the sBIT indicates 565.
|
// 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) {
|
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);
|
std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth);
|
||||||
} else {
|
} else {
|
||||||
*fOutCodec = new SkPngInterlacedDecoder(encodedInfo, imageInfo,
|
*fOutCodec = new SkPngInterlacedDecoder(std::move(encodedInfo),
|
||||||
std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth,
|
std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth,
|
||||||
numberPasses);
|
numberPasses);
|
||||||
}
|
}
|
||||||
@ -976,10 +968,9 @@ void AutoCleanPng::infoCallback(size_t idatLength) {
|
|||||||
this->releasePngPtrs();
|
this->releasePngPtrs();
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPngCodec::SkPngCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
|
SkPngCodec::SkPngCodec(SkEncodedInfo&& encodedInfo, std::unique_ptr<SkStream> stream,
|
||||||
std::unique_ptr<SkStream> stream, SkPngChunkReader* chunkReader,
|
SkPngChunkReader* chunkReader, void* png_ptr, void* info_ptr, int bitDepth)
|
||||||
void* png_ptr, void* info_ptr, int bitDepth)
|
: INHERITED(std::move(encodedInfo), png_select_xform_format(encodedInfo), std::move(stream))
|
||||||
: INHERITED(encodedInfo, imageInfo, png_select_xform_format(encodedInfo), std::move(stream))
|
|
||||||
, fPngChunkReader(SkSafeRef(chunkReader))
|
, fPngChunkReader(SkSafeRef(chunkReader))
|
||||||
, fPng_ptr(png_ptr)
|
, fPng_ptr(png_ptr)
|
||||||
, fInfo_ptr(info_ptr)
|
, fInfo_ptr(info_ptr)
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#define SkPngCodec_DEFINED
|
#define SkPngCodec_DEFINED
|
||||||
|
|
||||||
#include "SkCodec.h"
|
#include "SkCodec.h"
|
||||||
#include "SkColorSpaceXform.h"
|
|
||||||
#include "SkColorTable.h"
|
#include "SkColorTable.h"
|
||||||
#include "SkPngChunkReader.h"
|
#include "SkPngChunkReader.h"
|
||||||
#include "SkEncodedImageFormat.h"
|
#include "SkEncodedImageFormat.h"
|
||||||
@ -45,8 +44,8 @@ protected:
|
|||||||
void* fPtr;
|
void* fPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
SkPngCodec(const SkEncodedInfo&, const SkImageInfo&, std::unique_ptr<SkStream>,
|
SkPngCodec(SkEncodedInfo&&, std::unique_ptr<SkStream>, SkPngChunkReader*,
|
||||||
SkPngChunkReader*, void* png_ptr, void* info_ptr, int bitDepth);
|
void* png_ptr, void* info_ptr, int bitDepth);
|
||||||
|
|
||||||
Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, int*)
|
Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, int*)
|
||||||
override;
|
override;
|
||||||
|
@ -504,10 +504,6 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SkEncodedInfo& getEncodedInfo() const {
|
|
||||||
return fEncodedInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
int width() const {
|
int width() const {
|
||||||
return fWidth;
|
return fWidth;
|
||||||
}
|
}
|
||||||
@ -602,8 +598,6 @@ private:
|
|||||||
|
|
||||||
SkDngImage(SkRawStream* stream)
|
SkDngImage(SkRawStream* stream)
|
||||||
: fStream(stream)
|
: fStream(stream)
|
||||||
, fEncodedInfo(SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color,
|
|
||||||
SkEncodedInfo::kOpaque_Alpha, 8))
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
dng_memory_allocator fAllocator;
|
dng_memory_allocator fAllocator;
|
||||||
@ -615,11 +609,21 @@ private:
|
|||||||
|
|
||||||
int fWidth;
|
int fWidth;
|
||||||
int fHeight;
|
int fHeight;
|
||||||
SkEncodedInfo fEncodedInfo;
|
|
||||||
bool fIsScalable;
|
bool fIsScalable;
|
||||||
bool fIsXtransImage;
|
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
|
* 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,
|
* SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases,
|
||||||
@ -644,16 +648,22 @@ std::unique_ptr<SkCodec> SkRawCodec::MakeFromStream(std::unique_ptr<SkStream> st
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
sk_sp<SkColorSpace> colorSpace;
|
std::unique_ptr<SkEncodedInfo::ICCProfile> profile;
|
||||||
switch (imageData.color_space) {
|
switch (imageData.color_space) {
|
||||||
case ::piex::PreviewImageData::kSrgb:
|
case ::piex::PreviewImageData::kSrgb:
|
||||||
colorSpace = SkColorSpace::MakeSRGB();
|
profile = SkEncodedInfo::ICCProfile::MakeSRGB();
|
||||||
break;
|
break;
|
||||||
case ::piex::PreviewImageData::kAdobeRgb:
|
case ::piex::PreviewImageData::kAdobeRgb: {
|
||||||
colorSpace = SkColorSpace::MakeRGB(g2Dot2_TransferFn,
|
constexpr skcms_TransferFunction twoDotTwo =
|
||||||
SkColorSpace::kAdobeRGB_Gamut);
|
{ 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;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Theoretically PIEX can return JPEG compressed image or uncompressed RGB image. We only
|
// Theoretically PIEX can return JPEG compressed image or uncompressed RGB image. We only
|
||||||
// handle the JPEG compressed preview image here.
|
// handle the JPEG compressed preview image here.
|
||||||
@ -670,7 +680,7 @@ std::unique_ptr<SkCodec> SkRawCodec::MakeFromStream(std::unique_ptr<SkStream> st
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return SkJpegCodec::MakeFromStream(std::move(memoryStream), result,
|
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()) {
|
if (this->colorXform()) {
|
||||||
swizzler->swizzle(xformBuffer.get(), &srcRow[0]);
|
swizzler->swizzle(xformBuffer.get(), &srcRow[0]);
|
||||||
|
|
||||||
this->applyColorXform(dstRow, xformBuffer.get(), dstInfo.width(), kOpaque_SkAlphaType);
|
this->applyColorXform(dstRow, xformBuffer.get(), dstInfo.width());
|
||||||
} else {
|
} else {
|
||||||
swizzler->swizzle(dstRow, &srcRow[0]);
|
swizzler->swizzle(dstRow, &srcRow[0]);
|
||||||
}
|
}
|
||||||
@ -796,7 +806,8 @@ bool SkRawCodec::onDimensionsSupported(const SkISize& dim) {
|
|||||||
SkRawCodec::~SkRawCodec() {}
|
SkRawCodec::~SkRawCodec() {}
|
||||||
|
|
||||||
SkRawCodec::SkRawCodec(SkDngImage* dngImage)
|
SkRawCodec::SkRawCodec(SkDngImage* dngImage)
|
||||||
: INHERITED(dngImage->width(), dngImage->height(), dngImage->getEncodedInfo(),
|
: INHERITED(SkEncodedInfo::MakeSRGB(dngImage->width(), dngImage->height(),
|
||||||
SkColorSpaceXform::kRGBA_8888_ColorFormat, nullptr,
|
SkEncodedInfo::kRGB_Color,
|
||||||
SkColorSpace::MakeSRGB())
|
SkEncodedInfo::kOpaque_Alpha, 8),
|
||||||
|
skcms_PixelFormat_RGBA_8888, nullptr)
|
||||||
, fDngImage(dngImage) {}
|
, fDngImage(dngImage) {}
|
||||||
|
@ -890,6 +890,7 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SkEncodedInfo::kXAlpha_Color:
|
||||||
case SkEncodedInfo::kGrayAlpha_Color:
|
case SkEncodedInfo::kGrayAlpha_Color:
|
||||||
switch (dstInfo.colorType()) {
|
switch (dstInfo.colorType()) {
|
||||||
case kRGBA_8888_SkColorType:
|
case kRGBA_8888_SkColorType:
|
||||||
@ -963,6 +964,10 @@ SkSwizzler* SkSwizzler::CreateSwizzler(const SkEncodedInfo& encodedInfo,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case SkEncodedInfo::kRGB_Color:
|
||||||
switch (dstInfo.colorType()) {
|
switch (dstInfo.colorType()) {
|
||||||
case kRGBA_8888_SkColorType:
|
case kRGBA_8888_SkColorType:
|
||||||
|
@ -97,11 +97,10 @@ bool SkWbmpCodec::readRow(uint8_t* row) {
|
|||||||
return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes;
|
return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkWbmpCodec::SkWbmpCodec(int width, int height, const SkEncodedInfo& info,
|
SkWbmpCodec::SkWbmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream)
|
||||||
std::unique_ptr<SkStream> stream)
|
|
||||||
// Wbmp does not need a colorXform, so choose an arbitrary srcFormat.
|
// Wbmp does not need a colorXform, so choose an arbitrary srcFormat.
|
||||||
: INHERITED(width, height, info, SkColorSpaceXform::ColorFormat(),
|
: INHERITED(std::move(info), skcms_PixelFormat(),
|
||||||
std::move(stream), SkColorSpace::MakeSRGB())
|
std::move(stream))
|
||||||
, fSrcRowBytes(get_src_row_bytes(this->getInfo().width()))
|
, fSrcRowBytes(get_src_row_bytes(this->getInfo().width()))
|
||||||
, fSwizzler(nullptr)
|
, fSwizzler(nullptr)
|
||||||
{}
|
{}
|
||||||
@ -111,7 +110,7 @@ SkEncodedImageFormat SkWbmpCodec::onGetEncodedFormat() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool SkWbmpCodec::conversionSupported(const SkImageInfo& dst, SkColorType /*srcColor*/,
|
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);
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
*result = kSuccess;
|
*result = kSuccess;
|
||||||
SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kGray_Color,
|
auto info = SkEncodedInfo::Make(size.width(), size.height(), SkEncodedInfo::kGray_Color,
|
||||||
SkEncodedInfo::kOpaque_Alpha, 1);
|
SkEncodedInfo::kOpaque_Alpha, 1);
|
||||||
return std::unique_ptr<SkCodec>(new SkWbmpCodec(size.width(), size.height(), info,
|
return std::unique_ptr<SkCodec>(new SkWbmpCodec(std::move(info), std::move(stream)));
|
||||||
std::move(stream)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
|
int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
|
||||||
|
@ -29,7 +29,7 @@ protected:
|
|||||||
const Options&, int*) override;
|
const Options&, int*) override;
|
||||||
bool onRewind() override;
|
bool onRewind() override;
|
||||||
bool conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
|
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.
|
// No need to Xform; all pixels are either black or white.
|
||||||
bool usesColorXform() const override { return false; }
|
bool usesColorXform() const override { return false; }
|
||||||
private:
|
private:
|
||||||
@ -48,7 +48,7 @@ private:
|
|||||||
*/
|
*/
|
||||||
bool readRow(uint8_t* row);
|
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;
|
const size_t fSrcRowBytes;
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "SkCodecAnimation.h"
|
#include "SkCodecAnimation.h"
|
||||||
#include "SkCodecAnimationPriv.h"
|
#include "SkCodecAnimationPriv.h"
|
||||||
#include "SkCodecPriv.h"
|
#include "SkCodecPriv.h"
|
||||||
#include "SkColorSpaceXform.h"
|
|
||||||
#include "SkMakeUnique.h"
|
#include "SkMakeUnique.h"
|
||||||
#include "SkRasterPipeline.h"
|
#include "SkRasterPipeline.h"
|
||||||
#include "SkSampler.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;
|
WebPChunkIterator chunkIterator;
|
||||||
SkAutoTCallVProc<WebPChunkIterator, WebPDemuxReleaseChunkIterator> autoCI(&chunkIterator);
|
SkAutoTCallVProc<WebPChunkIterator, WebPDemuxReleaseChunkIterator> autoCI(&chunkIterator);
|
||||||
if (WebPDemuxGetChunk(demux, "ICCP", 1, &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) {
|
if (!profile || profile->profile()->data_color_space != skcms_Signature_RGB) {
|
||||||
colorSpace = SkColorSpace::MakeSRGB();
|
profile = SkEncodedInfo::ICCProfile::MakeSRGB();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,10 +172,9 @@ std::unique_ptr<SkCodec> SkWebpCodec::MakeFromStream(std::unique_ptr<SkStream> s
|
|||||||
|
|
||||||
|
|
||||||
*result = kSuccess;
|
*result = kSuccess;
|
||||||
SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8);
|
SkEncodedInfo info = SkEncodedInfo::Make(width, height, color, alpha, 8, std::move(profile));
|
||||||
return std::unique_ptr<SkCodec>(new SkWebpCodec(width, height, info, std::move(colorSpace),
|
return std::unique_ptr<SkCodec>(new SkWebpCodec(std::move(info), std::move(stream),
|
||||||
std::move(stream), demux.release(), std::move(data),
|
demux.release(), std::move(data), origin));
|
||||||
origin));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkISize SkWebpCodec::onGetScaledDimensions(float desiredScale) const {
|
SkISize SkWebpCodec::onGetScaledDimensions(float desiredScale) const {
|
||||||
@ -543,35 +543,8 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
|
|||||||
webpDst.installPixels(webpInfo, dst, rowBytes);
|
webpDst.installPixels(webpInfo, dst, rowBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Choose the step when we will perform premultiplication.
|
config.output.colorspace = webp_decode_mode(webpInfo.colorType(),
|
||||||
enum {
|
frame.has_alpha && dstInfo.alphaType() == kPremul_SkAlphaType && !this->colorXform());
|
||||||
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.is_external_memory = 1;
|
config.output.is_external_memory = 1;
|
||||||
|
|
||||||
config.output.u.RGBA.rgba = reinterpret_cast<uint8_t*>(webpDst.getAddr(dstX, dstY));
|
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;
|
xformDst = dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto xformAlphaType = (premulStep == kColorXform) ? kPremul_SkAlphaType :
|
|
||||||
( frame.has_alpha) ? kUnpremul_SkAlphaType :
|
|
||||||
kOpaque_SkAlphaType ;
|
|
||||||
for (int y = 0; y < rowsDecoded; y++) {
|
for (int y = 0; y < rowsDecoded; y++) {
|
||||||
this->applyColorXform(xformDst, xformSrc, scaledWidth, xformAlphaType);
|
this->applyColorXform(xformDst, xformSrc, scaledWidth);
|
||||||
if (blendWithPrevFrame) {
|
if (blendWithPrevFrame) {
|
||||||
blend_line(dstCT, dst, dstCT, xformDst,
|
blend_line(dstCT, dst, dstCT, xformDst,
|
||||||
dstInfo.alphaType(), frame.has_alpha, scaledWidth);
|
dstInfo.alphaType(), frame.has_alpha, scaledWidth);
|
||||||
@ -648,14 +618,14 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkWebpCodec::SkWebpCodec(int width, int height, const SkEncodedInfo& info,
|
SkWebpCodec::SkWebpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
|
||||||
sk_sp<SkColorSpace> colorSpace, std::unique_ptr<SkStream> stream,
|
|
||||||
WebPDemuxer* demux, sk_sp<SkData> data, SkEncodedOrigin origin)
|
WebPDemuxer* demux, sk_sp<SkData> data, SkEncodedOrigin origin)
|
||||||
: INHERITED(width, height, info, SkColorSpaceXform::kBGRA_8888_ColorFormat, std::move(stream),
|
: INHERITED(std::move(info), skcms_PixelFormat_BGRA_8888, std::move(stream),
|
||||||
std::move(colorSpace), origin)
|
origin)
|
||||||
, fDemux(demux)
|
, fDemux(demux)
|
||||||
, fData(std::move(data))
|
, fData(std::move(data))
|
||||||
, fFailed(false)
|
, fFailed(false)
|
||||||
{
|
{
|
||||||
fFrameHolder.setScreenSize(width, height);
|
const auto& eInfo = this->getEncodedInfo();
|
||||||
|
fFrameHolder.setScreenSize(eInfo.width(), eInfo.height());
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
#define SkWebpCodec_DEFINED
|
#define SkWebpCodec_DEFINED
|
||||||
|
|
||||||
#include "SkCodec.h"
|
#include "SkCodec.h"
|
||||||
#include "SkColorSpace.h"
|
|
||||||
#include "SkEncodedImageFormat.h"
|
#include "SkEncodedImageFormat.h"
|
||||||
#include "SkFrameHolder.h"
|
#include "SkFrameHolder.h"
|
||||||
#include "SkImageInfo.h"
|
#include "SkImageInfo.h"
|
||||||
@ -47,8 +46,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkWebpCodec(int width, int height, const SkEncodedInfo&, sk_sp<SkColorSpace>,
|
SkWebpCodec(SkEncodedInfo&&, std::unique_ptr<SkStream>, WebPDemuxer*, sk_sp<SkData>,
|
||||||
std::unique_ptr<SkStream>, WebPDemuxer*, sk_sp<SkData>, SkEncodedOrigin);
|
SkEncodedOrigin);
|
||||||
|
|
||||||
SkAutoTCallVProc<WebPDemuxer, WebPDemuxDelete> fDemux;
|
SkAutoTCallVProc<WebPDemuxer, WebPDemuxDelete> fDemux;
|
||||||
|
|
||||||
|
@ -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) {
|
DEF_TEST(Codec_crbug807324, r) {
|
||||||
if (GetResourcePath().isEmpty()) {
|
if (GetResourcePath().isEmpty()) {
|
||||||
return;
|
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