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 
data_unref_proc(void * skdata,const void *,size_t)32 static void data_unref_proc(void* skdata, const void*, size_t) {
33     SkASSERT(skdata);
34     static_cast<SkData*>(skdata)->unref();
35 }
36 
SkStreamToDataProvider(SkStream * stream)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 
SkStreamToCGImageSource(SkStream * stream)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 
argb_4444_force_opaque(void * row,int count)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 
argb_8888_force_opaque(void * row,int count)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 
alpha_8_force_opaque(void * row,int count)78 static void alpha_8_force_opaque(void* row, int count) {
79     memset(row, 0xFF, count);
80 }
81 
force_opaque(SkBitmap * bm)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:
AutoCFDataRelease(CFDataRef dr)117     AutoCFDataRelease(CFDataRef dr) : fDR(dr) {}
~AutoCFDataRelease()118     ~AutoCFDataRelease() { if (fDR) { CFRelease(fDR); } }
119 
operator CFDataRef()120     operator CFDataRef () { return fDR; }
121 };
122 
colorspace_is_sRGB(CGColorSpaceRef cs)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 
onDecode(SkStream * stream,SkBitmap * bm,Mode mode)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 
Factory(SkStreamRewindable * stream)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 
DecodeStream(SkStreamRewindable * stream)238 SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) {
239     return nullptr;
240 }
241 
242 /////////////////////////////////////////////////////////////////////////
243 
consumer_put(void * info,const void * buffer,size_t count)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 
consumer_release(void * info)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 
SkStreamToCGDataConsumer(SkWStream * stream)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 
SkStreamToImageDestination(SkWStream * stream,CFStringRef type)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:
SkImageEncoder_CG(Type t)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  */
onEncode(SkWStream * stream,const SkBitmap & bm,int quality)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 
sk_imageencoder_cg_factory(SkImageEncoder::Type t)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:
SkPNGImageEncoder_IOS()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 
UTType_to_Format(const CFStringRef uttype)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 
get_format_cg(SkStreamRewindable * stream)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