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 "SkStreamHelpers.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
28static void malloc_release_proc(void* info, const void* data, size_t size) {
29    sk_free(info);
30}
31
32static 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 = CopyStreamToStorage(&storage, stream);
36    void* data = storage.detach();
37
38    return CGDataProviderCreateWithData(data, data, len, malloc_release_proc);
39}
40
41static CGImageSourceRef SkStreamToCGImageSource(SkStream* stream) {
42    CGDataProviderRef data = SkStreamToDataProvider(stream);
43    CGImageSourceRef imageSrc = CGImageSourceCreateWithDataProvider(data, 0);
44    CGDataProviderRelease(data);
45    return imageSrc;
46}
47
48class SkImageDecoder_CG : public SkImageDecoder {
49protected:
50    virtual Result onDecode(SkStream* stream, SkBitmap* bm, Mode);
51};
52
53#define BITMAP_INFO (kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast)
54
55SkImageDecoder::Result SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
56    CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream);
57
58    if (NULL == imageSrc) {
59        return kFailure;
60    }
61    SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc);
62
63    CGImageRef image = CGImageSourceCreateImageAtIndex(imageSrc, 0, NULL);
64    if (NULL == image) {
65        return kFailure;
66    }
67    SkAutoTCallVProc<CGImage, CGImageRelease> arimage(image);
68
69    const int width = SkToInt(CGImageGetWidth(image));
70    const int height = SkToInt(CGImageGetHeight(image));
71
72    bm->setInfo(SkImageInfo::MakeN32Premul(width, height));
73    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
74        return kSuccess;
75    }
76
77    if (!this->allocPixelRef(bm, NULL)) {
78        return kFailure;
79    }
80
81    SkAutoLockPixels alp(*bm);
82
83    if (!SkCopyPixelsFromCGImage(bm->info(), bm->rowBytes(), bm->getPixels(), image)) {
84        return kFailure;
85    }
86
87    CGImageAlphaInfo info = CGImageGetAlphaInfo(image);
88    switch (info) {
89        case kCGImageAlphaNone:
90        case kCGImageAlphaNoneSkipLast:
91        case kCGImageAlphaNoneSkipFirst:
92            SkASSERT(SkBitmap::ComputeIsOpaque(*bm));
93            bm->setAlphaType(kOpaque_SkAlphaType);
94            break;
95        default:
96            // we don't know if we're opaque or not, so compute it.
97            if (SkBitmap::ComputeIsOpaque(*bm)) {
98                bm->setAlphaType(kOpaque_SkAlphaType);
99            }
100    }
101    if (!bm->isOpaque() && this->getRequireUnpremultipliedColors()) {
102        // CGBitmapContext does not support unpremultiplied, so the image has been premultiplied.
103        // Convert to unpremultiplied.
104        for (int i = 0; i < width; ++i) {
105            for (int j = 0; j < height; ++j) {
106                uint32_t* addr = bm->getAddr32(i, j);
107                *addr = SkUnPreMultiply::UnPreMultiplyPreservingByteOrder(*addr);
108            }
109        }
110        bm->setAlphaType(kUnpremul_SkAlphaType);
111    }
112    return kSuccess;
113}
114
115///////////////////////////////////////////////////////////////////////////////
116
117extern SkImageDecoder* image_decoder_from_stream(SkStreamRewindable*);
118
119SkImageDecoder* SkImageDecoder::Factory(SkStreamRewindable* stream) {
120    SkImageDecoder* decoder = image_decoder_from_stream(stream);
121    if (NULL == decoder) {
122        // If no image decoder specific to the stream exists, use SkImageDecoder_CG.
123        return SkNEW(SkImageDecoder_CG);
124    } else {
125        return decoder;
126    }
127}
128
129/////////////////////////////////////////////////////////////////////////
130
131SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
132    return NULL;
133}
134
135/////////////////////////////////////////////////////////////////////////
136
137static size_t consumer_put(void* info, const void* buffer, size_t count) {
138    SkWStream* stream = reinterpret_cast<SkWStream*>(info);
139    return stream->write(buffer, count) ? count : 0;
140}
141
142static void consumer_release(void* info) {
143    // we do nothing, since by design we don't "own" the stream (i.e. info)
144}
145
146static CGDataConsumerRef SkStreamToCGDataConsumer(SkWStream* stream) {
147    CGDataConsumerCallbacks procs;
148    procs.putBytes = consumer_put;
149    procs.releaseConsumer = consumer_release;
150    // we don't own/reference the stream, so it our consumer must not live
151    // longer that our caller's ownership of the stream
152    return CGDataConsumerCreate(stream, &procs);
153}
154
155static CGImageDestinationRef SkStreamToImageDestination(SkWStream* stream,
156                                                        CFStringRef type) {
157    CGDataConsumerRef consumer = SkStreamToCGDataConsumer(stream);
158    if (NULL == consumer) {
159        return NULL;
160    }
161    SkAutoTCallVProc<const void, CFRelease> arconsumer(consumer);
162
163    return CGImageDestinationCreateWithDataConsumer(consumer, type, 1, NULL);
164}
165
166class SkImageEncoder_CG : public SkImageEncoder {
167public:
168    SkImageEncoder_CG(Type t) : fType(t) {}
169
170protected:
171    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
172
173private:
174    Type fType;
175};
176
177/*  Encode bitmaps via CGImageDestination. We setup a DataConsumer which writes
178    to our SkWStream. Since we don't reference/own the SkWStream, our consumer
179    must only live for the duration of the onEncode() method.
180 */
181bool SkImageEncoder_CG::onEncode(SkWStream* stream, const SkBitmap& bm,
182                                 int quality) {
183    // Used for converting a bitmap to 8888.
184    const SkBitmap* bmPtr = &bm;
185    SkBitmap bitmap8888;
186
187    CFStringRef type;
188    switch (fType) {
189        case kICO_Type:
190            type = kUTTypeICO;
191            break;
192        case kBMP_Type:
193            type = kUTTypeBMP;
194            break;
195        case kGIF_Type:
196            type = kUTTypeGIF;
197            break;
198        case kJPEG_Type:
199            type = kUTTypeJPEG;
200            break;
201        case kPNG_Type:
202            // PNG encoding an ARGB_4444 bitmap gives the following errors in GM:
203            // <Error>: CGImageDestinationAddImage image could not be converted to destination
204            // format.
205            // <Error>: CGImageDestinationFinalize image destination does not have enough images
206            // So instead we copy to 8888.
207            if (bm.colorType() == kARGB_4444_SkColorType) {
208                bm.copyTo(&bitmap8888, kN32_SkColorType);
209                bmPtr = &bitmap8888;
210            }
211            type = kUTTypePNG;
212            break;
213        default:
214            return false;
215    }
216
217    CGImageDestinationRef dst = SkStreamToImageDestination(stream, type);
218    if (NULL == dst) {
219        return false;
220    }
221    SkAutoTCallVProc<const void, CFRelease> ardst(dst);
222
223    CGImageRef image = SkCreateCGImageRef(*bmPtr);
224    if (NULL == image) {
225        return false;
226    }
227    SkAutoTCallVProc<CGImage, CGImageRelease> agimage(image);
228
229    CGImageDestinationAddImage(dst, image, NULL);
230    return CGImageDestinationFinalize(dst);
231}
232
233///////////////////////////////////////////////////////////////////////////////
234
235static SkImageEncoder* sk_imageencoder_cg_factory(SkImageEncoder::Type t) {
236    switch (t) {
237        case SkImageEncoder::kICO_Type:
238        case SkImageEncoder::kBMP_Type:
239        case SkImageEncoder::kGIF_Type:
240        case SkImageEncoder::kJPEG_Type:
241        case SkImageEncoder::kPNG_Type:
242            break;
243        default:
244            return NULL;
245    }
246    return SkNEW_ARGS(SkImageEncoder_CG, (t));
247}
248
249static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_cg_factory);
250
251struct FormatConversion {
252    CFStringRef             fUTType;
253    SkImageDecoder::Format  fFormat;
254};
255
256// Array of the types supported by the decoder.
257static const FormatConversion gFormatConversions[] = {
258    { kUTTypeBMP, SkImageDecoder::kBMP_Format },
259    { kUTTypeGIF, SkImageDecoder::kGIF_Format },
260    { kUTTypeICO, SkImageDecoder::kICO_Format },
261    { kUTTypeJPEG, SkImageDecoder::kJPEG_Format },
262    // Also include JPEG2000
263    { kUTTypeJPEG2000, SkImageDecoder::kJPEG_Format },
264    { kUTTypePNG, SkImageDecoder::kPNG_Format },
265};
266
267static SkImageDecoder::Format UTType_to_Format(const CFStringRef uttype) {
268    for (size_t i = 0; i < SK_ARRAY_COUNT(gFormatConversions); i++) {
269        if (CFStringCompare(uttype, gFormatConversions[i].fUTType, 0) == kCFCompareEqualTo) {
270            return gFormatConversions[i].fFormat;
271        }
272    }
273    return SkImageDecoder::kUnknown_Format;
274}
275
276static SkImageDecoder::Format get_format_cg(SkStreamRewindable* stream) {
277    CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream);
278
279    if (NULL == imageSrc) {
280        return SkImageDecoder::kUnknown_Format;
281    }
282
283    SkAutoTCallVProc<const void, CFRelease> arsrc(imageSrc);
284    const CFStringRef name = CGImageSourceGetType(imageSrc);
285    if (NULL == name) {
286        return SkImageDecoder::kUnknown_Format;
287    }
288    return UTType_to_Format(name);
289}
290
291static SkImageDecoder_FormatReg gFormatReg(get_format_cg);
292