Swift Memory Crash From Selecting Image - swift

I have users enter a profile picture in an Enter Photo Controller as apart of registration. 90% of the time it doesn't crash when the user selects a photo from the Image Picker Controller. The error says that it's a memory error.
I thought resizing was supposed to fix the problem, yet it persists.
I am using Firestore as a backend.
Any ideas on why this is happening? I'm going insane trying to figure this out!
extension EnterPhotoController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
weak var selectedImage = info[.originalImage] as? UIImage
let selectedImage2 = selectedImage?.resized(maxSize: CGSize(width: 500, height: 500))
let imageButton = (picker as? CustomImagePickerController)?.imageBttn
imageButton?.setImage(selectedImage2?.withRenderingMode(.alwaysOriginal), for: .normal)
self.imageFull = true
dismiss(animated: true)
self.errorLabel.text = "Registering, hang tight..."
self.errorLabel.isHidden = false
self.selectPhotoButton.isEnabled = false
let filename = UUID().uuidString
let ref = Storage.storage().reference(withPath: "/images/\(filename)")
guard let imageData = selectedImage2?.jpegData(compressionQuality: 0.9) else { return }
ref.putData(imageData, metadata: nil) { (nil, err) in
guard err == nil else { return }
ref.downloadURL { (url, err) in
guard err == nil else { return }
let imageUrl = url?.absoluteString ?? ""
if imageUrl == "" {
print("fuck me man")
}
self.saveInfoToFirestore(imageUrl: imageUrl)
}
}
}
}
extension UIImage {
public func resized(maxSize: CGSize) -> UIImage? {
let imageSize = self.size
guard imageSize.height > 0, imageSize.width > 0 else { return nil }
let ratio = min(maxSize.width/imageSize.width, maxSize.height/imageSize.height)
let newSize = CGSize(width: imageSize.width*ratio, height: imageSize.height*ratio)
let renderer = UIGraphicsImageRenderer(size: newSize)
return renderer.image(actions: { (ctx) in
self.draw(in: CGRect(origin: .zero, size: newSize))
})
}
}
And from memory (my memory) I believe this is the error. I can't reproduce it.
malloc: Heap corruption detected, free list is damaged at 0x280165460 *** Incorrect guard value: 10751132320 "app-name"(945,0x16f5df000) malloc: *** set a breakpoint in malloc_error_break to debug

I'm not sure if my issue was similar, but I went crazy over figuring my issue out. I was trying to add custom metadata with spaces in them. So if you're adding any custom metadata, take out the spaces. Just a possibility this is your problem, I can't see your upload code.

Related

App Crashes When saving image to camera roll

When I try saving a scan to the camera roll the app crashes
Here's the Code:
func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
// Make sure the user scanned at least one page
guard scan.pageCount >= 1 else {
// You are responsible for dismissing the VNDocumentCameraViewController.
controller.dismiss(animated: true)
return
}
// This is a workaround for the VisionKit bug which breaks the `UIImage` returned from `VisionKit`
// See the `Image Loading Hack` section below for more information.
var arrImages = [UIImage]()
for i in 0...scan.pageCount-1 {
let originalImage = scan.imageOfPage(at: i)
let fixedImage = reloadedImage(originalImage)
arrImages.append(fixedImage)
}
controller.dismiss(animated: true)
let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let docURL = documentDirectory.appendingPathComponent("Delete This")
if Filetype == 1 {
let data = createNewPDF(arrImage: arrImages)
do {
try data?.write(to: docURL, options: .completeFileProtection)
print("Success")
} catch(let error) {
print("error is \(error.localizedDescription)")
}
} else {
if Filetype == 2 {
if customjg == 68 {
for i in 0...scan.pageCount-1 {
let originalImage = scan.imageOfPage(at: i)
let fixedImage = originalImage.jpegData(compressionQuality: 0.7)
let reloadedImage = UIImage(data: fixedImage!)
UIImageWriteToSavedPhotosAlbum(reloadedImage!, nil, nil, nil);
//arrImages.append(fixedImage)
}
if customjg == 69 {
let originalImage = scan.imageOfPage(at: 1)
let rere = self.resizeImagezz(image: originalImage, targetSize: CGSize(width: Widthv, height: Heightv))
let fixedImage = rere.jpegData(compressionQuality: 0.7)
let reloadedImage = UIImage(data: fixedImage!)
UIImageWriteToSavedPhotosAlbum(reloadedImage!, nil, nil, nil);
//arrImages.append(fixedImage)
}
}
}else{
if Filetype == 3 {
for i in 0...scan.pageCount-1 {
let originalImage = scan.imageOfPage(at: i)
let fixedImage = originalImage.pngData()
let reloadedImage = UIImage(data: fixedImage!)
UIImageWriteToSavedPhotosAlbum(reloadedImage!, nil, nil, nil);
//arrImages.append(fixedImage)
}
}
}
}
}
The File Type is a segment controlled switch case. The first option by default is JPEG.
It does not even ask for the camera roll access permission before crashing (Yes I've put it in the info.plist file).
Only PDF works as of now.
But the twist is that everything works when installed on iOS 14 Beta.
Please help me rectify this issue As soon as you can.
Thanks for the help in Advance.
As per documentation - https://developer.apple.com/documentation/uikit/1619125-uiimagewritetosavedphotosalbum,
we should implement the completionSelector. and for the same set completionTarget as self.
implement the api as below:
UIImageWriteToSavedPhotosAlbum(reloadedImage!, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
then in this completionSelector:
#objc func image(_ image: UIImage, didFinishSavingWithError error: NSError?, contextInfo: UnsafeRawPointer) {
guard let error = error else {//success return}
// found error
print(error)
}

UIImage sometimes flipped [duplicate]

If I use the image before it is saved it is normal. But if I save it and use it later is is 90 degrees turned. How can I make sure it doesn't save sideways?
func saveEvent(_ center1: CLLocation, title2: String, imagePicked1: UIImage)
{
let data = UIImagePNGRepresentation(imagePicked1);///
let url = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(NSUUID().uuidString+".dat")
do {
try data!.write(to: url!, options: [])
} catch let e as NSError {
print("Error! \(e)");
return
}
let image11 = CKAsset(fileURL: url!)
self.eventRecord.setObject(image11 as CKAsset, forKey: "Picture")
let publicData = CKContainer.default().publicCloudDatabase
publicData.save(self.eventRecord, completionHandler: { record, error in
if error == nil
{
print("Image saved")
}else{
print(error!)
}
})
}
If you need to save your PNG with correct rotation you will need to redraw your image if its orientation it is not .up. You can redraw it as follow:
extension UIImage {
func png(isOpaque: Bool = true) -> Data? { flattened(isOpaque: isOpaque)?.pngData() }
func flattened(isOpaque: Bool = true) -> UIImage? {
if imageOrientation == .up { return self }
UIGraphicsBeginImageContextWithOptions(size, isOpaque, scale)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(origin: .zero, size: size))
return UIGraphicsGetImageFromCurrentImageContext()
}
}
edit/update:
For iOS10+ tvOS10+ you can use UIGraphicsImageRenderer:
extension UIImage {
func png(isOpaque: Bool = true) -> Data? { flattened(isOpaque: isOpaque).pngData() }
func flattened(isOpaque: Bool = true) -> UIImage {
if imageOrientation == .up { return self }
let format = imageRendererFormat
format.opaque = isOpaque
return UIGraphicsImageRenderer(size: size, format: format).image { _ in draw(at: .zero) }
}
}
Playground testing:
Usage for images without transparency:
let image = UIImage(data: try! Data(contentsOf: URL(string: "https://i.stack.imgur.com/varL9.jpg")!))!
if let data = image.png() {
let imageFromPNGData = UIImage(data: data)
}
With transparency :
if let data = image.png(isOpaque: false) {
let imageFromPNGData = UIImage(data: data)
}
Just convert the image to JPEG data instead. No need to redraw your image:
let imageData = image.jpegData(compressionQuality: 1.0)
You can use this as well to prevent it from changing of orientation.
func rotateImage(image: UIImage) -> UIImage? {
if (image.imageOrientation == UIImage.Orientation.up ) {
return image
}
UIGraphicsBeginImageContext(image.size)
image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
let copy = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return copy
}

How to save resized images?

Good evening
I am trying to save the resized images in Documents Directory, to avoid having to resize every time it is called.
Analyzing the problem is just when I use the following line:
let jpgImageData = UIImageJPEGRepresentation (image, 1.0)
It appears that UIImageJPEGRepresentation undoes the changes made to the image and thus saves the image in the same ratio.
Anyone know a way to fix this?
Below the code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var imgView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let myImageName = "image_10001.jpg"
let imagePath = fileInDocumentsDirectory(filename: myImageName)
if let image = UIImage(named:"image_10001")?.resizedImage(newSize: UIScreen.main.bounds.size){
print("Image : \(image.size.height)")
_ = saveImage(image: image, path: imagePath)
}
if let loadedImage = loadImageFromPath(path: imagePath){
print("Screen: \(UIScreen.main.bounds.size.height)")
print("Image Size: \(loadedImage.size.height)")
// let image = UIImageJPEGRepresentation(loadedImage, 0.9)
// let imgRes = UIImage(data: image!)?.resizedImage(newSize: UIScreen.main.bounds.size)
////
// let load = loadedImage.resizedImage(newSize: UIScreen.main.bounds.size)
//
// print("Load: \(load.size.height)")
//
// _ = saveImage(image: load, path: imagePath)
//
imgView.image = loadedImage
//
// imgView.image = UIImage(data: image!)?.resizedImage(newSize: UIScreen.main.bounds.size)
}
// Do any additional setup after loading the view, typically from a nib.
}
func loadImageFromPath(path: String) -> UIImage? {
let image = UIImage(contentsOfFile: path)
if image == nil {
print("missing image at: \(path)")
}
print("Loading image from path: \(path)") // this is just for you to see the path in case you want to go to the directory, using Finder.
return image
}
func getDocumentsURL() -> URL {
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
return documentsURL
}
func fileInDocumentsDirectory(filename: String) -> String {
let fileURL = getDocumentsURL().appendingPathComponent(filename)
return fileURL.path
}
func saveImage (image: UIImage, path: String ) -> Bool{
print("Save")
let url = URL(fileURLWithPath: path)
// let pngImageData = UIImagePNGRepresentation(image)
let jpgImageData = UIImageJPEGRepresentation(image, 1.0) // if you want to save as JPEG
let img = UIImage(data:jpgImageData!)
//
print("SIMG: \(String(describing: img?.size.height))")
do {
_ = try jpgImageData?.write(to: url, options: .atomicWrite)
print("Save Success")
} catch let error {
print(error)
return false
}
return true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension UIImage {
/// Returns a image that fills in newSize
func resizedImage(newSize: CGSize) -> UIImage {
// Guard newSize is different
guard self.size != newSize else { return self }
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
self.draw(in: CGRect(x:0, y:0, width:newSize.width, height: newSize.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
/// Returns a resized image that fits in rectSize, keeping it's aspect ratio
/// Note that the new image size is not rectSize, but within it.
func resizedImageWithinRect(rectSize: CGSize) -> UIImage {
let widthFactor = size.width / rectSize.width
let heightFactor = size.height / rectSize.height
var resizeFactor = widthFactor
if size.height > size.width {
resizeFactor = heightFactor
}
let newSize = CGSize(width:size.width/resizeFactor, height:size.height/resizeFactor)
let resized = resizedImage(newSize: newSize)
return resized
}
var jpeg: Data? {
return UIImageJPEGRepresentation(self, 1) // QUALITY min = 0 / max = 1
}
var png: Data? {
return UIImagePNGRepresentation(self)
}
}
extension Data {
var uiImage: UIImage? {
return UIImage(data: self)
}
}
I assume you have some "old" image inside your documents directory that was saved with some older code you had (not resized).
I assume that because the code you posted will not save any new images, because of this line:
if let image = UIImage(named:"image_10001")?.resizedImage(newSize: UIScreen.main.bounds.size){
//resize code
}
I think you wanted to use here same image name just taken from bundle:
if let image = UIImage(named: myImageName)?.resizedImage(newSize: UIScreen.main.bounds.size){
//resize code
}
You can Reset Simulator Content and confirm that no image will be loaded with the code you posted here.

PNG/JPEG representation from CIImage always returns nil

I'm currently making a photo editing app.
When a photo is selected by the user, it is automatically converted into black and white using this code:
func blackWhiteImage(image: UIImage) -> Data {
print("Starting black & white")
let orgImg = CIImage(image: image)
let bnwImg = orgImg?.applyingFilter("CIColorControls", withInputParameters: [kCIInputSaturationKey:0.0])
let outputImage = UIImage(ciImage: bnwImg!)
print("Black & white complete")
return UIImagePNGRepresentation(outputImage)!
}
The problem I am having with this code is that I keep getting this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
I have had my code in a slightly different configuration, but it still breaks when it gets to the UIImagePNG/JPEGRepresentation(xx) section.
Are there any ways to get the PNG or JPEG data from a CIImage for use in an image view / just UIImage in general?
Any of the other methods don't go into enough detail for what code should be used.
Just begin a new graphics context and draw your grayscale image there. iOS 10 or later you can use UIGraphicsImageRenderer, for older iOS version syntax please check edit history:
Xcode 11 • Swift 5.1
func blackWhiteImage(image: UIImage, isOpaque: Bool = false) -> Data? {
guard let ciImage = CIImage(image: image)?.applyingFilter("CIColorControls", parameters: [kCIInputSaturationKey: 0]) else { return nil }
let format = image.imageRendererFormat
format.opaque = isOpaque
return UIGraphicsImageRenderer(size: image.size, format: format).image { _ in
UIImage(ciImage: ciImage).draw(in: CGRect(origin: .zero, size: image.size))
}.pngData()
}
You can also extend UIImage to return a grayscale image :
extension UIImage {
var coreImage: CIImage? { CIImage(image: self) }
func grayscale(isOpaque: Bool = false) -> UIImage? {
guard let coreImage = coreImage?.applyingFilter("CIColorControls", parameters: [kCIInputSaturationKey: 0]) else { return nil }
let format = imageRendererFormat
format.opaque = isOpaque
return UIGraphicsImageRenderer(size: size, format: format).image { _ in
UIImage(ciImage: coreImage).draw(in: CGRect(origin: .zero, size: size))
}
}
}
let profilePicture = UIImage(data: try! Data(contentsOf: URL(string:"http://i.stack.imgur.com/Xs4RX.jpg")!))!
if let grayscale = profilePicture.grayscale(), let data = grayscale.pngData() { // or Swift 4.1 or earlier -> let data = UIImagePNGRepresentation(grayscale)
print(data.count) // 689035
}

"CIImage initWithCVPixelBuffer:options:" failed because its pixel format p422 is not supported in iOS 10

In ios10 , I want to get video capture, but get an error "[CIImage initWithCVPixelBuffer:options:] failed because its pixel format p422 is not supported."
My code is this:
func previewImage(handle: (image: UIImage?) -> Void) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
guard let time = self.player?.currentTime() else {
return
}
guard let pixelBuffer = self.output?.copyPixelBufferForItemTime(time,
itemTimeForDisplay: nil) else {
return
}
let ciImage = CIImage(CVPixelBuffer: pixelBuffer)
let temporaryContext = CIContext(options: nil)
let rect = CGRectMake(
0,
0,
CGFloat(CVPixelBufferGetWidth(pixelBuffer)),
CGFloat(CVPixelBufferGetHeight(pixelBuffer))
)
let image: UIImage?
if let videoImage = temporaryContext.createCGImage(ciImage, fromRect: rect) {
image = UIImage(CGImage: videoImage)
}
else {
image = nil
}
handle(image: image)
})
})
}
get an error like this :
what should I do 😲😲😲😲😲😲😲?
Can you show how you're setting up your AVPlayerItemVideoOutput?
It looks like you're using some (unknown to me, p422?) kind of 4:2:2 format instead of a more compatible one like kCVPixelFormatType_420YpCbCr8BiPlanarFullRange or kCVPixelFormatType_32BGRA.