I'm writing an iOS application using Swift 2.2 and I want to save profile picture of an account locally in a Realm database according to resize the picked image. I googled and also saw here but not clear well. If images are small in size or less in numbers or if I have more images or large size what can be done?
another confusion is what I will use either NSData or NSString ?
my model is
class IndividualContact: Object {
dynamic var photoDataString = ""
var photoData: NSData? = nil
dynamic var isPhotoAvailable = false
}
and I already picked image from gallery
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
imageView.contentMode = .ScaleAspectFit
imageView.image = pickedImage
}
now how can I store it according to resize it as (120*110 size)?
You can not save directly image into Realm, convert it into NSData and the store it.
if your image is of type JPEG then use,
let data = NSData(data: UIImageJPEGRepresentation(yourImage,0.9))
and if your image is of PNG type then use,
let data = NSData(data: UIImagePNGRepresentation(yourImage))
after that write you file in realm like,
let realm = Realm()
realm.write{
realm.add(data)
}
Hope this helps.
You can't save directly image into Realm, convert it into Data and
the store it.
Convert your image to Data
let data = NSData(data: UIImageJPEGRepresentation(yourImage,0.9))
Convert data to PNG format if any
let imgPNG = UIImage.imageWithData(data)
Convert PNG image to Data
let dataPNGImg = NSData(data: UIImagePNGRepresentation(imgPNG))
Store your data into Realm DB...
let realm = Realm()
realm.write{
realm.add(dataPNGImg)
}
IMPORTANT!!!
It is not a good idea to store an image in the database. It will increase database load and processing time. You can store the image path instead of the image.
Related
When the user selects an item from their photo library, the app saves the UIImage to the app's directory using the following code:
let imageUUID = UUID()
let filename = getDocumentsDirectory().appendingPathComponent("\(imageUUID)")
guard let uiImage = newImage else { return}
if let jpegData = uiImage.jpegData(compressionQuality: 0.8) {
try? jpegData.write(to: filename, options: [.atomicWrite, .completeFileProtection])
}
How can I use the saved image in a view?
Thanks!
First, you should save the UUID somewhere so that you can read the file later. This could be in UserDefaults, a JSON file, CoreData, or whatever, depending on your needs.
Suppose you have the path to the file stored in filePath, you can create an Image like this:
Image(uiImage: UIImage(contentsOfFile: filePath) ?? UIImage())
This will use an empty image as fallback if it failed to read the file.
Following code convert UIImage to Image in SwiftUI:
let uiImage = UIImage(contentsOfFile: path) ?? UIImage() // Access it from your storage
let image = Image(uiImage: uiImage)
There are different UIImage initializer methods available, you can use any one of them to get UIImage instance.
https://developer.apple.com/documentation/swiftui/image
You will like this tutorial of Coredata with SwiftUI: https://www.raywenderlich.com/9335365-core-data-with-swiftui-tutorial-getting-started
When I pick an image from gallery, I convert it to NSData & assign it a variable like so...
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
let data = UIImagePNGRepresentation(image) as NSData?
self.appDelegate.mydata1 = data!
}
Now I'm trying to store self.appDelegate.mydata1 to coredata like so..
guard let appDelegate = ... else {
return
}
let managedContext = ...
let entity = ...
let newProdObj = ...
newProdObj.setValue(self.appDelegate.mydata1, forKey: "imageData") //The attribute imageData in xcdatamodel is of type 'Binary Data'
do {
try managedContext.save()
self.newProductDetails.append(newProdObj as! NewProduct)
} catch let error as NSError {}
Later in another viewcontroller I'm fetching it like so...
guard let appDelegate = ...
let managedContext = ...
let fetchRequest = ...
do {
newProdDetails = try managedContext.fetch(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) as! [NewProduct]
for result in newProdDetails {
print(result)
if let imageData = result.value(forKey: "imageData") as? NSData {
print(imageData)
}}
} catch let error as NSError {}
But when I try to print imageData, the control gets stuck and it goes on continuously printing numbers (which is the data) something like so...<123214 434534 345345 ...etc.
Did go through other posts with the same issue but couldn't get much help from them...
Instead of saving image data in coreData, save your images in document directory and name of those images in UserDefaults/Core Data.
And then you can fetch name from UserDefaults/Core Data and you can get the filPath for those images using this :
// Get path for any filename in document directory
func getFilePathInDocuments(fileName:String, completionHandler:#escaping(String, Bool)->()) {
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let url = NSURL(fileURLWithPath: path)
let fileManager = FileManager.default
let filePath = url.appendingPathComponent(fileName)?.path
if (fileManager.fileExists(atPath: filePath!)) {
completionHandler(filePath!, true)
}else{
completionHandler("File not found!",false)
}
}
If you want to know how to write your images in document directory see this : how to use writeToFile to save image in document directory?
This is not an issue. You are fetching the NSData which is an image, hence its printing the bytes in the image data which are the numbers you are talking about. Also this code is executing in the main thread, hence your app is unresponsive.
As the other answer pointed out save your image in document directory and save the relative path of the imagename in core data. This way you can fetch the name of the imagepath(relative mind you, as full document directory URL can change in app launch), and load the image from the document directory.
Also when saving the image in document directory, please do so in a background queue, using GCD or NSOperation/Operation, as if this image is large it can again block the main thread, as you are operating this in the main thread.
My suggestion is that convert image data to base64 string, and store it to CoreData. Later when you get back image, you can convert it back to NSData. Please refer this for base64 string conversion:
convert base64 decoded NSData to NSString
I am using share extension in my application and I want to show image taken time while I am sharing image with share extension.Is there any way to get the time of image when we use share extension.
The timestamp is available in EXIF data stored with the images. You can get it using UIImagePickerController like this:
https://stackoverflow.com/a/33672661/4042468
On the other hand, if you have image file url, you can use import ImageIO and the below code to get all the properties of the image of which date time is one.
if let imagePath = Bundle.main.path(forResource: "test", ofType: "jpg") {
let imageURL = NSURL(fileURLWithPath: imagePath)
if let imageSource = CGImageSourceCreateWithURL(imageURL, nil) {
if let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [String: AnyObject] {
}
}
}
Note that there is a Exif key in which you can find timestamp.
Following method i ill try, but the image not show in properly and it getting loss
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
img_View.image = info[UIImagePickerControllerOriginalImage] as? UIImage
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let imageData:NSData = UIImagePNGRepresentation(image)!
strImage = imageData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
print(strImage)
dismissViewControllerAnimated(true, completion: nil)
}
here lossy image Corrupted image here
While i decode image into my computer i'm getting full image with slightly blur, But while i'm send my base64 string to service(WEBAPI)(Windows PC), they get only half of the image. can somebody help me how to fix this issue
swift 4
this question is bit old but as its one of the top search result in google i will add the solution for swift4.
You need to define the option of encoding
let image = UIImage(named: "yourimagename")
let imageData = UIImagePNGRepresentation(image)
let base64Str = imageData?.base64EncodedString(options: .lineLength64Characters)
You are probably capping it with the option CharacterLineLength
I just do this: imageData.base64EncodedDataWithOptions(NSDataBase64EncodingOptions())
Swift 3
var sample = UIImage(named: "try-swift-logo")
let imageData:Data = UIImagePNGRepresentation(sample!)!
let base64String = imageData.base64EncodedString()
I just need to upload some images, and I feel like my simple code should work, but for some reason it isn't. I'm getting an error saying that my object exceeds the Parse.com limit of 128kb... And I'm sure it doesn't actually exceed that. Code is here.
override func viewDidLoad() {
super.viewDidLoad()
func addCards(urlString:String) {
var newCard = PFObject(className: "Cards")
let url = NSURL(string: urlString)
let urlRequest = NSURLRequest(URL: url!)
NSURLConnection.sendAsynchronousRequest(urlRequest, queue: NSOperationQueue.mainQueue(), completionHandler: {
response, data, error in
newCard["image"] = data
newCard.save()
})
}
addCards("http://image.com/image")
You shouldn't just be pushing the image data direct into the object. Instead, create a PFFile instance with the data and set that. Then, save the file and the card at the same time (using saveAll).
See the following link from Parse documentations which has a code snippet and also the reason for using PFFile as suggested by Wain:
https://www.parse.com/docs/ios/guide#files
According to Parse documentation: You can easily store images by converting them to NSData and then using PFFile. Suppose you have a UIImage named image that you want to save as a PFFile:
let imageData = UIImagePNGRepresentation(image)
let imageFile = PFFile(name:"image.png", data:imageData)
var userPhoto = PFObject(className:"UserPhoto")
userPhoto["imageName"] = "My trip to Hawaii!"
userPhoto["imageFile"] = imageFile
userPhoto.saveInBackground()