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