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:
commit-bot@chromium.org 2014-04-22 20:24:33 +00:00
Родитель 945ec3a2be
Коммит 60b5dce199
5 изменённых файлов: 231 добавлений и 45 удалений

Просмотреть файл

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