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 
malloc_release_proc(void * info,const void * data,size_t size)28 static void malloc_release_proc(void* info, const void* data, size_t size) {
29     sk_free(info);
30 }
31 
SkStreamToDataProvider(SkStream * stream)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 
SkStreamToCGImageSource(SkStream * stream)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 
argb_4444_force_opaque(void * row,int count)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 
argb_8888_force_opaque(void * row,int count)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 
alpha_8_force_opaque(void * row,int count)72 static void alpha_8_force_opaque(void* row, int count) {
73     memset(row, 0xFF, count);
74 }
75 
force_opaque(SkBitmap * bm)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:
AutoCFDataRelease(CFDataRef dr)111     AutoCFDataRelease(CFDataRef dr) : fDR(dr) {}
~AutoCFDataRelease()112     ~AutoCFDataRelease() { if (fDR) { CFRelease(fDR); } }
113 
operator CFDataRef()114     operator CFDataRef () { return fDR; }
115 };
116 
colorspace_is_sRGB(CGColorSpaceRef cs)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 
onDecode(SkStream * stream,SkBitmap * bm,Mode mode)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 
Factory(SkStreamRewindable * stream)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 
DecodeStream(SkStreamRewindable * stream)221 SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
222     return NULL;
223 }
224 
225 /////////////////////////////////////////////////////////////////////////
226 
consumer_put(void * info,const void * buffer,size_t count)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 
consumer_release(void * info)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 
SkStreamToCGDataConsumer(SkWStream * stream)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 
SkStreamToImageDestination(SkWStream * stream,CFStringRef type)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:
SkImageEncoder_CG(Type t)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  */
onEncode(SkWStream * stream,const SkBitmap & bm,int quality)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 
sk_imageencoder_cg_factory(SkImageEncoder::Type t)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:
SkPNGImageEncoder_IOS()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 
UTType_to_Format(const CFStringRef uttype)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 
get_format_cg(SkStreamRewindable * stream)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