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:
Leon Scroggins III 2017-10-30 09:07:53 -04:00 committed by Skia Commit-Bot
parent 60aaeb2b55
commit 0cbc10f94e
7 changed files with 135 additions and 87 deletions

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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());
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;
};