17

I'm using UIImageWriteToSavedPhotosAlbum to save a UIImage to the user's photo album. The problem is that the image doesn't have transparency and is a JPG. I've got the pixel data set correctly to have transparency, but there doesn't seem to be a way to save in a transparency-supported format. Ideas?

EDIT: There is no way to accomplish this, however there are other ways to deliver PNG images to the user. One of which is to save the image in the Documents directory (as detailed below). Once you've done that, you can email it, save it in a database, etc. You just can't get it into the photo album (for now) unless it is a lossy non-transparent JPG.

erickson
  • 265,237
  • 58
  • 395
  • 493
Eli
  • 4,874
  • 6
  • 41
  • 50

5 Answers5

45

As pointed out on this SO question there is a simple way to save pngs in your Photo Albums:

UIImage* image = ...;                                     // produce your image
NSData* imageData =  UIImagePNGRepresentation(image);     // get png representation
UIImage* pngImage = [UIImage imageWithData:imageData];    // rewrap
UIImageWriteToSavedPhotosAlbum(pngImage, nil, nil, nil);  // save to photo album
Community
  • 1
  • 1
IlDan
  • 6,851
  • 3
  • 33
  • 34
15

This is a problem I have noticed before and reported on the Apple Developer Forums about a year ago. As far as I know it is still an open issue.

If you have a moment, please take the time to file a feature request at Apple Bug Report. If more people report this issue, it is more likely that Apple will fix this method to output non-lossy, alpha-capable PNG.

EDIT

If you can compose your image in memory, I think something like the following would work or at least get you started:

- (UIImage *) composeImageWithWidth:(NSInteger)_width andHeight:(NSInteger)_height {
    CGSize _size = CGSizeMake(_width, _height);
    UIGraphicsBeginImageContext(_size);

    // Draw image with Quartz 2D routines over here...

    UIImage *_compositeImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return _compositeImage;
}

//
// cf. https://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/FilesandNetworking/FilesandNetworking.html#//apple_ref/doc/uid/TP40007072-CH21-SW20
//

- (BOOL) writeApplicationData:(NSData *)data toFile:(NSString *)fileName {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    if (!documentsDirectory) {
        NSLog(@"Documents directory not found!");
        return NO;
    }
    NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];
    return ([data writeToFile:appFile atomically:YES]);
}

// ...

NSString *_imageName = @"myImageName.png";
NSData *_imageData = [NSData dataWithData:UIImagePNGRepresentation([self composeImageWithWidth:100 andHeight:100)];

if (![self writeApplicationData:_imageData toFile:_imageName]) {
    NSLog(@"Save failed!");
}
Alex Reynolds
  • 95,983
  • 54
  • 240
  • 345
  • Done and done. I've heard there is a way to save images to the documents folder in a non-lossy format. Any idea how to do that? – Eli Sep 28 '09 at 21:47
  • I have updated my answer. Hopefully this helps get you started. – Alex Reynolds Sep 28 '09 at 22:20
  • Beautiful! Worked wonders. The image is a PNG and has transparency, I just needed to find it and that was it. – Eli Sep 29 '09 at 17:04
  • I don't understand how this works. Where is the reference to the original image data? From reading the code, it looks like a "blank" image gets created, with the developer specifying a height and width. I'd like to pass in a UIImage object from the camera. – Daddy Nov 28 '10 at 00:45
  • Do check out http://stackoverflow.com/a/10279075/129202 below that will work with `UIImageWriteToSavedPhotosAlbum`, no need to save to docs folder. – Jonny Jun 03 '13 at 02:29
  • Before you voted this down, you looked at the answer date, right? – Alex Reynolds Jun 03 '13 at 11:37
8

In Swift 5:

func pngFrom(image: UIImage) -> UIImage {
    let imageData = image.pngData()!
    let imagePng = UIImage(data: imageData)!
    return imagePng
}
KuDji
  • 159
  • 2
  • 6
6

I created an extension of UIImage with safe unwrapping:

Extension

extension UIImage {
    func toPNG() -> UIImage? {
        guard let imageData = self.pngData() else {return nil}
        guard let imagePng = UIImage(data: imageData) else {return nil}
        return imagePng
    }
}

Usage:

let image = //your UIImage
if let pngImage = image.toPNG() {
     UIImageWriteToSavedPhotosAlbum(pngImage, nil, nil, nil)
}
DanielZanchi
  • 2,708
  • 1
  • 25
  • 37
4

As an alternative to creating a secondary UIImage for UIImageWriteToSavedPhotosAlbum the PNG data can be written directly using the PHPhotoLibrary.

Here is a UIImage extension named 'saveToPhotos' which does this:

extension UIImage {

    func saveToPhotos(completion: @escaping (_ success:Bool) -> ()) {

        if let pngData = self.pngData() {

            PHPhotoLibrary.shared().performChanges({ () -> Void in

                let creationRequest = PHAssetCreationRequest.forAsset()
                let options = PHAssetResourceCreationOptions()

                creationRequest.addResource(with: PHAssetResourceType.photo, data: pngData, options: options)

            }, completionHandler: { (success, error) -> Void in

                if success == false {

                    if let errorString = error?.localizedDescription  {
                        print("Photo could not be saved: \(errorString))")
                    }

                    completion(false)
                }
                else {
                    print("Photo saved!")

                    completion(true)
                }
            })
        }
        else {
            completion(false)
        }

    }
}

To use:

    if let image = UIImage(named: "Background.png") {
        image.saveToPhotos { (success) in
            if success {
                // image saved to photos
            }
            else {
                // image not saved
            }
        }
    }
Joe Pagliaro
  • 336
  • 3
  • 8