Save image in Realm - swift

I'm trying to pick image from device's Photo Library in method:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
userPhoto.image = info[UIImagePickerControllerOriginalImage] as! UIImage?
userPhoto.contentMode = .scaleAspectFill
userPhoto.clipsToBounds = true
dismiss(animated: true, completion: nil)
}
and save this picture in Realm (as NSData):
asset.assetImage = UIImagePNGRepresentation(userPhoto.image!)! as NSData?
...
try! myRealm.write
{
user.assetsList.append(asset)
myRealm.add(user)
}
After build succeeded and trying to pick and save image (in the app) i have app error:
'Binary too big'
What i'm doing wrong?
P.S. Sorry for my English :)
After some actions i have this code. But it's overwrite my image.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
let imageUrl = info[UIImagePickerControllerReferenceURL] as! NSURL
let imageName = imageUrl.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let photoURL = NSURL(fileURLWithPath: documentDirectory)
let localPath = photoURL.appendingPathComponent(imageName!)
let image = info[UIImagePickerControllerOriginalImage]as! UIImage
let data = UIImagePNGRepresentation(image)
do
{
try data?.write(to: localPath!, options: Data.WritingOptions.atomic)
}
catch
{
// Catch exception here and act accordingly
}
userPhoto.image = image
userPhoto.contentMode = .scaleAspectFill
userPhoto.clipsToBounds = true
urlCatch = (localPath?.path)!
self.dismiss(animated: true, completion: nil);
}

Don't save the image itself into realm, just save the location of the image into realm as String or NSString and load the image from that saved path. Performance wise it's always better to load images from that physical location and your database doesn't get too big
func loadImageFromPath(_ path: NSString) -> UIImage? {
let image = UIImage(contentsOfFile: path as String)
if image == nil {
return UIImage()
} else{
return image
}
}
or you just save the image name, if it's in your documents directory anyhow
func loadImageFromName(_ imgName: String) -> UIImage? {
guard imgName.characters.count > 0 else {
print("ERROR: No image name")
return UIImage()
}
let imgPath = Utils.getDocumentsDirectory().appendingPathComponent(imgName)
let image = ImageUtils.loadImageFromPath(imgPath as NSString)
return image
}
and here a rough example how to save a captured image to your directory with a unique name:
#IBAction func capture(_ sender: AnyObject) {
let videoConnection = stillImageOutput?.connection(withMediaType: AVMediaTypeVideo)
stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (imageDataSampleBuffer, error) -> Void in
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)
//self.stillImage = UIImage(data: imageData!)
//self.savedImage.image = self.stillImage
let timestampFilename = String(Int(Date().timeIntervalSince1970)) + "someName.png"
let filenamePath = URL(fileReferenceLiteralResourceName: getDocumentsDirectory().appendingPathComponent(timestampFilename))
let imgData = try! imageData?.write(to: filenamePath, options: [])
})
/* helper get Document Directory */
class func getDocumentsDirectory() -> NSString {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
//print("Path: \(documentsDirectory)")
return documentsDirectory as NSString
}

https://realm.io/docs/objc/latest/#current-limitations
maximum data size is 16 MB . this is limitation of realm

Depending on how your serializing the image data (for example if it's a lossless bitmap), it's quite possible that this data exceed 16MB, which as you've stated is Realm's maximum supported size for binary properties.
When you invoke NSData.length, how large does it say your data is?

Related

Uiview to Data (Saving a Gif to firebase)

In my app, I take a photo from my camera, and then the user can add a sticker gif on it.
I want to save the result on Firebase Storage (in a gif format)
So to summarize, I want to convert my UIview into Data, to save it on Firebase ( Storage.storage().reference().child("Gif").putData(data, metadata: nil, completion: { (metadata, error) in })
I have tried that :
let yourViewToData = NSKeyedArchiver.archivedData(withRootObject: self.canvasView)
but the result isn't a gif file
I have tried a func like this but I cannot intercept Data on it and I'm not sure of the result :
let img = self.canvasView.toImage()
animatedGif(from: [img])
func animatedGif(from images: [UIImage]) {
let fileProperties: CFDictionary = [kCGImagePropertyGIFDictionary as String: [kCGImagePropertyGIFLoopCount as String: 0]] as CFDictionary
let frameProperties: CFDictionary = [kCGImagePropertyGIFDictionary as String: [(kCGImagePropertyGIFDelayTime as String): 1.0]] as CFDictionary
let documentsDirectoryURL: URL? = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL: URL? = documentsDirectoryURL?.appendingPathComponent("animated.gif")
if let url = fileURL as CFURL? {
if let destination = CGImageDestinationCreateWithURL(url, kUTTypeGIF, images.count, nil) {
CGImageDestinationSetProperties(destination, fileProperties)
for image in images {
if let cgImage = image.cgImage {
CGImageDestinationAddImage(destination, cgImage, frameProperties)
}
}
if !CGImageDestinationFinalize(destination) {
print("Failed to finalize the image destination")
}
print("Url = \(fileURL)")
}
}
}
Any idea how I can save my UIView to a gif file on Firebase Storage?
I am looking to make an alternative solution . Take like 15 screenshot of UImage from my UIView, in order to make a gif later. I have this func :
func toImage() -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.isOpaque, 0.0)
self.drawHierarchy(in: self.bounds, afterScreenUpdates: false)
let snapshotImageFromMyView = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return snapshotImageFromMyView!
}
Does someone know how can I make like 15 screenshot with this func? Thanks
Thanks !

swift image picker gets several pictures

i have a problem with inserting images into a CollectionView cell using an ImagePicker. The problem is, if I click on a photo which I would like to insert quickly several times, then the photo is inserted several times in different cells.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
picker.dismiss(animated: true, completion: nil)
picker.allowsEditing = true
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
collectionViewController?.imageArray.append(pickedImage)
collectionViewController?.newImages.append(pickedImage)
let guid = UUID()
let fileManager = FileManager.default
let imagePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("\(guid).png")
let data = UIImagePNGRepresentation(fixOrientation(img: pickedImage))
fileManager.createFile(atPath: imagePath as String, contents: data, attributes: nil)
let image = CoreDataManager.shared.createImageyObject(pfad: imagePath, date: Date(), guid: guid)
collectionViewController?.images.append(image)
if collectionViewController?.images.count == 1 {
collectionViewController?.images[0].isBaseImage = true
collectionViewController?.lastIndex = 0
}
collectionViewController?.update()
}
}
Mediainfo contains image url, media url... Maybe you should cache picked imageURL (that unique) in a Set then check if imageURL that's already existed.

Getting location details from image in ios swift

I am trying to get location details from image using
UIImagePickerControllerReferenceURL but I found that PHAsset.fetchAssets(withALAssetURLs: [URL], options: opts) has been deprecated .Please help me in getting location details.
Can we do it using PHAssetCollection?. If so please help me
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
print(info)
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
selectedImage.contentMode = .scaleAspectFit
selectedImage.image = chosenImage
dismiss(animated:true, completion: nil)
if let URL = info[UIImagePickerControllerReferenceURL] as? URL {
let opts = PHFetchOptions()
opts.fetchLimit = 1
let assets = PHAsset.fetchAssets(withALAssetURLs: [URL], options: opts)
let asset = assets[0]
print(asset.location)
// The location is "asset.location", as a CLLocation
// ... Other stuff like dismiss omitted
}
}
Only solution I found so far is to use the iOS 10 code block even in iOS 11 and just ignore the UIImagePickerControllerReferenceURL deprecated message (the key still exists and works in iOS 11)
import AssetsLibrary
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let imageUrl = info[UIImagePickerControllerReferenceURL] as? NSURL{
print(imageUrl.absoluteString) //"assets-library://asset/asset.JPG?id=ED7AC36B-A150-4C38-BB8C-B6D696F4F2ED&ext=JPG"
// access image from URL
let assetLibrary = ALAssetsLibrary()
assetLibrary.asset(for: imageUrl as URL! , resultBlock: { (asset: ALAsset!) -> Void in
if let actualAsset = asset as ALAsset? {
let assetRep: ALAssetRepresentation = actualAsset.defaultRepresentation()
let iref = assetRep.fullResolutionImage().takeUnretainedValue()
let image = UIImage.init(cgImage: iref)
self.img.image = image
}
}, failureBlock: { (error) -> Void in
})
}
dismiss(animated: true, completion: nil)
}
Hope this will help.

saving document path in custom struct array in Userdefaults error swift

I have a custom struct Information. for the property image(string) I want to insert the path of the document directory where the image is saved. When i try to use the UserDefaults to save the struct array, it is saved successfully and also retrieved. But when i use the path to retrieve the image from the document directory it shows the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value.
And when I use the if-else block to catch the exception, No image is displayed on the tableview.
Below is my code:
struct Information{
var image : String
var content : String?
var url : String?
init(image:String,content:String?,url:String?){
self.image = image
self.content = content
self.url = url
}
init(dictionary : [String:String]) {
self.image = dictionary["image"]!
self.content = dictionary["content"]!
self.url = dictionary["url"]!
}
var dictionaryRepresentation : [String:String] {
return ["image" : image, "content" : content!, "url" : url!]
}
}
And my View Controller:
override func viewDidAppear(_ animated: Bool) {
savePath()
loadDefaults()
tableView.reloadData()
}
func saveDefaults()
{
let cfcpArray = information.map{ $0.dictionaryRepresentation }
UserDefaults.standard.set(cfcpArray, forKey: "cfcpArray")
}
func loadDefaults()
{
information = (UserDefaults.standard.object(forKey: "cfcpArray") as! [[String:String]]).map{ Information(dictionary:$0) }
for info in information{
print(info)
}
}
func savePath(){
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
// Get the Document directory path
let documentDirectorPath:String = paths[0]
// Create a new path for the new images folder
imagesDirectoryPath = documentDirectorPath + "/ImagePicker"
var objcBool:ObjCBool = true
let isExist = FileManager.default.fileExists(atPath: imagesDirectoryPath, isDirectory: &objcBool)
// If the folder with the given path doesn't exist already, create it
if isExist == false{
do{
try FileManager.default.createDirectory(atPath: imagesDirectoryPath, withIntermediateDirectories: true, attributes: nil)
}catch{
print("Something went wrong while creating a new folder")
}
}
tableView.reloadData()
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
// The info dictionary may contain multiple representations of the image. You want to use the edited.
guard let selectedImage = info[UIImagePickerControllerEditedImage] as? UIImage
else {
fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
}
image = selectedImage
dismiss(animated: true, completion: nil)
saveImage()
}
func saveImage(){
// Save image to Document directory
var imagePath = Date().description
imagePath = imagePath.replacingOccurrences(of: " ", with: "")
imagePath = imagesDirectoryPath + "/\(imagePath).png"
path = imagePath
// print(path!)
let data = UIImagePNGRepresentation(image)
let success = FileManager.default.createFile(atPath:path!, contents: data, attributes: nil)
information.append(Information(image:path!, content:" ", url: " "))
saveDefaults()
tableView.reloadData()
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "TableViewCell"
/*Because you created a custom cell class that you want to use, downcast the type of the cell to your custom cell subclass, MealTableViewCell.*/
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier , for: indexPath) as? TableViewCell
else{
fatalError("The dequeued cell is not an instance of MealTableViewCell.")
}
let info = information[indexPath.row]
if let data = FileManager.default.contents(atPath: info.image)
{
let decodeimage = UIImage(data: data)
cell.photos.image = decodeimage
}
else{
print("Not displaying image")
}
// cell.photos.image = UIImage(data: data!)
return cell
}
Any suggestions is really appreciated. Thank you.
Don't do that. The URL to the documents folder changes periodically for security reasons.
Save a relative path – or just the file name – and after reading the data get the current documents URL and append the path.
Note: NSSearchPathForDirectoriesInDomains is outdated. Use url(for:in:appropriateFor:create:) and the URL related API of FileManager
PS: Why are content and url optionals although the dictionary initializer passes always non-optional values?
Here is the working code. Tested.
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
}
And to save the image :
// Save image to Document directory
var imagePath = Date().description
imagePath = imagePath.replacingOccurrences(of: " ", with: "")
imagePath = "/\(imagePath).png"
let relpath = getDocumentsURL()
let relativepath = relpath.appendingPathComponent(imagePath)
let data = UIImagePNGRepresentation(image)
let success = FileManager.default.createFile(atPath: relativepath.path , contents: data, attributes: nil)

How to Handle Image Orientation

I have an issue on capture image from camera. When I capture the image from camera using UIImagePickerController and after Capturing I save the image in my document directory and display it on my custom collectionView. But the problem is when I capture image and save it to document directory and when I load the image in my collectionView it display for the user on wrong orientation how can I handle the image orientation? I tried to save image as JPEG its work good but it support only one orientation. I want to save image as png because it support all orientation.
My code:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
// handle image orientation
//end
// code for save image in document directory from camera roll
let fileManager = NSFileManager.defaultManager()
do {
let document = try fileManager.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
let getFolders = try fileManager.contentsOfDirectoryAtURL(document, includingPropertiesForKeys: nil, options: .SkipsHiddenFiles)
var maxImageNumber:Int = 0 // for get the max number image in document directory
for folder in getFolders {
if folder.lastPathComponent! == albumName {
let getImagesCheck = try fileManager.contentsOfDirectoryAtURL(folder, includingPropertiesForKeys: nil, options: .SkipsHiddenFiles)
let getImages = try fileManager.contentsOfDirectoryAtURL(folder, includingPropertiesForKeys: nil, options: .SkipsHiddenFiles)
if getImages.count <= 0 {
let imageUrl = folder.URLByAppendingPathComponent("Image \(getImagesCheck.count + 1).png")
if let convertImage = UIImagePNGRepresentation(image) {
convertImage.writeToURL(imageUrl, atomically: true)
}
}else {
// continue save images
let getImages_else = try fileManager.contentsOfDirectoryAtURL(folder, includingPropertiesForKeys: nil, options: .SkipsHiddenFiles)
for img in getImages_else {
let getImageName = img.lastPathComponent!
let arrayOne = getImageName.componentsSeparatedByString(".")
let arrayTwo = arrayOne[0].componentsSeparatedByString(" ")
let getImageNumber = Int(arrayTwo[1])
if getImageNumber! > maxImageNumber {
maxImageNumber = getImageNumber!
}
}
let imageUrl = folder.URLByAppendingPathComponent("Image \(maxImageNumber + 1).png")
if let convertImage = UIImagePNGRepresentation(image) {
convertImage.writeToURL(imageUrl, atomically: true)
}
}
}
}
}catch {
print(error)
}
self.dismissViewControllerAnimated(true, completion: nil)
}