зеркало из https://github.com/mozilla/moz-skia.git
expose CGImage -> SkBitmap
BUG=skia: R=scroggo@google.com, halcanary@google.com Author: reed@google.com Review URL: https://codereview.chromium.org/243463005 git-svn-id: http://skia.googlecode.com/svn/trunk@14315 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
945ec3a2be
Коммит
60b5dce199
|
@ -108,3 +108,91 @@ private:
|
|||
};
|
||||
|
||||
DEF_GM( return SkNEW(AAClipGM); )
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef SK_BUILD_FOR_MAC
|
||||
|
||||
static SkCanvas* make_canvas(const SkBitmap& bm) {
|
||||
const SkImageInfo& info = bm.info();
|
||||
if (info.bytesPerPixel() == 4) {
|
||||
return SkCanvas::NewRasterDirectN32(info.width(), info.height(),
|
||||
(SkPMColor*)bm.getPixels(),
|
||||
bm.rowBytes());
|
||||
} else {
|
||||
return SkNEW_ARGS(SkCanvas, (bm));
|
||||
}
|
||||
}
|
||||
|
||||
#include "SkCGUtils.h"
|
||||
static void test_image(SkCanvas* canvas, const SkImageInfo& info) {
|
||||
SkBitmap bm;
|
||||
bm.allocPixels(info);
|
||||
|
||||
SkAutoTUnref<SkCanvas> newc(make_canvas(bm));
|
||||
if (info.isOpaque()) {
|
||||
bm.eraseColor(SK_ColorGREEN);
|
||||
} else {
|
||||
bm.eraseColor(0);
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(SK_ColorBLUE);
|
||||
newc->drawCircle(50, 50, 49, paint);
|
||||
canvas->drawBitmap(bm, 10, 10);
|
||||
|
||||
CGImageRef image = SkCreateCGImageRefWithColorspace(bm, NULL);
|
||||
|
||||
SkBitmap bm2;
|
||||
SkCreateBitmapFromCGImage(&bm2, image);
|
||||
CGImageRelease(image);
|
||||
|
||||
canvas->drawBitmap(bm2, 10, 120);
|
||||
}
|
||||
|
||||
class CGImageGM : public skiagm::GM {
|
||||
public:
|
||||
CGImageGM() {}
|
||||
|
||||
protected:
|
||||
virtual SkString onShortName() SK_OVERRIDE {
|
||||
return SkString("cgimage");
|
||||
}
|
||||
|
||||
virtual SkISize onISize() SK_OVERRIDE {
|
||||
return SkISize::Make(800, 250);
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
|
||||
const struct {
|
||||
SkColorType fCT;
|
||||
SkAlphaType fAT;
|
||||
} rec[] = {
|
||||
{ kRGB_565_SkColorType, kOpaque_SkAlphaType },
|
||||
|
||||
{ kRGBA_8888_SkColorType, kPremul_SkAlphaType },
|
||||
{ kRGBA_8888_SkColorType, kUnpremul_SkAlphaType },
|
||||
{ kRGBA_8888_SkColorType, kOpaque_SkAlphaType },
|
||||
|
||||
{ kBGRA_8888_SkColorType, kPremul_SkAlphaType },
|
||||
{ kBGRA_8888_SkColorType, kUnpremul_SkAlphaType },
|
||||
{ kBGRA_8888_SkColorType, kOpaque_SkAlphaType },
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(rec); ++i) {
|
||||
SkImageInfo info = SkImageInfo::Make(100, 100, rec[i].fCT, rec[i].fAT);
|
||||
test_image(canvas, info);
|
||||
canvas->translate(info.width() + 10, 0);
|
||||
}
|
||||
}
|
||||
|
||||
virtual uint32_t onGetFlags() const SK_OVERRIDE { return kSkipPipe_Flag; }
|
||||
|
||||
private:
|
||||
typedef skiagm::GM INHERITED;
|
||||
};
|
||||
|
||||
DEF_GM( return SkNEW(CGImageGM); )
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
#ifndef SkCGUtils_DEFINED
|
||||
#define SkCGUtils_DEFINED
|
||||
|
||||
#include "SkTypes.h"
|
||||
#include "SkSize.h"
|
||||
#include "SkImageInfo.h"
|
||||
|
||||
#ifdef SK_BUILD_FOR_MAC
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
|
@ -22,6 +23,22 @@ class SkBitmap;
|
|||
class SkData;
|
||||
class SkStream;
|
||||
|
||||
/**
|
||||
* Given a CGImage, allocate an SkBitmap and copy the image's pixels into it. If scaleToFit is not
|
||||
* null, use it to determine the size of the bitmap, and scale the image to fill the bitmap.
|
||||
* Otherwise use the image's width/height.
|
||||
*
|
||||
* On failure, return false, and leave bitmap unchanged.
|
||||
*/
|
||||
SK_API bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef src, SkISize* scaleToFit = NULL);
|
||||
|
||||
/**
|
||||
* Copy the pixels from src into the memory specified by info/rowBytes/dstPixels. On failure,
|
||||
* return false (e.g. ImageInfo incompatible with src).
|
||||
*/
|
||||
SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* dstPixels,
|
||||
CGImageRef src);
|
||||
|
||||
/**
|
||||
* Create an imageref from the specified bitmap using the specified colorspace.
|
||||
* If space is NULL, then CGColorSpaceCreateDeviceRGB() is used.
|
||||
|
|
|
@ -997,7 +997,8 @@ bool SkBitmap::canCopyTo(SkColorType dstColorType) const {
|
|||
switch (dstColorType) {
|
||||
case kAlpha_8_SkColorType:
|
||||
case kRGB_565_SkColorType:
|
||||
case kN32_SkColorType:
|
||||
case kRGBA_8888_SkColorType:
|
||||
case kBGRA_8888_SkColorType:
|
||||
break;
|
||||
case kIndex_8_SkColorType:
|
||||
if (!sameConfigs) {
|
||||
|
|
|
@ -68,7 +68,9 @@ bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
|
|||
|
||||
const int width = SkToInt(CGImageGetWidth(image));
|
||||
const int height = SkToInt(CGImageGetHeight(image));
|
||||
bm->setConfig(SkBitmap::kARGB_8888_Config, width, height);
|
||||
SkImageInfo skinfo = SkImageInfo::MakeN32Premul(width, height);
|
||||
|
||||
bm->setConfig(skinfo);
|
||||
if (SkImageDecoder::kDecodeBounds_Mode == mode) {
|
||||
return true;
|
||||
}
|
||||
|
@ -76,16 +78,12 @@ bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
|
|||
if (!this->allocPixelRef(bm, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkAutoLockPixels alp(*bm);
|
||||
|
||||
bm->lockPixels();
|
||||
bm->eraseColor(SK_ColorTRANSPARENT);
|
||||
|
||||
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef cg = CGBitmapContextCreate(bm->getPixels(), width, height, 8, bm->rowBytes(), cs, BITMAP_INFO);
|
||||
CFRelease(cs);
|
||||
|
||||
CGContextDrawImage(cg, CGRectMake(0, 0, width, height), image);
|
||||
CGContextRelease(cg);
|
||||
if (!SkCopyPixelsFromCGImage(bm->info(), bm->rowBytes(), bm->getPixels(), image)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CGImageAlphaInfo info = CGImageGetAlphaInfo(image);
|
||||
switch (info) {
|
||||
|
@ -112,7 +110,6 @@ bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
|
|||
}
|
||||
bm->setAlphaType(kUnpremul_SkAlphaType);
|
||||
}
|
||||
bm->unlockPixels();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,40 @@
|
|||
#include "SkBitmap.h"
|
||||
#include "SkColorPriv.h"
|
||||
|
||||
static CGBitmapInfo ComputeCGAlphaInfo_RGBA(SkAlphaType at) {
|
||||
CGBitmapInfo info = kCGBitmapByteOrder32Big;
|
||||
switch (at) {
|
||||
case kOpaque_SkAlphaType:
|
||||
case kIgnore_SkAlphaType:
|
||||
info |= kCGImageAlphaNoneSkipLast;
|
||||
break;
|
||||
case kPremul_SkAlphaType:
|
||||
info |= kCGImageAlphaPremultipliedLast;
|
||||
break;
|
||||
case kUnpremul_SkAlphaType:
|
||||
info |= kCGImageAlphaLast;
|
||||
break;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
static CGBitmapInfo ComputeCGAlphaInfo_BGRA(SkAlphaType at) {
|
||||
CGBitmapInfo info = kCGBitmapByteOrder32Little;
|
||||
switch (at) {
|
||||
case kOpaque_SkAlphaType:
|
||||
case kIgnore_SkAlphaType:
|
||||
info |= kCGImageAlphaNoneSkipFirst;
|
||||
break;
|
||||
case kPremul_SkAlphaType:
|
||||
info |= kCGImageAlphaPremultipliedFirst;
|
||||
break;
|
||||
case kUnpremul_SkAlphaType:
|
||||
info |= kCGImageAlphaFirst;
|
||||
break;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) {
|
||||
SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info);
|
||||
delete bitmap;
|
||||
|
@ -28,44 +62,23 @@ static bool getBitmapInfo(const SkBitmap& bm,
|
|||
// doesn't see quite right. Are they thinking 1555?
|
||||
*bitsPerComponent = 5;
|
||||
*info = kCGBitmapByteOrder16Little | kCGImageAlphaNone;
|
||||
break;
|
||||
#endif
|
||||
#else
|
||||
if (upscaleTo32) {
|
||||
*upscaleTo32 = true;
|
||||
}
|
||||
// fall through
|
||||
case kN32_SkColorType:
|
||||
// now treat like RGBA
|
||||
*bitsPerComponent = 8;
|
||||
#if SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
|
||||
*info = kCGBitmapByteOrder32Big;
|
||||
if (bm.isOpaque()) {
|
||||
*info |= kCGImageAlphaNoneSkipLast;
|
||||
} else {
|
||||
*info |= kCGImageAlphaPremultipliedLast;
|
||||
}
|
||||
#elif SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
|
||||
// Matches the CGBitmapInfo that Apple recommends for best
|
||||
// performance, used by google chrome.
|
||||
*info = kCGBitmapByteOrder32Little;
|
||||
if (bm.isOpaque()) {
|
||||
*info |= kCGImageAlphaNoneSkipFirst;
|
||||
} else {
|
||||
*info |= kCGImageAlphaPremultipliedFirst;
|
||||
}
|
||||
#else
|
||||
// ...add more formats as required...
|
||||
#warning Cannot convert SkBitmap to CGImageRef with these shiftmasks. \
|
||||
This will probably not work.
|
||||
// Legacy behavior. Perhaps turn this into an error at some
|
||||
// point.
|
||||
*info = kCGBitmapByteOrder32Big;
|
||||
if (bm.isOpaque()) {
|
||||
*info |= kCGImageAlphaNoneSkipLast;
|
||||
} else {
|
||||
*info |= kCGImageAlphaPremultipliedLast;
|
||||
}
|
||||
*info = ComputeCGAlphaInfo_RGBA(kOpaque_SkAlphaType);
|
||||
#endif
|
||||
break;
|
||||
case kRGBA_8888_SkColorType:
|
||||
*bitsPerComponent = 8;
|
||||
*info = ComputeCGAlphaInfo_RGBA(bm.alphaType());
|
||||
break;
|
||||
case kBGRA_8888_SkColorType:
|
||||
*bitsPerComponent = 8;
|
||||
*info = ComputeCGAlphaInfo_BGRA(bm.alphaType());
|
||||
break;
|
||||
case kARGB_4444_SkColorType:
|
||||
*bitsPerComponent = 4;
|
||||
*info = kCGBitmapByteOrder16Little;
|
||||
|
@ -231,3 +244,73 @@ bool SkPDFDocumentToBitmap(SkStream* stream, SkBitmap* output) {
|
|||
output->swap(bitmap);
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels,
|
||||
CGImageRef image) {
|
||||
CGBitmapInfo cg_bitmap_info = 0;
|
||||
size_t bitsPerComponent = 0;
|
||||
switch (info.colorType()) {
|
||||
case kRGBA_8888_SkColorType:
|
||||
bitsPerComponent = 8;
|
||||
cg_bitmap_info = ComputeCGAlphaInfo_RGBA(info.alphaType());
|
||||
break;
|
||||
case kBGRA_8888_SkColorType:
|
||||
bitsPerComponent = 8;
|
||||
cg_bitmap_info = ComputeCGAlphaInfo_BGRA(info.alphaType());
|
||||
break;
|
||||
default:
|
||||
return false; // no other colortypes are supported (for now)
|
||||
}
|
||||
|
||||
CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef cg = CGBitmapContextCreate(pixels, info.width(), info.height(), bitsPerComponent,
|
||||
rowBytes, cs, cg_bitmap_info);
|
||||
CFRelease(cs);
|
||||
if (NULL == cg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// use this blend mode, to avoid having to erase the pixels first, and to avoid CG performing
|
||||
// any blending (which could introduce errors and be slower).
|
||||
CGContextSetBlendMode(cg, kCGBlendModeCopy);
|
||||
|
||||
CGContextDrawImage(cg, CGRectMake(0, 0, info.width(), info.height()), image);
|
||||
CGContextRelease(cg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkCreateBitmapFromCGImage(SkBitmap* dst, CGImageRef image, SkISize* scaleToFit) {
|
||||
const int width = scaleToFit ? scaleToFit->width() : SkToInt(CGImageGetWidth(image));
|
||||
const int height = scaleToFit ? scaleToFit->height() : SkToInt(CGImageGetHeight(image));
|
||||
SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
|
||||
|
||||
SkBitmap tmp;
|
||||
if (!tmp.allocPixels(info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SkCopyPixelsFromCGImage(tmp.info(), tmp.rowBytes(), tmp.getPixels(), image)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CGImageAlphaInfo cgInfo = CGImageGetAlphaInfo(image);
|
||||
switch (cgInfo) {
|
||||
case kCGImageAlphaNone:
|
||||
case kCGImageAlphaNoneSkipLast:
|
||||
case kCGImageAlphaNoneSkipFirst:
|
||||
SkASSERT(SkBitmap::ComputeIsOpaque(tmp));
|
||||
tmp.setAlphaType(kOpaque_SkAlphaType);
|
||||
break;
|
||||
default:
|
||||
// we don't know if we're opaque or not, so compute it.
|
||||
if (SkBitmap::ComputeIsOpaque(tmp)) {
|
||||
tmp.setAlphaType(kOpaque_SkAlphaType);
|
||||
}
|
||||
}
|
||||
|
||||
*dst = tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче