Make SkImageGeneratorCG apply encoded origin
SkImageGeneratorCG: - Detect the origin and apply it to the output - Deprecate NewFromEncodedCG and add MakeFromEncodedCG SkCodecImageGenerator: - Move code elsewhere for sharing - Apply origin for incomplete decodes SkPixmap.cpp/SkPixmapPriv.h: - Now has the shared code for generators to apply origin DMSrcSink.cpp: - Call MakeFromEncodedCG SkCGUtils.h: - Add a version of SkCopyPixelsFromCGImage that takes an SkPixmap Bug: skia:7138 Bug: skia:3834 Change-Id: Ic6dbc76360c6a84913b67373582f328d3946d637 Reviewed-on: https://skia-review.googlesource.com/63740 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Leon Scroggins <scroggo@google.com>
This commit is contained in:
parent
60aaeb2b55
commit
0cbc10f94e
@ -942,7 +942,7 @@ Error ImageGenSrc::draw(SkCanvas* canvas) const {
|
||||
break;
|
||||
case kPlatform_Mode: {
|
||||
#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
|
||||
gen.reset(SkImageGeneratorCG::NewFromEncodedCG(encoded.get()));
|
||||
gen = SkImageGeneratorCG::MakeFromEncodedCG(encoded);
|
||||
#elif defined(SK_BUILD_FOR_WIN)
|
||||
gen.reset(SkImageGeneratorWIC::NewFromEncodedWIC(encoded.get()));
|
||||
#endif
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "SkSize.h"
|
||||
#include "SkImageInfo.h"
|
||||
#include "SkImage.h"
|
||||
#include "SkPixmap.h"
|
||||
|
||||
#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
|
||||
|
||||
@ -46,6 +47,9 @@ SK_API sk_sp<SkImage> SkMakeImageFromCGImage(CGImageRef);
|
||||
*/
|
||||
SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* dstPixels,
|
||||
CGImageRef src);
|
||||
static inline bool SkCopyPixelsFromCGImage(const SkPixmap& dst, CGImageRef src) {
|
||||
return SkCopyPixelsFromCGImage(dst.info(), dst.rowBytes(), dst.writable_addr(), src);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an imageref from the specified bitmap using the specified colorspace.
|
||||
|
@ -5,42 +5,10 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "SkAutoPixmapStorage.h"
|
||||
#include "SkCodecImageGenerator.h"
|
||||
#include "SkMakeUnique.h"
|
||||
#include "SkPixmapPriv.h"
|
||||
|
||||
#define kMirrorX SkPixmapPriv::kMirrorX
|
||||
#define kMirrorY SkPixmapPriv::kMirrorY
|
||||
#define kSwapXY SkPixmapPriv::kSwapXY
|
||||
|
||||
const uint8_t gOrientationFlags[] = {
|
||||
0, // kTopLeft_SkEncodedOrigin
|
||||
kMirrorX, // kTopRight_SkEncodedOrigin
|
||||
kMirrorX | kMirrorY, // kBottomRight_SkEncodedOrigin
|
||||
kMirrorY, // kBottomLeft_SkEncodedOrigin
|
||||
kSwapXY, // kLeftTop_SkEncodedOrigin
|
||||
kMirrorX | kSwapXY, // kRightTop_SkEncodedOrigin
|
||||
kMirrorX | kMirrorY | kSwapXY, // kRightBottom_SkEncodedOrigin
|
||||
kMirrorY | kSwapXY, // kLeftBottom_SkEncodedOrigin
|
||||
};
|
||||
|
||||
SkPixmapPriv::OrientFlags SkPixmapPriv::OriginToOrient(SkEncodedOrigin o) {
|
||||
unsigned io = static_cast<int>(o) - 1;
|
||||
SkASSERT(io < SK_ARRAY_COUNT(gOrientationFlags));
|
||||
return static_cast<SkPixmapPriv::OrientFlags>(gOrientationFlags[io]);
|
||||
}
|
||||
|
||||
static bool should_swap_width_height(SkEncodedOrigin o) {
|
||||
return SkToBool(SkPixmapPriv::OriginToOrient(o) & kSwapXY);
|
||||
}
|
||||
|
||||
static SkImageInfo swap_width_height(SkImageInfo info) {
|
||||
return info.makeWH(info.height(), info.width());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unique_ptr<SkImageGenerator> SkCodecImageGenerator::MakeFromEncodedCodec(sk_sp<SkData> data) {
|
||||
auto codec = SkCodec::MakeFromData(data);
|
||||
if (nullptr == codec) {
|
||||
@ -55,8 +23,8 @@ static SkImageInfo adjust_info(SkCodec* codec) {
|
||||
if (kUnpremul_SkAlphaType == info.alphaType()) {
|
||||
info = info.makeAlphaType(kPremul_SkAlphaType);
|
||||
}
|
||||
if (should_swap_width_height(codec->getOrigin())) {
|
||||
info = swap_width_height(info);
|
||||
if (SkPixmapPriv::ShouldSwapWidthHeight(codec->getOrigin())) {
|
||||
info = SkPixmapPriv::SwapWidthHeight(info);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
@ -73,39 +41,23 @@ SkData* SkCodecImageGenerator::onRefEncodedData() {
|
||||
|
||||
bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& requestInfo, void* requestPixels,
|
||||
size_t requestRowBytes, const Options& opts) {
|
||||
const auto origin = fCodec->getOrigin();
|
||||
const SkPixmap request(requestInfo, requestPixels, requestRowBytes);
|
||||
const SkPixmap* codecMap = &request;
|
||||
SkAutoPixmapStorage storage; // used if we have to post-orient the output from the codec
|
||||
SkPixmap dst(requestInfo, requestPixels, requestRowBytes);
|
||||
|
||||
if (origin != kTopLeft_SkEncodedOrigin) {
|
||||
SkImageInfo info = requestInfo;
|
||||
if (should_swap_width_height(origin)) {
|
||||
info = swap_width_height(info);
|
||||
auto decode = [this, &opts](const SkPixmap& pm) {
|
||||
SkCodec::Options codecOpts;
|
||||
codecOpts.fPremulBehavior = opts.fBehavior;
|
||||
SkCodec::Result result = fCodec->getPixels(pm, &codecOpts);
|
||||
switch (result) {
|
||||
case SkCodec::kSuccess:
|
||||
case SkCodec::kIncompleteInput:
|
||||
case SkCodec::kErrorInInput:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
// need a tmp buffer to receive the pixels, so we can post-orient them
|
||||
if (!storage.tryAlloc(info)) {
|
||||
return false;
|
||||
}
|
||||
codecMap = &storage;
|
||||
}
|
||||
};
|
||||
|
||||
SkCodec::Options codecOpts;
|
||||
codecOpts.fPremulBehavior = opts.fBehavior;
|
||||
SkCodec::Result result = fCodec->getPixels(*codecMap, &codecOpts);
|
||||
switch (result) {
|
||||
case SkCodec::kSuccess:
|
||||
if (codecMap != &request) {
|
||||
return SkPixmapPriv::Orient(request, *codecMap,
|
||||
SkPixmapPriv::OriginToOrient(origin));
|
||||
}
|
||||
// fall through
|
||||
case SkCodec::kIncompleteInput:
|
||||
case SkCodec::kErrorInInput:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return SkPixmapPriv::Orient(dst, fCodec->getOrigin(), decode);
|
||||
}
|
||||
|
||||
bool SkCodecImageGenerator::onQueryYUV8(SkYUVSizeInfo* sizeInfo, SkYUVColorSpace* colorSpace) const
|
||||
|
@ -446,3 +446,32 @@ bool SkPixmapPriv::Orient(const SkPixmap& dst, const SkPixmap& src, OrientFlags
|
||||
return draw_orientation(dst, src, flags);
|
||||
}
|
||||
|
||||
#define kMirrorX SkPixmapPriv::kMirrorX
|
||||
#define kMirrorY SkPixmapPriv::kMirrorY
|
||||
#define kSwapXY SkPixmapPriv::kSwapXY
|
||||
|
||||
static constexpr uint8_t gOrientationFlags[] = {
|
||||
0, // kTopLeft_SkEncodedOrigin
|
||||
kMirrorX, // kTopRight_SkEncodedOrigin
|
||||
kMirrorX | kMirrorY, // kBottomRight_SkEncodedOrigin
|
||||
kMirrorY, // kBottomLeft_SkEncodedOrigin
|
||||
kSwapXY, // kLeftTop_SkEncodedOrigin
|
||||
kMirrorX | kSwapXY, // kRightTop_SkEncodedOrigin
|
||||
kMirrorX | kMirrorY | kSwapXY, // kRightBottom_SkEncodedOrigin
|
||||
kMirrorY | kSwapXY, // kLeftBottom_SkEncodedOrigin
|
||||
};
|
||||
|
||||
SkPixmapPriv::OrientFlags SkPixmapPriv::OriginToOrient(SkEncodedOrigin o) {
|
||||
unsigned io = static_cast<int>(o) - 1;
|
||||
SkASSERT(io < SK_ARRAY_COUNT(gOrientationFlags));
|
||||
return static_cast<SkPixmapPriv::OrientFlags>(gOrientationFlags[io]);
|
||||
}
|
||||
|
||||
bool SkPixmapPriv::ShouldSwapWidthHeight(SkEncodedOrigin o) {
|
||||
return SkToBool(OriginToOrient(o) & kSwapXY);
|
||||
}
|
||||
|
||||
SkImageInfo SkPixmapPriv::SwapWidthHeight(const SkImageInfo& info) {
|
||||
return info.makeWH(info.height(), info.width());
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "SkPixmap.h"
|
||||
#include "SkEncodedOrigin.h"
|
||||
#include "SkAutoPixmapStorage.h"
|
||||
|
||||
class SkPixmapPriv {
|
||||
public:
|
||||
@ -27,6 +28,41 @@ public:
|
||||
* by the flags. If the inputs are invalid, this returns false and no copy is made.
|
||||
*/
|
||||
static bool Orient(const SkPixmap& dst, const SkPixmap& src, OrientFlags);
|
||||
|
||||
static bool ShouldSwapWidthHeight(SkEncodedOrigin o);
|
||||
static SkImageInfo SwapWidthHeight(const SkImageInfo& info);
|
||||
|
||||
/**
|
||||
* Decode an image and then copy into dst, applying origin.
|
||||
*
|
||||
* @param dst SkPixmap to write the final image, after
|
||||
* applying the origin.
|
||||
* @param origin SkEncodedOrigin to apply to the raw pixels.
|
||||
* @param decode Function for decoding into a pixmap without
|
||||
* applying the origin.
|
||||
*/
|
||||
static bool Orient(const SkPixmap& dst, SkEncodedOrigin origin,
|
||||
std::function<bool(const SkPixmap&)> decode) {
|
||||
SkAutoPixmapStorage storage;
|
||||
const SkPixmap* tmp = &dst;
|
||||
if (origin != kTopLeft_SkEncodedOrigin) {
|
||||
auto info = dst.info();
|
||||
if (ShouldSwapWidthHeight(origin)) {
|
||||
info = SwapWidthHeight(info);
|
||||
}
|
||||
if (!storage.tryAlloc(info)) {
|
||||
return false;
|
||||
}
|
||||
tmp = &storage;
|
||||
}
|
||||
if (!decode(*tmp)) {
|
||||
return false;
|
||||
}
|
||||
if (tmp != &dst) {
|
||||
return Orient(dst, *tmp, OriginToOrient(origin));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "SkImageGeneratorCG.h"
|
||||
#include "SkPixmapPriv.h"
|
||||
|
||||
#ifdef SK_BUILD_FOR_MAC
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
@ -28,8 +29,14 @@ static CGImageSourceRef data_to_CGImageSrc(SkData* data) {
|
||||
return imageSrc;
|
||||
}
|
||||
|
||||
#ifdef SK_LEGACY_NEW_FROM_ENCODED_CG
|
||||
SkImageGenerator* SkImageGeneratorCG::NewFromEncodedCG(SkData* data) {
|
||||
CGImageSourceRef imageSrc = data_to_CGImageSrc(data);
|
||||
return MakeFromEncodedCG(sk_ref_sp(data)).release();
|
||||
}
|
||||
#endif
|
||||
|
||||
std::unique_ptr<SkImageGenerator> SkImageGeneratorCG::MakeFromEncodedCG(sk_sp<SkData> data) {
|
||||
CGImageSourceRef imageSrc = data_to_CGImageSrc(data.get());
|
||||
if (!imageSrc) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -50,8 +57,6 @@ SkImageGenerator* SkImageGeneratorCG::NewFromEncodedCG(SkData* data) {
|
||||
if (nullptr == widthRef || nullptr == heightRef) {
|
||||
return nullptr;
|
||||
}
|
||||
bool hasAlpha = (bool) (CFDictionaryGetValue(properties,
|
||||
kCGImagePropertyHasAlpha));
|
||||
|
||||
int width, height;
|
||||
if (!CFNumberGetValue(widthRef, kCFNumberIntType, &width) ||
|
||||
@ -59,20 +64,37 @@ SkImageGenerator* SkImageGeneratorCG::NewFromEncodedCG(SkData* data) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool hasAlpha = (bool) (CFDictionaryGetValue(properties,
|
||||
kCGImagePropertyHasAlpha));
|
||||
SkAlphaType alphaType = hasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType;
|
||||
SkImageInfo info = SkImageInfo::MakeS32(width, height, alphaType);
|
||||
|
||||
auto origin = kDefault_SkEncodedOrigin;
|
||||
auto orientationRef = (CFNumberRef) (CFDictionaryGetValue(properties,
|
||||
kCGImagePropertyOrientation));
|
||||
int originInt;
|
||||
if (orientationRef && CFNumberGetValue(orientationRef, kCFNumberIntType, &originInt)) {
|
||||
origin = (SkEncodedOrigin) originInt;
|
||||
}
|
||||
|
||||
if (SkPixmapPriv::ShouldSwapWidthHeight(origin)) {
|
||||
info = SkPixmapPriv::SwapWidthHeight(info);
|
||||
}
|
||||
|
||||
// FIXME: We have the opportunity to extract color space information here,
|
||||
// though I think it makes sense to wait until we understand how
|
||||
// we want to communicate it to the generator.
|
||||
|
||||
return new SkImageGeneratorCG(info, autoImageSrc.release(), data);
|
||||
return std::unique_ptr<SkImageGenerator>(new SkImageGeneratorCG(info, autoImageSrc.release(),
|
||||
std::move(data), origin));
|
||||
}
|
||||
|
||||
SkImageGeneratorCG::SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc, SkData* data)
|
||||
SkImageGeneratorCG::SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc,
|
||||
sk_sp<SkData> data, SkEncodedOrigin origin)
|
||||
: INHERITED(info)
|
||||
, fImageSrc(imageSrc)
|
||||
, fData(SkRef(data))
|
||||
, fData(std::move(data))
|
||||
, fOrigin(origin)
|
||||
{}
|
||||
|
||||
SkData* SkImageGeneratorCG::onRefEncodedData() {
|
||||
@ -105,18 +127,17 @@ bool SkImageGeneratorCG::onGetPixels(const SkImageInfo& info, void* pixels, size
|
||||
}
|
||||
SkAutoTCallVProc<CGImage, CGImageRelease> autoImage(image);
|
||||
|
||||
// FIXME: Using this function (as opposed to swizzling ourselves) greatly
|
||||
// restricts the color and alpha types that we support. If we
|
||||
// swizzle ourselves, we can add support for:
|
||||
// kUnpremul_SkAlphaType
|
||||
// 16-bit per component RGBA
|
||||
// kGray_8_SkColorType
|
||||
// kIndex_8_SkColorType
|
||||
// Additionally, it would be interesting to compare the performance
|
||||
// of SkSwizzler with CG's built in swizzler.
|
||||
if (!SkCopyPixelsFromCGImage(info, rowBytes, pixels, image)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
SkPixmap dst(info, pixels, rowBytes);
|
||||
auto decode = [&image](const SkPixmap& pm) {
|
||||
// FIXME: Using SkCopyPixelsFromCGImage (as opposed to swizzling
|
||||
// ourselves) greatly restricts the color and alpha types that we
|
||||
// support. If we swizzle ourselves, we can add support for:
|
||||
// kUnpremul_SkAlphaType
|
||||
// 16-bit per component RGBA
|
||||
// kGray_8_SkColorType
|
||||
// Additionally, it would be interesting to compare the performance
|
||||
// of SkSwizzler with CG's built in swizzler.
|
||||
return SkCopyPixelsFromCGImage(pm, image);
|
||||
};
|
||||
return SkPixmapPriv::Orient(dst, fOrigin, decode);
|
||||
}
|
||||
|
@ -10,16 +10,21 @@
|
||||
|
||||
#include "SkCGUtils.h"
|
||||
#include "SkData.h"
|
||||
#include "SkEncodedOrigin.h"
|
||||
#include "SkImageGenerator.h"
|
||||
#include "SkTemplates.h"
|
||||
|
||||
class SkImageGeneratorCG : public SkImageGenerator {
|
||||
public:
|
||||
#ifdef SK_LEGACY_NEW_FROM_ENCODED_CG
|
||||
/*
|
||||
* Refs the data if an image generator can be returned. Otherwise does
|
||||
* not affect the data.
|
||||
*/
|
||||
static SkImageGenerator* NewFromEncodedCG(SkData* data);
|
||||
#endif
|
||||
|
||||
static std::unique_ptr<SkImageGenerator> MakeFromEncodedCG(sk_sp<SkData>);
|
||||
|
||||
protected:
|
||||
SkData* onRefEncodedData() override;
|
||||
@ -30,12 +35,13 @@ protected:
|
||||
private:
|
||||
/*
|
||||
* Takes ownership of the imageSrc
|
||||
* Refs the data
|
||||
*/
|
||||
SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc, SkData* data);
|
||||
SkImageGeneratorCG(const SkImageInfo& info, const void* imageSrc, sk_sp<SkData> data,
|
||||
SkEncodedOrigin origin);
|
||||
|
||||
SkAutoTCallVProc<const void, CFRelease> fImageSrc;
|
||||
sk_sp<SkData> fData;
|
||||
const SkEncodedOrigin fOrigin;
|
||||
|
||||
typedef SkImageGenerator INHERITED;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user