Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(956)

Unified Diff: src/ports/SkImageDecoder_CG.cpp

Issue 1828433004: Revert of Delete SkImageDecoder (Closed) Base URL: https://skia.googlesource.com/skia.git@fix-animator
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/images/bmpdecoderhelper.cpp ('k') | src/ports/SkImageDecoder_WIC.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/ports/SkImageDecoder_CG.cpp
diff --git a/src/ports/SkImageDecoder_CG.cpp b/src/ports/SkImageDecoder_CG.cpp
index ead0ed6506ff19d5c602d541a87543620bad291e..c4446ae16d67ef5671c817af569f188a73fe177d 100644
--- a/src/ports/SkImageDecoder_CG.cpp
+++ b/src/ports/SkImageDecoder_CG.cpp
@@ -11,6 +11,7 @@
#include "SkCGUtils.h"
#include "SkColorPriv.h"
#include "SkData.h"
+#include "SkImageDecoder.h"
#include "SkImageEncoder.h"
#include "SkMovie.h"
#include "SkStream.h"
@@ -27,6 +28,210 @@
#include <ImageIO/ImageIO.h>
#include <MobileCoreServices/MobileCoreServices.h>
#endif
+
+static void data_unref_proc(void* skdata, const void*, size_t) {
+ SkASSERT(skdata);
+ static_cast<SkData*>(skdata)->unref();
+}
+
+static CGDataProviderRef SkStreamToDataProvider(SkStream* stream) {
+ // TODO: use callbacks, so we don't have to load all the data into RAM
+ SkData* skdata = SkCopyStreamToData(stream).release();
+ if (!skdata) {
+ return nullptr;
+ }
+
+ return CGDataProviderCreateWithData(skdata, skdata->data(), skdata->size(), data_unref_proc);
+}
+
+static CGImageSourceRef SkStreamToCGImageSource(SkStream* stream) {
+ CGDataProviderRef data = SkStreamToDataProvider(stream);
+ if (!data) {
+ return nullptr;
+ }
+ CGImageSourceRef imageSrc = CGImageSourceCreateWithDataProvider(data, 0);
+ CGDataProviderRelease(data);
+ return imageSrc;
+}
+
+class SkImageDecoder_CG : public SkImageDecoder {
+protected:
+ virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode);
+};
+
+static void argb_4444_force_opaque(void* row, int count) {
+ uint16_t* row16 = (uint16_t*)row;
+ for (int i = 0; i < count; ++i) {
+ row16[i] |= 0xF000;
+ }
+}
+
+static void argb_8888_force_opaque(void* row, int count) {
+ // can use RGBA or BGRA, they have the same shift for alpha
+ const uint32_t alphaMask = 0xFF << SK_RGBA_A32_SHIFT;
+ uint32_t* row32 = (uint32_t*)row;
+ for (int i = 0; i < count; ++i) {
+ row32[i] |= alphaMask;
+ }
+}
+
+static void alpha_8_force_opaque(void* row, int count) {
+ memset(row, 0xFF, count);
+}
+
+static void force_opaque(SkBitmap* bm) {
+ SkAutoLockPixels alp(*bm);
+ if (!bm->getPixels()) {
+ return;
+ }
+
+ void (*proc)(void*, int);
+ switch (bm->colorType()) {
+ case kARGB_4444_SkColorType:
+ proc = argb_4444_force_opaque;
+ break;
+ case kRGBA_8888_SkColorType:
+ case kBGRA_8888_SkColorType:
+ proc = argb_8888_force_opaque;
+ break;
+ case kAlpha_8_SkColorType:
+ proc = alpha_8_force_opaque;
+ break;
+ default:
+ return;
+ }
+
+ char* row = (char*)bm->getPixels();
+ for (int y = 0; y < bm->height(); ++y) {
+ proc(row, bm->width());
+ row += bm->rowBytes();
+ }
+ bm->setAlphaType(kOpaque_SkAlphaType);
+}
+
+#define BITMAP_INFO (kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast)
+
+class AutoCFDataRelease {
+ CFDataRef fDR;
+public:
+ AutoCFDataRelease(CFDataRef dr) : fDR(dr) {}
+ ~AutoCFDataRelease() { if (fDR) { CFRelease(fDR); } }
+
+ operator CFDataRef () { return fDR; }
+};
+
+static bool colorspace_is_sRGB(CGColorSpaceRef cs) {
+#ifdef SK_BUILD_FOR_IOS
+ return true; // iOS seems to define itself to always return sRGB <reed>
+#else
+ AutoCFDataRelease data(CGColorSpaceCopyICCProfile(cs));
+ if (data) {
+ // found by inspection -- need a cleaner way to sniff a profile
+ const CFIndex ICC_PROFILE_OFFSET_TO_SRGB_TAG = 52;
+
+ if (CFDataGetLength(data) >= ICC_PROFILE_OFFSET_TO_SRGB_TAG + 4) {
+ return !memcmp(CFDataGetBytePtr(data) + ICC_PROFILE_OFFSET_TO_SRGB_TAG, "sRGB", 4);
+ }
+ }
+ return false;
+#endif
+}
+
+SkImageDecoder::Result SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
+ CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream);
+
+ if (nullptr == imageSrc) {
+ return kFailure;
+ }
+ SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc);
+
+ CGImageRef image = CGImageSourceCreateImageAtIndex(imageSrc, 0, nullptr);
+ if (nullptr == image) {
+ return kFailure;
+ }
+ SkAutoTCallVProc<CGImage, CGImageRelease> arimage(image);
+
+ const int width = SkToInt(CGImageGetWidth(image));
+ const int height = SkToInt(CGImageGetHeight(image));
+ SkColorProfileType cpType = kLinear_SkColorProfileType;
+
+ CGColorSpaceRef cs = CGImageGetColorSpace(image);
+ if (cs) {
+ CGColorSpaceModel m = CGColorSpaceGetModel(cs);
+ if (kCGColorSpaceModelRGB == m && colorspace_is_sRGB(cs)) {
+ cpType = kSRGB_SkColorProfileType;
+ }
+ }
+
+ SkAlphaType at = kPremul_SkAlphaType;
+ switch (CGImageGetAlphaInfo(image)) {
+ case kCGImageAlphaNone:
+ case kCGImageAlphaNoneSkipLast:
+ case kCGImageAlphaNoneSkipFirst:
+ at = kOpaque_SkAlphaType;
+ break;
+ default:
+ break;
+ }
+
+ bm->setInfo(SkImageInfo::Make(width, height, kN32_SkColorType, at, cpType));
+ if (SkImageDecoder::kDecodeBounds_Mode == mode) {
+ return kSuccess;
+ }
+
+ if (!this->allocPixelRef(bm, nullptr)) {
+ return kFailure;
+ }
+
+ SkAutoLockPixels alp(*bm);
+
+ if (!SkCopyPixelsFromCGImage(bm->info(), bm->rowBytes(), bm->getPixels(), image)) {
+ return kFailure;
+ }
+
+ CGImageAlphaInfo info = CGImageGetAlphaInfo(image);
+ switch (info) {
+ case kCGImageAlphaNone:
+ case kCGImageAlphaNoneSkipLast:
+ case kCGImageAlphaNoneSkipFirst:
+ // We're opaque, but we can't rely on the data always having 0xFF
+ // in the alpha slot (which Skia wants), so we have to ram it in
+ // ourselves.
+ force_opaque(bm);
+ 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 kSuccess;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*);
+
+SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) {
+ SkImageDecoder* decoder = image_decoder_from_stream(stream);
+ if (nullptr == decoder) {
+ // If no image decoder specific to the stream exists, use SkImageDecoder_CG.
+ return new SkImageDecoder_CG;
+ } else {
+ return decoder;
+ }
+}
/////////////////////////////////////////////////////////////////////////
@@ -150,13 +355,57 @@
static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_cg_factory);
-class SkPNGImageEncoder_CG : public SkImageEncoder_CG {
+#ifdef SK_BUILD_FOR_IOS
+class SkPNGImageEncoder_IOS : public SkImageEncoder_CG {
public:
- SkPNGImageEncoder_CG()
+ SkPNGImageEncoder_IOS()
: SkImageEncoder_CG(kPNG_Type) {
}
};
-DEFINE_ENCODER_CREATOR(PNGImageEncoder_CG);
+DEFINE_ENCODER_CREATOR(PNGImageEncoder_IOS);
+#endif
+
+struct FormatConversion {
+ CFStringRef fUTType;
+ SkImageDecoder::Format fFormat;
+};
+
+// Array of the types supported by the decoder.
+static const FormatConversion gFormatConversions[] = {
+ { kUTTypeBMP, SkImageDecoder::kBMP_Format },
+ { kUTTypeGIF, SkImageDecoder::kGIF_Format },
+ { kUTTypeICO, SkImageDecoder::kICO_Format },
+ { kUTTypeJPEG, SkImageDecoder::kJPEG_Format },
+ // Also include JPEG2000
+ { kUTTypeJPEG2000, SkImageDecoder::kJPEG_Format },
+ { kUTTypePNG, SkImageDecoder::kPNG_Format },
+};
+
+static SkImageDecoder::Format UTType_to_Format(const CFStringRef uttype) {
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) {
+ if (CFStringCompare(uttype, gFormatConversions[i].fUTType, 0) == kCFCompareEqualTo) {
+ return gFormatConversions[i].fFormat;
+ }
+ }
+ return SkImageDecoder::kUnknown_Format;
+}
+
+static SkImageDecoder::Format get_format_cg(SkStreamRewindable* stream) {
+ CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream);
+
+ if (nullptr == imageSrc) {
+ return SkImageDecoder::kUnknown_Format;
+ }
+
+ SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc);
+ const CFStringRef name = CGImageSourceGetType(imageSrc);
+ if (nullptr == name) {
+ return SkImageDecoder::kUnknown_Format;
+ }
+ return UTType_to_Format(name);
+}
+
+static SkImageDecoder_FormatReg gFormatReg(get_format_cg);
#endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
« no previous file with comments | « src/images/bmpdecoderhelper.cpp ('k') | src/ports/SkImageDecoder_WIC.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698