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 "SkColorData.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 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 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 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 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 */ 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 bitmapN32; 93 bitmapN32.allocPixels(bm.info().makeColorType(kN32_SkColorType)); 94 bm.readPixels(bitmapN32.info(), bitmapN32.getPixels(), bitmapN32.rowBytes(), 0, 0); 95 bm.swap(bitmapN32); 96 } 97 type = kUTTypePNG; 98 break; 99 default: 100 return false; 101 } 102 103 CGImageDestinationRef dst = SkStreamToImageDestination(stream, type); 104 if (nullptr == dst) { 105 return false; 106 } 107 SkAutoTCallVProc<const void, CFRelease> ardst(dst); 108 109 CGImageRef image = SkCreateCGImageRef(bm); 110 if (nullptr == image) { 111 return false; 112 } 113 SkAutoTCallVProc<CGImage, CGImageRelease> agimage(image); 114 115 CGImageDestinationAddImage(dst, image, nullptr); 116 return CGImageDestinationFinalize(dst); 117 } 118 119 #endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) 120