OLD | NEW |
| (Empty) |
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 "SkImageEncoder.h" | |
15 #include "SkMovie.h" | |
16 #include "SkStream.h" | |
17 #include "SkStreamPriv.h" | |
18 #include "SkTemplates.h" | |
19 #include "SkUnPreMultiply.h" | |
20 | |
21 #ifdef SK_BUILD_FOR_MAC | |
22 #include <ApplicationServices/ApplicationServices.h> | |
23 #endif | |
24 | |
25 #ifdef SK_BUILD_FOR_IOS | |
26 #include <CoreGraphics/CoreGraphics.h> | |
27 #include <ImageIO/ImageIO.h> | |
28 #include <MobileCoreServices/MobileCoreServices.h> | |
29 #endif | |
30 | |
31 ///////////////////////////////////////////////////////////////////////// | |
32 | |
33 SkMovie* SkMovie::DecodeStream(SkStreamRewindable* stream) { | |
34 return nullptr; | |
35 } | |
36 | |
37 ///////////////////////////////////////////////////////////////////////// | |
38 | |
39 static size_t consumer_put(void* info, const void* buffer, size_t count) { | |
40 SkWStream* stream = reinterpret_cast<SkWStream*>(info); | |
41 return stream->write(buffer, count) ? count : 0; | |
42 } | |
43 | |
44 static void consumer_release(void* info) { | |
45 // we do nothing, since by design we don't "own" the stream (i.e. info) | |
46 } | |
47 | |
48 static CGDataConsumerRef SkStreamToCGDataConsumer(SkWStream* stream) { | |
49 CGDataConsumerCallbacks procs; | |
50 procs.putBytes = consumer_put; | |
51 procs.releaseConsumer = consumer_release; | |
52 // we don't own/reference the stream, so it our consumer must not live | |
53 // longer that our caller's ownership of the stream | |
54 return CGDataConsumerCreate(stream, &procs); | |
55 } | |
56 | |
57 static CGImageDestinationRef SkStreamToImageDestination(SkWStream* stream, | |
58 CFStringRef type) { | |
59 CGDataConsumerRef consumer = SkStreamToCGDataConsumer(stream); | |
60 if (nullptr == consumer) { | |
61 return nullptr; | |
62 } | |
63 SkAutoTCallVProc<const void, CFRelease> arconsumer(consumer); | |
64 | |
65 return CGImageDestinationCreateWithDataConsumer(consumer, type, 1, nullptr); | |
66 } | |
67 | |
68 class SkImageEncoder_CG : public SkImageEncoder { | |
69 public: | |
70 SkImageEncoder_CG(Type t) : fType(t) {} | |
71 | |
72 protected: | |
73 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality); | |
74 | |
75 private: | |
76 Type fType; | |
77 }; | |
78 | |
79 /* Encode bitmaps via CGImageDestination. We setup a DataConsumer which writes | |
80 to our SkWStream. Since we don't reference/own the SkWStream, our consumer | |
81 must only live for the duration of the onEncode() method. | |
82 */ | |
83 bool SkImageEncoder_CG::onEncode(SkWStream* stream, const SkBitmap& bm, | |
84 int quality) { | |
85 // Used for converting a bitmap to 8888. | |
86 const SkBitmap* bmPtr = &bm; | |
87 SkBitmap bitmap8888; | |
88 | |
89 CFStringRef type; | |
90 switch (fType) { | |
91 case kICO_Type: | |
92 type = kUTTypeICO; | |
93 break; | |
94 case kBMP_Type: | |
95 type = kUTTypeBMP; | |
96 break; | |
97 case kGIF_Type: | |
98 type = kUTTypeGIF; | |
99 break; | |
100 case kJPEG_Type: | |
101 type = kUTTypeJPEG; | |
102 break; | |
103 case kPNG_Type: | |
104 // PNG encoding an ARGB_4444 bitmap gives the following errors in GM
: | |
105 // <Error>: CGImageDestinationAddImage image could not be converted
to destination | |
106 // format. | |
107 // <Error>: CGImageDestinationFinalize image destination does not ha
ve enough images | |
108 // So instead we copy to 8888. | |
109 if (bm.colorType() == kARGB_4444_SkColorType) { | |
110 bm.copyTo(&bitmap8888, kN32_SkColorType); | |
111 bmPtr = &bitmap8888; | |
112 } | |
113 type = kUTTypePNG; | |
114 break; | |
115 default: | |
116 return false; | |
117 } | |
118 | |
119 CGImageDestinationRef dst = SkStreamToImageDestination(stream, type); | |
120 if (nullptr == dst) { | |
121 return false; | |
122 } | |
123 SkAutoTCallVProc<const void, CFRelease> ardst(dst); | |
124 | |
125 CGImageRef image = SkCreateCGImageRef(*bmPtr); | |
126 if (nullptr == image) { | |
127 return false; | |
128 } | |
129 SkAutoTCallVProc<CGImage, CGImageRelease> agimage(image); | |
130 | |
131 CGImageDestinationAddImage(dst, image, nullptr); | |
132 return CGImageDestinationFinalize(dst); | |
133 } | |
134 | |
135 /////////////////////////////////////////////////////////////////////////////// | |
136 | |
137 static SkImageEncoder* sk_imageencoder_cg_factory(SkImageEncoder::Type t) { | |
138 switch (t) { | |
139 case SkImageEncoder::kICO_Type: | |
140 case SkImageEncoder::kBMP_Type: | |
141 case SkImageEncoder::kGIF_Type: | |
142 case SkImageEncoder::kJPEG_Type: | |
143 case SkImageEncoder::kPNG_Type: | |
144 break; | |
145 default: | |
146 return nullptr; | |
147 } | |
148 return new SkImageEncoder_CG(t); | |
149 } | |
150 | |
151 static SkImageEncoder_EncodeReg gEReg(sk_imageencoder_cg_factory); | |
152 | |
153 class SkPNGImageEncoder_CG : public SkImageEncoder_CG { | |
154 public: | |
155 SkPNGImageEncoder_CG() | |
156 : SkImageEncoder_CG(kPNG_Type) { | |
157 } | |
158 }; | |
159 | |
160 DEFINE_ENCODER_CREATOR(PNGImageEncoder_CG); | |
161 | |
162 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) | |
OLD | NEW |