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