Home | History | Annotate | Download | only in ports
      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