0

Please find code below.

  1. I am creating a QRCode.
  2. Then I want to convert it to png and email as an attachment.

The line:

let imgData = UIImagePNGRepresentation(imageToEmail)

keeps giving back nil and causes the code to crash. Any help?

class ViewController: UIViewController, MFMailComposeViewControllerDelegate {
    @IBOutlet weak var dataField: UITextField!
    @IBOutlet weak var displayCodeView: UIImageView!

    var filter:CIFilter!
    var qrImage = UIImage()

    @IBAction func generatePressed(_ sender: UIButton) {
        if let text = dataField.text {
            let data = text.data(using: .ascii, allowLossyConversion: false)

            filter = CIFilter(name: "CIQRCodeGenerator")
            filter.setValue(data, forKey: "inputMessage")

            let transform = CGAffineTransform(scaleX: 10, y: 10)

            qrImage = UIImage(ciImage: filter.outputImage!.transformed(by: transform))
            displayCodeView.image = qrImage

            let mailComposeViewController = configureMailController(imageToEmail: qrImage)
            if MFMailComposeViewController.canSendMail() {
                self.present(mailComposeViewController, animated: true, completion: nil)
            } else {
                showMailError()
            }
        }
    }

    func configureMailController(imageToEmail: UIImage) -> MFMailComposeViewController {
        let mailComposerVC = MFMailComposeViewController()
        mailComposerVC.mailComposeDelegate = self

        mailComposerVC.setToRecipients(["jc@project44laight.com"])
        mailComposerVC.setSubject("QRCode")
        let imgData = UIImagePNGRepresentation(imageToEmail)
        mailComposerVC.addAttachmentData(imgData!, mimeType: "image/png", fileName:  "qrCode.png")
        let emailBody = "<html><body><p>QR code is attached in image </p></body></html>"
        mailComposerVC.setMessageBody(emailBody, isHTML:true)

        return mailComposerVC
    }

    func showMailError() {
        let sendMailErrorAlert = UIAlertController(title: "Email error", message: "Your device could not send email", preferredStyle: .alert)
        let dismiss = UIAlertAction(title: "Ok", style: .default, handler: nil)
        sendMailErrorAlert.addAction(dismiss)
        self.present(sendMailErrorAlert, animated: true, completion: nil)
    }

    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        switch result {
        case .cancelled:
            print("Mail cancelled")
            break
        case .saved:
            print("Mail saved")
            break
        case .sent:
            print("Mail sent")
            break
        case .failed:
            print("Mail failed to send")
            break

        }
        controller.dismiss(animated: true, completion: nil)
    }
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • 1
    Does the image view show the generated QR Code properly? – rmaddy May 28 '18 at 04:00
  • yes. If I comment out the call to the following block the code works and qrCode image show up correctly . let mailComposeViewController = configureMailController(imageToEmail: qrImage) if MFMailComposeViewController.canSendMail() { self.present(mailComposeViewController, animated: true, completion: nil) } else { showMailError() } – user9832689 May 28 '18 at 04:56
  • Not that this is related to your issue but you should move the line `let mailComposeViewController = configureMailController(imageToEmail: qrImage)` to be inside the `if MFMailComposeViewController.canSendMail() {` block. No need to create the mail composer if you can't send email. – rmaddy May 28 '18 at 04:59
  • Furthermore if I try UIImagePNGRepresentation(UIImage(named:"FileIsaved")!) then the emailing parts works also. – user9832689 May 28 '18 at 05:05

1 Answers1

0

Add this extension to your code

extension UIImage {

/**
 Creates the UIImageJPEGRepresentation out of an UIImage
 @return Data
 */

func generatePNGRepresentation() -> Data? {

    let newImage = self.copyOriginalImage()
    let newData = UIImagePNGRepresentation(newImage)

    return newData!
}

/**
 Copies Original Image which fixes the crash for extracting Data from UIImage
 @return UIImage
 */

private func copyOriginalImage() -> UIImage {
    UIGraphicsBeginImageContext(self.size);
    self.draw(in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext();

    return newImage!
    }
}

In your code,

let imgData = imageToEmail.generatePNGRepresentation()
  • Hello Bala ji. Ty for the suggestion. That does work!!! Why is that the copying has to be explicitly - shouldn't the conversion constructor doing this? Seems kind of crazy – user9832689 May 28 '18 at 06:11
  • 1
    I am also new to swift I created ReadQr app in App Store I also had the same returning nil problem it seems it only takes the cgimage for conversion to data that's why we set it to the context. And then covert it and return the data. –  May 28 '18 at 06:15
  • Thanks for your help!! – user9832689 May 28 '18 at 07:31