Storing images to CoreData - Swift - ios

In my code I managed to save a textLabel with CoreData but I can't seem to properly save the image. I've read some tutorials and I know I have to convert it to NSData. But how do I do it?
Thanks in advance!

You shouldn't save large data inside core data, an Apple engineer told me this little trick at the last WWDC:
You can use the property "Allows external storage":
By doing this as far as i know, your image will be stored somewhere in the file system, and inside core data will be saved a link to your picture in the file system. every time you'll ask for the picture, core data will automatically retrive the image from the file system.
To save the image as NSData you can do:
let image = UIImage(named: "YourImage")
let imageData = NSData(data: UIImageJPEGRepresentation(image, 1.0))
managedObject?.setValue(imageData, forKey: "YourKey")
Remember that 1.0 in the UIImageJPEGRepresentatio means that your using the best quality and so the image will be large and heavy:
The quality of the resulting JPEG image, expressed as a value from 0.0
to 1.0. The value 0.0 represents the maximum compression (or lowest
quality) while the value 1.0 represents the least compression (or best
quality).

Core Data isn't meant to save big binary files like images. Use Document Directory in file system instead.
Here is sample code to achieve that.
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as! String
// self.fileName is whatever the filename that you need to append to base directory here.
let path = documentsDirectory.stringByAppendingPathComponent(self.fileName)
let success = data.writeToFile(path, atomically: true)
if !success { // handle error }
It is recommended to save filename part to core data along with other meta data associated with that image and retrieve from file system every time you need it.
edit: also note that from ios8 onwards, persisting full file url is invalid since sandboxed app-id is dynamically generated. You will need to obtain documentsDirectory dynamically as needed.

Here you go for JPEG and for PNG you just use UIImagePNGRepresentation:
let image = UIImage(named: "YourImage")
let imageData = NSData(data: UIImageJPEGRepresentation(image, 1.0))
managedObject?.setValue(imageData, forKey: "YourKey")

Generally large data objects are not stored in a database or Core Data. Instead save the images in the Document directory (or a sub-directory) and save the file name in Core Data.
Se the answer by #Valentin on how to create a data representation of an image.
Save it with func writeToFile(_ path: String, atomically atomically: Bool) -> Bool

Related

Save Image (SwiftUI) to Realm database

I am using SwiftUI and Realm.
I want to save an Image to the database. The image is a photo taken from the device's camera and is not stored in the gallery.
It's my understanding that I need to convert the image to NSData, but I can only find syntax that works with UIImage.
I tried
let uiImage: UIImage = image.asUIImage()
but get this error:
Value of type 'Image?' has no member 'asUIImage'
What am I doing wrong here, how can I have an Image to Realm local database?
EDIT: Thanks for the suggested "possible duplicate", but no: the duplicate (which I have already seen prior to making my post) is for UIImage (UIKit). I am using Image (SwiftUI).
The struct Image is only a building block for the UI in Swift UI and it is not an object that represents the literal image, but rather something that displays some image.
The common approach, is to see how you create Image - where do you get the actual image from - and to use the source, the image itself to save it.
Just as side note, I wanted to mention that storing data blobs in Realm database can be extremely slow and more commonly used and fast approach is to write files to disk and to store only the names of those files in the database.
Elaborating on this approach, you can:
create a folder to store your images in Library path in user domain mask
You can read about iOS Sandbox file system and where you can store stuff at Apple File System Programming Guide.
For our purposes, it will suffice to this method.
let imagesFolderUrl = try! FileManager.default.url(for: . applicationSupportDirectory, in: .userDomainMask)
.appendingPathComponent("images_database")
You should check if this directory exists and create it if it doesn't - there's plenty of information about this online.
Then, when you have an image Data, you give it a name, you create a URL that will point to where it will be stored and then you write it.
let imageData: Data
let imageName = "some new name for this particular image - maybe image id or something"
let imageUrl = imagesFolderUrl.appendingPathComponent(imageName)
imageData.write(to: url) // Very slow operation that you should perform in background and not on UI thread
Then, you store the name of the image in the Realm database
Then, when you pull a record from Realm database and see the name of the image, you can construct the url again and read a Data from it
let record: RealmRecord
let imageName = record.imageName
let url = imagesFolder.appendingPathComponent(imageName)
let data = Data(url: imageName)
That's overly simplifying it.

Data to UIImage to UIImageJPEGRepresentation equality failure

Why does this transformation fails to result in the same image data?
let path = Bundle(for: type(of: self)).url(forResource: "Image", withExtension: "jpg")
inputData = try! Data(contentsOf: path!)
let testImage = UIImage(data: inputData)
let testImageData = UIImageJPEGRepresentation(testImage!, 1.0)
expect(testImageData).to(equal(inputData))
From what I understand UIImageJPEGRepresentation and UIImagePNGRepresentation can strip the image of meta data. Is that the reason?
There is no particular reason why two JPEG files showing the same image would be identical. JPEG files have lots of header info, different compression algorithms, etc. And even if both files have a compression level of 1 (do they?) they are both lossy, so something will differ every time you expand and recompress. Your expectations here are just wrong. But then it also sounds like you’re trying to test something that does not need testing in the first place.
I was facing the same Issue, and was able to solve using UIImagePNGRepresentation to convert the UIImage to Data, and then compared to see if both Data were equal.

How to fetch an image from photo library of iOS using URL path?

I used UIImagePickerController to select an image from photo library of an iOS device. Then I saved the URL path of the selected image in database using Core Data. Now I want to use that saved URL path to fetch the image in another view controller. How can I fetch the image using URL path using Objective-C? Is there any framework for that? I found ALAssets framework is deprecated.
You should not save the URL for the image, unless you saved it into a more permanent location on the device. UIImagePickerController will provide you a URL to a temporary image, but this may be deleted after you close the app.
Instead, grab the actual UIImage locally and save that as a blob with CoreData.
let image = info[UIImagePickerControllerOriginalImage] as? UIImage
let imageData = UIImageJPEGRepresentation(image, 1.0)
From here, save the data as a blob to a CoreData database. This is an article in itself, so I won't go into depth here. Refer to a resource such as http://pinkstone.co.uk/how-to-save-a-uiimage-in-core-data-and-retrieve-it/
To retrieve that image from the data, fetch the blob from CoreData and convert it to a UIImage:
let imageData = < Core Data Fetch and Processing >
if let image = UIImage(data: imageData) {
// Use your image
}

Save image to core data while selecting image from photo album

I have used Eureka to create a form and I have installed the image framework. I have added an image row but I am struggling to save the image to coredata.
The attribute in coredata is set to binary data
Based on how my user form works, I need to declare my image variable globally.
I think my problem is connecting the relationship between NSdata and UIImage. The tutorials I find handles this through UIImagePNGRepresentation. But they know the image file name. I don't know this as I select the file from photos.
Global variable = var otsPhoto: NSData? = nil
Form field
<<< ImageRow() {
$0.title = "Attachment"
$0.sourceTypes = [.PhotoLibrary, .SavedPhotosAlbum, .Camera] //1
$0.value = otsPhoto //2
$0.clearAction = .yes(style: .destructive) //3
$0.onChange { [unowned self] row in //4
self.otsPhoto = row.value
}
Returns 2 errors
1) cannot assign value type NSData? to type UIImage?
2) Cannot convert value of type (_) -> to expected argument
It is not advisable to store Images into Sqlite file. The best approach would be to:
Copy the Image from the Photos using UIImagePickerController
to the application bundle or download the image from the server to
the app bundle.
Get the path of the image stored from the application bundle. (you will already know this as you are storing at some location in the app bundle)
Store this path as a String in your table
This way even if the photo is deleted from the Photos, there is a copy of it in your app.
Some resources
https://developer.apple.com/documentation/uikit/uiimagepickercontroller
https://developer.apple.com/documentation/foundation/nsfilemanager

Ios swift - storing uiimage in document directory and path in core data

I'm currently storing my images directly in core data and experiencing issues when having to retrieve a high quality images.
I was advised to store the images in the document directory and save a path in core-data as to not store the actual images there but simply the address of where I can go and find it.
Can someone push me in the right direction? Can't seem to find the appropriate guidance?
I was able to find the answers to all my questions in this youtube video -
https://www.youtube.com/watch?v=6vk4UrJR8WM
This is the github with the file that has instructions as to how to complete this - https://github.com/TDAbboud/WeightLogger-Images
Try Hanake cache: https://github.com/Haneke/Haneke
It worked really well for me personally with the same problem. It makes a sometimes painful task pretty easy.
Save an image in Document directory is easy this code is not optimized is just for give you a hint( you should manage errors, optionals etc). Suppose that you already have a valid UIImage instance called image and a valid image name String called imageName
let data = UIImagePNGRepresentation(image)
// Unwrapping the data optional
if let data = data {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let path = (paths.first! as! NSString).stringByAppendingPathComponent(imageName)
data.writeToFile(path, options: [])
//Save the path into your managed object
}

Resources