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; }
bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream); if (NULL == imageSrc) { return false; } SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc); CGImageRef image = CGImageSourceCreateImageAtIndex(imageSrc, 0, NULL); if (NULL == image) { return false; } SkAutoTCallVProc<CGImage, CGImageRelease> arimage(image); const int width = SkToInt(CGImageGetWidth(image)); const int height = SkToInt(CGImageGetHeight(image)); bm->setInfo(SkImageInfo::MakeN32Premul(width, height)); if (SkImageDecoder::kDecodeBounds_Mode == mode) { return true; } if (!this->allocPixelRef(bm, NULL)) { return false; } SkAutoLockPixels alp(*bm); if (!SkCopyPixelsFromCGImage(bm->info(), bm->rowBytes(), bm->getPixels(), image)) { return false; } CGImageAlphaInfo info = CGImageGetAlphaInfo(image); switch (info) { case kCGImageAlphaNone: case kCGImageAlphaNoneSkipLast: case kCGImageAlphaNoneSkipFirst: SkASSERT(SkBitmap::ComputeIsOpaque(*bm)); bm->setAlphaType(kOpaque_SkAlphaType); break; default: // we don't know if we're opaque or not, so compute it. if (SkBitmap::ComputeIsOpaque(*bm)) { bm->setAlphaType(kOpaque_SkAlphaType); } } if (!bm->isOpaque() && this->getRequireUnpremultipliedColors()) { // CGBitmapContext does not support unpremultiplied, so the image has been premultiplied. // Convert to unpremultiplied. for (int i = 0; i < width; ++i) { for (int j = 0; j < height; ++j) { uint32_t* addr = bm->getAddr32(i, j); *addr = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(*addr); } } bm->setAlphaType(kUnpremul_SkAlphaType); } return true; }
bool SkImageGeneratorCG::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) { if (kN32_SkColorType != info.colorType()) { // FIXME: Support other colorTypes. return false; } switch (info.alphaType()) { case kOpaque_SkAlphaType: if (kOpaque_SkAlphaType != this->getInfo().alphaType()) { return false; } break; case kPremul_SkAlphaType: break; default: return false; } CGImageRef image = CGImageSourceCreateImageAtIndex((CGImageSourceRef) fImageSrc.get(), 0, nullptr); if (!image) { return false; } 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; }