• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "SkImageEncoderPriv.h"
9 
10 #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
11 
12 #include "SkBitmap.h"
13 #include "SkCGUtils.h"
14 #include "SkColorPriv.h"
15 #include "SkData.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 
consumer_put(void * info,const void * buffer,size_t count)31 static size_t consumer_put(void* info, const void* buffer, size_t count) {
32     SkWStream* stream = reinterpret_cast<SkWStream*>(info);
33     return stream->write(buffer, count) ? count : 0;
34 }
35 
consumer_release(void * info)36 static void consumer_release(void* info) {
37     // we do nothing, since by design we don't "own" the stream (i.e. info)
38 }
39 
SkStreamToCGDataConsumer(SkWStream * stream)40 static CGDataConsumerRef SkStreamToCGDataConsumer(SkWStream* stream) {
41     CGDataConsumerCallbacks procs;
42     procs.putBytes = consumer_put;
43     procs.releaseConsumer = consumer_release;
44     // we don't own/reference the stream, so it our consumer must not live
45     // longer that our caller's ownership of the stream
46     return CGDataConsumerCreate(stream, &procs);
47 }
48 
SkStreamToImageDestination(SkWStream * stream,CFStringRef type)49 static CGImageDestinationRef SkStreamToImageDestination(SkWStream* stream,
50                                                         CFStringRef type) {
51     CGDataConsumerRef consumer = SkStreamToCGDataConsumer(stream);
52     if (nullptr == consumer) {
53         return nullptr;
54     }
55     SkAutoTCallVProc<const void, CFRelease> arconsumer(consumer);
56 
57     return CGImageDestinationCreateWithDataConsumer(consumer, type, 1, nullptr);
58 }
59 
60 /*  Encode bitmaps via CGImageDestination. We setup a DataConsumer which writes
61     to our SkWStream. Since we don't reference/own the SkWStream, our consumer
62     must only live for the duration of the onEncode() method.
63  */
SkEncodeImageWithCG(SkWStream * stream,const SkPixmap & pixmap,SkEncodedImageFormat format)64 bool SkEncodeImageWithCG(SkWStream* stream, const SkPixmap& pixmap, SkEncodedImageFormat format) {
65     SkBitmap bm;
66     if (!bm.installPixels(pixmap)) {
67         return false;
68     }
69     bm.setImmutable();
70 
71     CFStringRef type;
72     switch (format) {
73         case SkEncodedImageFormat::kICO:
74             type = kUTTypeICO;
75             break;
76         case SkEncodedImageFormat::kBMP:
77             type = kUTTypeBMP;
78             break;
79         case SkEncodedImageFormat::kGIF:
80             type = kUTTypeGIF;
81             break;
82         case SkEncodedImageFormat::kJPEG:
83             type = kUTTypeJPEG;
84             break;
85         case SkEncodedImageFormat::kPNG:
86             // PNG encoding an ARGB_4444 bitmap gives the following errors in GM:
87             // <Error>: CGImageDestinationAddImage image could not be converted to destination
88             // format.
89             // <Error>: CGImageDestinationFinalize image destination does not have enough images
90             // So instead we copy to 8888.
91             if (bm.colorType() == kARGB_4444_SkColorType) {
92                 SkBitmap bitmap8888;
93                 bm.copyTo(&bitmap8888, kN32_SkColorType);
94                 bm.swap(bitmap8888);
95             }
96             type = kUTTypePNG;
97             break;
98         default:
99             return false;
100     }
101 
102     CGImageDestinationRef dst = SkStreamToImageDestination(stream, type);
103     if (nullptr == dst) {
104         return false;
105     }
106     SkAutoTCallVProc<const void, CFRelease> ardst(dst);
107 
108     CGImageRef image = SkCreateCGImageRef(bm);
109     if (nullptr == image) {
110         return false;
111     }
112     SkAutoTCallVProc<CGImage, CGImageRelease> agimage(image);
113 
114     CGImageDestinationAddImage(dst, image, nullptr);
115     return CGImageDestinationFinalize(dst);
116 }
117 
118 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS)
119