Saving CGImageRef to a png file?
Create a CGImageDestination
, passing kUTTypePNG
as the type of file to create. Add the image, then finalize the destination.
iOS: writing a CGImageRef disk in png or jpeg
Using UIKit, the code becomes a simple 3-liner:
UIImage *uiImage = [UIImage imageWithCGImage:cgImage];
NSData *jpgData = UIImageJPEGRepresentation(uiImage, 0.9f);
[jpgData writeToFile:path atomically:NO];
How to write CGImageRef to png file. CGImageDestinationCreateWithURL returns nil
@import MobileCoreServices; // or `@import CoreServices;` on Mac
@import ImageIO;
BOOL CGImageWriteToFile(CGImageRef image, NSString *path) {
CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:path];
CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, NULL);
if (!destination) {
NSLog(@"Failed to create CGImageDestination for %@", path);
return NO;
}
CGImageDestinationAddImage(destination, image, nil);
if (!CGImageDestinationFinalize(destination)) {
NSLog(@"Failed to write image to %@", path);
CFRelease(destination);
return NO;
}
CFRelease(destination);
return YES;
}
You have to add ImageIO and MobileCoreServices to your project and also have to add header.
Save CGImageRef as PNG-8
Hmm, no answers :) I believe the solution may be to use libpng but I haven't tried it yet. I'll mark this as the accepted answer for now, but if anyone can offer a good tip I'll gladly change it over!
Thanks.
Edit:
I ended up hacking apart https://github.com/pornel/pngquant to get it to accept CGImageRefs, and save PNG-8 files. It wasn't pretty. In the end, I actually switched to GIF (kUTTypeGIF
) which ran a lot faster in my tests.
Save CGImageRef to PNG file errors? (ARC Caused?)
The code you posted wouldn't work either with or without ARC, because you need to expand the tilde in the path name before passing it.
The code you posted also was leaking the items returned by CGDisplayCreateImage
and CGImageDestinationCreateWithURL
. Here's an example that works and doesn't leak:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
CGDirectDisplayID displayID = CGMainDisplayID();
CGImageRef imageRef = CGDisplayCreateImage(displayID); //this is a screenshot (works fine)
NSString *path = [@"~/Desktop/public.png" stringByExpandingTildeInPath];
[self savePNGImage:imageRef path:path];
CFRelease(imageRef);
}
- (void)savePNGImage:(CGImageRef)imageRef path:(NSString *)path
{
NSURL *fileURL = [NSURL fileURLWithPath:path];
CGImageDestinationRef dr = CGImageDestinationCreateWithURL((__bridge CFURLRef)fileURL, kUTTypePNG , 1, NULL);
CGImageDestinationAddImage(dr, imageRef, NULL);
CGImageDestinationFinalize(dr);
CFRelease(dr);
}
SWIFT 3 - CGImage to PNG
Thanks the issue of DonMag in my other question SWIFT 3 - CGImage copy always nil, here is the code to solve this :
func saveImageWithAlpha(theImage: UIImage, destFile: URL) -> Void {
// odd but works... solution to image not saving with proper alpha channel
UIGraphicsBeginImageContext(theImage.size)
theImage.draw(at: CGPoint.zero)
let saveImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if let img = saveImage, let data = UIImagePNGRepresentation(img) {
try? data.write(to: destFile)
}
}
How exactly to make a CGImageRef from an image on disk
gcamp is more or less correct, you are pretty safe to use this on a background thread, but to answer your question, I believe the following would work.
CGDataProviderRef dataProvider = CGDataProviderCreateWithFilename("file");
CGImageRef image = CGImageCreateWithPNGDataProvider(dataProvider, NULL, NO, kCGRenderingIntentDefault);
There is also a function for jpg images, CGImageCreateWithJPEGDataProvider
.
(be sure to release the data provider and image when done)
How to save CGImage to Data in Swift?
The problem is the way you are creating your mutable data. Data
is not convertible to NSMutableData
. Just change your forced casting from Data
to CFMutableData
to CFDataCreateMutable(nil, 0)
. Another option is to use NSMutableData
which is toll-free bridged to CFMutableData
. Try like this:
if let cgi = cgi,
let mutableData = CFDataCreateMutable(nil, 0),
let destination = CGImageDestinationCreateWithData(mutableData, "public.png" as CFString, 1, nil) {
CGImageDestinationAddImage(destination, cgi, nil)
if CGImageDestinationFinalize(destination) {
let data = mutableData as Data
if let image = UIImage(data: data) {
print(image.size)
}
} else {
print("Error writing Image")
}
}
edit/update: Xcode 11 • Swift 5.1
extension CGImage {
var png: Data? {
guard let mutableData = CFDataCreateMutable(nil, 0),
let destination = CGImageDestinationCreateWithData(mutableData, "public.png" as CFString, 1, nil) else { return nil }
CGImageDestinationAddImage(destination, self, nil)
guard CGImageDestinationFinalize(destination) else { return nil }
return mutableData as Data
}
}
Related Topics
Understanding Spritekit Collisionbitmask
How to Create a Global Variable
How to Stop a Dispatchworkitem in Gcd
Accessing an Enumeration Association Value in Swift
How to Display an Activity Indicator With Text on iOS 8 With Swift
All Dates Between Two Date Objects (Swift)
How to Make a Weak Protocol Reference in 'Pure' Swift (Without @Objc)
Multiple Functions With the Same Name
What's the Difference Between "As", "As!", and "As"
Cfrunloop in Swift Command Line Program
How to Detect If an Skspritenode Has Been Touched
What Is the "Some" Keyword in Swift(Ui)
How to Convert Array of Bytes [Uint8] into Hexa String in Swift
Knowing Where Retain Cycles Are and Removing Them
Fatal Error: Swapping a Location With Itself Is Not Supported With Swift 2.0