Md. Mostafizur Rahman
Md. Mostafizur Rahman

Reputation: 481

UIImageWriteToSavedPhotosAlbum not working

I am generating barcode from a string and then try to save this image to iPhone photos library. Here is my code:

@IBOutlet weak var uuidLabel: UILabel!
@IBOutlet weak var barcodeDisplay: UIImageView!

@IBAction func generateBarcode(_ sender: Any) {
    barcodeDisplay.image = generateBarcodeFromString(string: uuidLabel.text!)
    UIImageWriteToSavedPhotosAlbum(barcodeDisplay.image!, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}

@objc func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
    if let error = error {
        let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert)
        ac.addAction(UIAlertAction(title: "OK", style: .default))
        present(ac, animated: true)
    } else {
        let ac = UIAlertController(title: "Saved!", message: "Your image has been saved to your photos.", preferredStyle: .alert)
        ac.addAction(UIAlertAction(title: "OK", style: .default))
        present(ac, animated: true)
    }
}

func generateBarcodeFromString(string:String)->UIImage? {
    let data = string.data(using: String.Encoding.ascii)
    if let filter = CIFilter(name: "CICode128BarcodeGenerator") {
        filter.setValue(data, forKey: "inputMessage")
        let transform = CGAffineTransform(scaleX: 1, y: 1)
        if let output = filter.outputImage?.transformed(by: transform) {
            return UIImage(ciImage: output)
        }
    }
    return nil
}

When i run this app, it's generate the barcode and it's displayed on the view controller. When i try to save this image to iPhone photos library, the selector says,"Your image has been saved to your photos." but image is not saved into iPhone photos library.

After that, when i try to convert this image into NSData by following:

let data = UIImagePNGRepresentation(barcodeDisplay.image!) as NSData?

It's return nil. What's the problem behind this ?

Upvotes: 4

Views: 3969

Answers (1)

Nischal Hada
Nischal Hada

Reputation: 3288

Swift version: 5.2

The problem is QRCode is CIImage so we need to convert it to UIImage in-order to save to Photos Album

QRCodeGenerator.swift

import UIKit

final class QrCodeGenerator {
    func generateQRCode(from string: String) -> UIImage? {
        let data = string.data(using: String.Encoding.ascii)

        if let filter = CIFilter(name: "CIQRCodeGenerator") {
            filter.setValue(data, forKey: "inputMessage")
            let transform = CGAffineTransform(scaleX: 5, y: 5) // Scale according to imgView
            if let output = filter.outputImage?.transformed(by: transform) {
                return convert(output)
            }
        }
        return nil
    }

    private func convert(_ cmage:CIImage) -> UIImage? {
        let context:CIContext = CIContext(options: nil)
        guard let cgImage:CGImage = context.createCGImage(cmage, from: cmage.extent) else { return nil }
        let image:UIImage = UIImage(cgImage: cgImage)
        return image
    }
}

ImageSaver.swift

import UIKit

final class ImageSaver: NSObject {
    func writeToPhotoAlbum(image: UIImage) {
        UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveError), nil)
    }

    @objc func saveError(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
        if let error = error {
            print("error: \(error.localizedDescription)")
        } else {
            print("Save completed!")
        }
    }
}

QrCodeViewController

import UIKit

class QrCodeViewController: UIViewController {
    @IBOutlet weak var qrCodeImageView: UIImageView!
    private let qrCodeGenerator = QrCodeGenerator()
    private let imageSaver = ImageSaver()

    init() {
        super.init(nibName: "QrCodeViewController", bundle: nil)
    }

    required init?(coder _: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Save Photo", style: .plain, target: self, action: #selector(addTapped))
        guard let image = qrCodeGenerator.generateQRCode(from: "mock") else { return }
        qrCodeImageView.image = image
    }

    @objc func addTapped() {
        guard let inputImage = QrCodeGenerator().generateQRCode(from: "mock") else { assertionFailure("null image"); return }
        imageSaver.writeToPhotoAlbum(image: inputImage)
    }

}

For letting the app to be able to write (add) photos into the device photos library we have to add the NSPhotoLibraryAddUsageDescription into the application's plist file:

<key>NSPhotoLibraryAddUsageDescription</key>
<string>Our application needs permission to write photos...</string>

Upvotes: 13

Related Questions