1 /* 2 * Copyright 2008 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkTypes.h" 9 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 10 11 #include "SkCGUtils.h" 12 #include "SkColorPriv.h" 13 #include "SkData.h" 14 #include "SkImageDecoder.h" 15 #include "SkImageEncoder.h" 16 #include "SkMovie.h" 17 #include "SkStream.h" 18 #include "SkStreamPriv.h" 19 #include "SkTemplates.h" 20 #include "SkUnPreMultiply.h" 21 22 #ifdef SK_BUILD_FOR_MAC 23 #include <ApplicationServices/ApplicationServices.h> 24 #endif 25 26 #ifdef SK_BUILD_FOR_IOS 27 #include <CoreGraphics/CoreGraphics.h> 28 #include <ImageIO/ImageIO.h> 29 #include <MobileCoreServices/MobileCoreServices.h> 30 #endif 31 32 static void data_unref_proc(void* skdata, const void*, size_t) { 33 SkASSERT(skdata); 34 static_cast<SkData*>(skdata)->unref(); 35 } 36 37 static CGDataProviderRef SkStreamToDataProvider(SkStream* stream) { 38 // TODO: use callbacks, so we don't have to load all the data into RAM 39 SkData* skdata = SkCopyStreamToData(stream); 40 if (!skdata) { 41 return nullptr; 42 } 43 44 return CGDataProviderCreateWithData(skdata, skdata->data(), skdata->size(), data_unref_proc); 45 } 46 47 static CGImageSourceRef SkStreamToCGImageSource(SkStream* stream) { 48 CGDataProviderRef data = SkStreamToDataProvider(stream); 49 if (!data) { 50 return nullptr; 51 } 52 CGImageSourceRef imageSrc = CGImageSourceCreateWithDataProvider(data, 0); 53 CGDataProviderRelease(data); 54 return imageSrc; 55 } 56 57 class SkImageDecoder_CG : public SkImageDecoder { 58 protected: 59 virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode); 60 }; 61 62 static void argb_4444_force_opaque(void* row, int count) { 63 uint16_t* row16 = (uint16_t*)row; 64 for (int i = 0; i < count; ++i) { 65 row16[i] |= 0xF000; 66 } 67 } 68 69 static void argb_8888_force_opaque(void* row, int count) { 70 // can use RGBA or BGRA, they have the same shift for alpha 71 const uint32_t alphaMask = 0xFF << SK_RGBA_A32_SHIFT; 72 uint32_t* row32 = (uint32_t*)row; 73 for (int i = 0; i < count; ++i) { 74 row32[i] |= alphaMask; 75 } 76 } 77 78 static void alpha_8_force_opaque(void* row, int count) { 79 memset(row, 0xFF, count); 80 } 81 82 static void force_opaque(SkBitmap* bm) { 83 SkAutoLockPixels alp(*bm); 84 if (!bm->getPixels()) { 85 return; 86 } 87 88 void (*proc)(void*, int); 89 switch (bm->colorType()) { 90 case kARGB_4444_SkColorType: 91 proc = argb_4444_force_opaque; 92 break; 93 case kRGBA_8888_SkColorType: 94 case kBGRA_8888_SkColorType: 95 proc = argb_8888_force_opaque; 96 break; 97 case kAlpha_8_SkColorType: 98 proc = alpha_8_force_opaque; 99 break; 100 default: 101 return; 102 } 103 104 char* row = (char*)bm->getPixels(); 105 for (int y = 0; y < bm->height(); ++y) { 106 proc(row, bm->width()); 107 row += bm->rowBytes(); 108 } 109 bm->setAlphaType(kOpaque_SkAlphaType); 110 } 111 112 #define BITMAP_INFO (kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast) 113 114 class AutoCFDataRelease { 115 CFDataRef fDR; 116 public: 117 AutoCFDataRelease(CFDataRef dr) : fDR(dr) {} 118 ~AutoCFDataRelease() { if (fDR) { CFRelease(fDR); } } 119 120 operator CFDataRef () { return fDR; } 121 }; 122 123 static bool colorspace_is_sRGB(CGColorSpaceRef cs) { 124 #ifdef SK_BUILD_FOR_IOS 125 return true; // iOS seems to define itself to always return sRGB <reed> 126 #else 127 AutoCFDataRelease data(CGColorSpaceCopyICCProfile(cs)); 128 if (data) { 129 // found by inspection -- need a cleaner way to sniff a profile 130 const CFIndex ICC_PROFILE_OFFSET_TO_SRGB_TAG = 52; 131 132 if (CFDataGetLength(data) >= ICC_PROFILE_OFFSET_TO_SRGB_TAG + 4) { 133 return !memcmp(CFDataGetBytePtr(data) + ICC_PROFILE_OFFSET_TO_SRGB_TAG, "sRGB", 4); 134 } 135 } 136 return false; 137 #endif 138 } 139 140 SkImageDecoder::Result SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { 141 CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream); 142 143 if (nullptr == imageSrc) { 144 return kFailure; 145 } 146 SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc); 147 148 CGImageRef image = CGImageSourceCreateImageAtIndex(imageSrc, 0, nullptr); 149 if (nullptr == image) { 150 return kFailure; 151 } 152 SkAutoTCallVProc<CGImage, CGImageRelease> arimage(image); 153 154 const int width = SkToInt(CGImageGetWidth(image)); 155 const int height = SkToInt(CGImageGetHeight(image)); 156 SkColorProfileType cpType = kLinear_SkColorProfileType; 157 158 CGColorSpaceRef cs = CGImageGetColorSpace(image); 159 if (cs) { 160 CGColorSpaceModel m = CGColorSpaceGetModel(cs); 161 if (kCGColorSpaceModelRGB == m && colorspace_is_sRGB(cs)) { 162 cpType = kSRGB_SkColorProfileType; 163 } 164 } 165 166 SkAlphaType at = kPremul_SkAlphaType; 167 switch (CGImageGetAlphaInfo(image)) { 168 case kCGImageAlphaNone: 169 case kCGImageAlphaNoneSkipLast: 170 case kCGImageAlphaNoneSkipFirst: 171 at = kOpaque_SkAlphaType; 172 break; 173 default: 174 break; 175 } 176 177 bm->setInfo(SkImageInfo::Make(width, height, kN32_SkColorType, at, cpType)); 178 if (SkImageDecoder::kDecodeBounds_Mode == mode) { 179 return kSuccess; 180 } 181 182 if (!this->allocPixelRef(bm, nullptr)) { 183 return kFailure; 184 } 185 186 SkAutoLockPixels alp(*bm); 187 188 if (!SkCopyPixelsFromCGImage(bm->info(), bm->rowBytes(), bm->getPixels(), image)) { 189 return kFailure; 190 } 191 192 CGImageAlphaInfo info = CGImageGetAlphaInfo(image); 193 switch (info) { 194 case kCGImageAlphaNone: 195 case kCGImageAlphaNoneSkipLast: 196 case kCGImageAlphaNoneSkipFirst: 197 // We're opaque, but we can't rely on the data always having 0xFF 198 // in the alpha slot (which Skia wants), so we have to ram it in 199 // ourselves. 200 force_opaque(bm); 201 break; 202 default: 203 // we don't know if we're opaque or not, so compute it. 204 if (SkBitmap::ComputeIsOpaque(*bm)) { 205 bm->setAlphaType(kOpaque_SkAlphaType); 206 } 207 } 208 if (!bm->isOpaque() && this->getRequireUnpremultipliedColors()) { 209 // CGBitmapContext does not support unpremultiplied, so the image has been premultiplied. 210 // Convert to unpremultiplied. 211 for (int i = 0; i < width; ++i) { 212 for (int j = 0; j < height; ++j) { 213 uint32_t* addr = bm->getAddr32(i, j); 214 *addr = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(*addr); 215 } 216 } 217 bm->setAlphaType(kUnpremul_SkAlphaType); 218 } 219 return kSuccess; 220 } 221 222 /////////////////////////////////////////////////////////////////////////////// 223 224 extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*); 225 226 SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) { 227 SkImageDecoder* decoder = image_decoder_from_stream(stream); 228 if (nullptr == decoder) { 229 // If no image decoder specific to the stream exists, use SkImageDecoder_CG. 230 return new SkImageDecoder_CG; 231 } else { 232 return decoder; 233 } 234 } 235 236 ///////////////////////////////////////////////////////////////////////// 237 238 SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) { 239 return nullptr; 240 } 241 242 ///////////////////////////////////////////////////////////////////////// 243 244 static size_t consumer_put(void* info, const void* buffer, size_t count) { 245 SkWStream* stream = reinterpret_cast<SkWStream*>(info); 246 return stream->write(buffer, count) ? count : 0; 247 } 248 249 static void consumer_release(void* info) { 250 // we do nothing, since by design we don't "own" the stream (i.e. info) 251 } 252 253 static CGDataConsumerRef SkStreamToCGDataConsumer(SkWStream* stream) { 254 CGDataConsumerCallbacks procs; 255 procs.putBytes = consumer_put; 256 procs.releaseConsumer = consumer_release; 257 // we don't own/reference the stream, so it our consumer must not live 258 // longer that our caller's ownership of the stream 259 return CGDataConsumerCreate(stream, &procs); 260 } 261 262 static CGImageDestinationRef SkStreamToImageDestination(SkWStream* stream, 263 CFStringRef type) { 264 CGDataConsumerRef consumer = SkStreamToCGDataConsumer(stream); 265 if (nullptr == consumer) { 266 return nullptr; 267 } 268 SkAutoTCallVProc<const void, CFRelease> arconsumer(consumer); 269 270 return CGImageDestinationCreateWithDataConsumer(consumer, type, 1, nullptr); 271 } 272 273 class SkImageEncoder_CG : public SkImageEncoder { 274 public: 275 SkImageEncoder_CG(Type t) : fType(t) {} 276 277 protected: 278 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); 279 280 private: 281 Type fType; 282 }; 283 284 /* Encode bitmaps via CGImageDestination. We setup a DataConsumer which writes 285 to our SkWStream. Since we don't reference/own the SkWStream, our consumer 286 must only live for the duration of the onEncode() method. 287 */ 288 bool SkImageEncoder_CG::onEncode(SkWStream* stream, const SkBitmap& bm, 289 int quality) { 290 // Used for converting a bitmap to 8888. 291 const SkBitmap* bmPtr = &bm; 292 SkBitmap bitmap8888; 293 294 CFStringRef type; 295 switch (fType) { 296 case kICO_Type: 297 type = kUTTypeICO; 298 break; 299 case kBMP_Type: 300 type = kUTTypeBMP; 301 break; 302 case kGIF_Type: 303 type = kUTTypeGIF; 304 break; 305 case kJPEG_Type: 306 type = kUTTypeJPEG; 307 break; 308 case kPNG_Type: 309 // PNG encoding an ARGB_4444 bitmap gives the following errors in GM: 310 // <Error>: CGImageDestinationAddImage image could not be converted to destination 311 // format. 312 // <Error>: CGImageDestinationFinalize image destination does not have enough images 313 // So instead we copy to 8888. 314 if (bm.colorType() == kARGB_4444_SkColorType) { 315 bm.copyTo(&bitmap8888, kN32_SkColorType); 316 bmPtr = &bitmap8888; 317 } 318 type = kUTTypePNG; 319 break; 320 default: 321 return false; 322 } 323 324 CGImageDestinationRef dst = SkStreamToImageDestination(stream, type); 325 if (nullptr == dst) { 326 return false; 327 } 328 SkAutoTCallVProc<const void, CFRelease> ardst(dst); 329 330 CGImageRef image = SkCreateCGImageRef(*bmPtr); 331 if (nullptr == image) { 332 return false; 333 } 334 SkAutoTCallVProc<CGImage, CGImageRelease> agimage(image); 335 336 CGImageDestinationAddImage(dst, image, nullptr); 337 return CGImageDestinationFinalize(dst); 338 } 339 340 /////////////////////////////////////////////////////////////////////////////// 341 342 static SkImageEncoder* sk_imageencoder_cg_factory(SkImageEncoder::Type t) { 343 switch (t) { 344 case SkImageEncoder::kICO_Type: 345 case SkImageEncoder::kBMP_Type: 346 case SkImageEncoder::kGIF_Type: 347 case SkImageEncoder::kJPEG_Type: 348 case SkImageEncoder::kPNG_Type: 349 break; 350 default: 351 return nullptr; 352 } 353 return new SkImageEncoder_CG(t); 354 } 355 356 static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_cg_factory); 357 358 #ifdef SK_BUILD_FOR_IOS 359 class SkPNGImageEncoder_IOS : public SkImageEncoder_CG { 360 public: 361 SkPNGImageEncoder_IOS() 362 : SkImageEncoder_CG(kPNG_Type) { 363 } 364 }; 365 366 DEFINE_ENCODER_CREATOR(PNGImageEncoder_IOS); 367 #endif 368 369 struct FormatConversion { 370 CFStringRef fUTType; 371 SkImageDecoder::Format fFormat; 372 }; 373 374 // Array of the types supported by the decoder. 375 static const FormatConversion gFormatConversions[] = { 376 { kUTTypeBMP, SkImageDecoder::kBMP_Format }, 377 { kUTTypeGIF, SkImageDecoder::kGIF_Format }, 378 { kUTTypeICO, SkImageDecoder::kICO_Format }, 379 { kUTTypeJPEG, SkImageDecoder::kJPEG_Format }, 380 // Also include JPEG2000 381 { kUTTypeJPEG2000, SkImageDecoder::kJPEG_Format }, 382 { kUTTypePNG, SkImageDecoder::kPNG_Format }, 383 }; 384 385 static SkImageDecoder::Format UTType_to_Format(const CFStringRef uttype) { 386 for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) { 387 if (CFStringCompare(uttype, gFormatConversions[i].fUTType, 0) == kCFCompareEqualTo) { 388 return gFormatConversions[i].fFormat; 389 } 390 } 391 return SkImageDecoder::kUnknown_Format; 392 } 393 394 static SkImageDecoder::Format get_format_cg(SkStreamRewindable* stream) { 395 CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream); 396 397 if (nullptr == imageSrc) { 398 return SkImageDecoder::kUnknown_Format; 399 } 400 401 SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc); 402 const CFStringRef name = CGImageSourceGetType(imageSrc); 403 if (nullptr == name) { 404 return SkImageDecoder::kUnknown_Format; 405 } 406 return UTType_to_Format(name); 407 } 408 409 static SkImageDecoder_FormatReg gFormatReg(get_format_cg); 410 411 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 412