When I load an image from a file path into a UIImage, the size ends up increasing. Am I doing something wrong?
let imageData = try! Data(contentsOf: imageUrl)
print("Original file size : \(imageData.count.readableSize())") // Displays 2.34 MB
let image = UIImage(contentsOfFile: imageUrl.path)
print("UIImage file size : \(image.pngData()!.readableSize())") // Displays 5.71 MB
extension Int
{
func readableSize() -> String
{
let units = ["bytes", "KB", "MB", "GB", "TB"]
var count = 0
var readableFileSize = self
while readableFileSize > 1024
{
readableFileSize = readableFileSize/1024
count += 1
}
return String(format: "%.2f", readableFileSize) + " " + units[count]
}
}
In the above code sample, assume that the image loaded is of png format.
I am looking for a way to circumvent this and get the actual data that was initially loaded
Edit: I'm trying to load an image into UIImage, resize it and then save it back into the file system. I'm looking for a way to achieve this without increasing the size of the file because of what I have described. I'm open to even an alternative to resize without loading the image into UIImage.
Maybe it does not answer your question but I want to share some useful information.
Code:
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileName = "2.png"
let fileURL = documentsDirectory.appendingPathComponent(fileName)
let imageData = try! Data(contentsOf: fileURL)
print("Original file size : \(imageData.count/1024)")
let image = UIImage(contentsOfFile: fileURL.path)
print("UIImage file size : \(image!.pngData()!.count/1024)")
Debug log as you mentioned in your question(size is different):
Original file size : 6083
UIImage file size : 14982
Conclusion:
After lot's of research and frustration, I realized that the size of
an image in document directory (14982) and size image from data is
identical (14982) that's mean when we are getting data from URL automatically compress it by the system.
Try this:
let remoteImageData = try? Data(contentsOf: URL(string: "https://upload.wikimedia.org/wikipedia/de/b/bb/Png-logo.png")!)
print(remoteImageData)
if let imageFileUrl = Bundle.main.url(forResource: "Png-logo", withExtension: "png") {
let imageFileData = try? Data(contentsOf: imageFileUrl)
print(imageFileData)
}
Prints:
Optional(811068 bytes)
Optional(811068 bytes)
Related
i have a bunch of images in my App's Documents Directory. i want to load one of them in an UIImage that i have in my view. this is what i do:
myImage.image = UIImage(named: "image.jpg") // the file exist but this returns nil
I also tried to init the image using:
myImage.image = UIImage(contentsOfFile: imagePath) //this also doesn't work but the path i got starts (at least in the sim) with file://
Anyone can suggest something? I'm kinda a noob in iOS programming.
Thanks
EDIT:
imagePath comes from:
func getImgPath(name: String) -> String
{
let documentsDirectory = self.getDocumentsDirectory()
let fullpath = documentsDirectory.appendingPathComponent(name)
return fullpath.absoluteString
}
This might help
let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
if let dirPath = paths.first
{
let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("name.png")
let image = UIImage(contentsOfFile: imageURL.path)
// Do whatever you want with the image
}
Try adding your images under Assets.xcassets. Then you'll be able to reference your image by:
UIImage(named: 'yourImageName')
You can conveniently add images with various size settings.
You can get the path of the image as fowllows:
let imagePath = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("image.jpg")
If this doesn't work, check if your file name is correct.
I understand that if you are downloading images from internet means, you need to convert the URL to UIImage
if let url = URL(string: "your url") {
let data = try? Data(contentsOf: url)
if let imageData = data {
if let image = UIImage(data: imageData) {
imageView.image = image
}
}
}
If i understand your question correct, this will be the answer.
I've an image (captureImage) which is taken by camera and resized. I use UIImageJPEGRepresentation to compress image, after the compression, image's size is increased. Is it normal behaviour or I'm doing compression/resizing in wrong way?
if let image = captureImage {
print(image.size) // (700, 700)
let compressedImageData = UIImageJPEGRepresentation(image, 0.3)!
let compressedImage = UIImage(data: compressedImageData)!
print(compressedImage.size) // (3024, 3024)
}
Yes this code is for image compression
let compressedImageData = UIImageJPEGRepresentation(image, 0.3)!
One way for getting the file size is by saving into document directory.
For example -
let filePath = fileURL
var fileSize : UInt64
do {
//return [FileAttributeKey : Any]
let attr = try FileManager.default.attributesOfItem(atPath: filePath.path)
fileSize = attr[FileAttributeKey.size] as! UInt64
//if you convert to NSDictionary, you can get file size old way as well.
let dict = attr as NSDictionary
fileSize = dict.fileSize()
print(fileSize)
} catch {
print("Error: \(error)")
}
I am sending some images via socket and I would like to create text file with information about the images to send over the network as well. I right now I can send the images no problem by creating a variable for the image data like so
let imageData = UIImageJPEGRepresentation(someUIImage, 1.0)
How do create a variable with the data of the text file?
let textData = someTextFileAsData.....
Is this what you want?
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
// Get the URL to the file. Below is an example
let fileURL = documentsDirectory.appendingPathComponent("test").appendingPathExtension("txt") // Replace "test" with your fileName and "txt" with your fileExtension
var text = ""
do {
text = try String(contentsOf: fileURL)
} catch {
fatalError("error: \(error.localizedDescription)")
}
Expanding a bit on Anthonin C.'s answer:
Each file in iOS is identified by a URL (just like a webpage, but this is a URL referring to the iOS filesystem). There are a few places in the system where you can save files, most of which you can get the URLs for by reading
FileManager.default.urls(for: SearchPathDirectory, in: SearchPathDomainMask)
(FileManager class reference).
For instance, to save in the user's personal "documents" directory, you would do:
let fileName = "socketLog.txt"
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
//build full path to file
let path = dir.appendingPathComponent(fileName)
do {
try text.write(to: path, atomically: false, encoding: String.Encoding.utf8)
}
catch {/* error handling here */}
}
where text would be the string data you want to save.
You should use write(to: URL, atomically: Bool) or write(toFile: String, atomically: Bool) of NSData method to write your data in a file.
In your case it would be :
let imageData = UIImageJPEGRepresentation(someUIImage, 1.0)
imageData.writeToFile("imageData.txt", atomically:true)
You can then restore it like that :
var imageData = NSData(contentsOfFile: "imageData.txt")
And to get back the image from data :
let image : UIImage = UIImage(data: imageData)
In my app I am storing an image in local storage and I am saving the path of that image in my Realm database. And now i have problems with load this image from that path?
Thats how I save path to database:
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory,nsUserDomainMask, true)
let dirPath = paths.first
let imageURL1 = URL(fileURLWithPath: dirPath!).appendingPathComponent("refuge1.jpg")
let med1 = Meditation()
med1.name = "Refuge"
med1.count = 0
med1.targetAmount = 111111
med1.malasStep = 108
med1.imagePath = imageURL1.path
med1.id = 1
It's straightforward that am trying to get an image from this meditation.imagePath path. I double-checked the path, image is there still am not able to set the image using this path, is there is something that am missing?
In debug mode I see this:
Meditation {
name = Refuge;
count = 0;
targetAmount = 111111;
malasStep = 108;
imagePath = /Users/macbook/Library/Developer/CoreSimulator/Devices/2E25309F-D6A9-41C3-9EF4-67203142172C/data/Containers/Data/Application/F198640B-3C72-4F9C-8173-FB00D3ABEC15/Documents/refuge1.jpg;
id = 1;}
but my variable image still nil in debug mode
// Configure the cell...
cell.nameOfMeditation.text = meditation.name
cell.countOfMeditation.text = String(meditation.count)
let image = UIImage(contentsOfFile: meditation.imagePath)
cell.imageForMeditation.image = image
return cell
I see name of meditation and sound, bot no omg.
It's not advised to save the absolute file path of a file in an iOS app (ie, everything including /Users/macbook/Library/Developer/...), in Realm or anywhere else.
For security reasons, iOS devices rename the UUID folder name between launches. This means that while the folder path was valid at the time it was saved, it won't be at a later date.
Instead, it's recommended to save just the relative path of the file (eg, its location in relation to just the Documents folder. In this case, it would be just /refuge1.jpg) and to then dynamically build the absolute path by requesting the Documents directory path as you need it.
Try this:
// Use these convenience methods if you do a lot of saving and loading
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 saveRefugeOne(image: UIImage) {
// Create a file name, and then save the path in your documents with that name
let imageFileName:String = "refuge1.jpg"
let imagePath = fileInDocumentsDirectory(imageFileName!)
saveImage(image, path: imagePath)
}
func loadRefugeOne() -> UIImage? {
// Get the image back
let imageName:String = "refuge1.jpg" // Or whatever name you saved
let imagePath = fileInDocumentsDirectory(imageName)
if let loadedImage = self.loadImageFromPath(imagePath) {
return loadedImage
} else {
print("Couldn't Load: \(imageName)")
return nil
}
}
// This will be your method to save image
func saveImage(_ image: UIImage, path: String ) {
//If you want PNG use this let pngImageData = UIImagePNGRepresentation(image)
// But since you mentioned JPEG:
if let jpgData = UIImageJPEGRepresentation(image, 1.0) {
try? jpgData.write(to: URL(fileURLWithPath: path), options: [.atomic])
}
}
// This will load image from saved path. Make sure to store the path
// somewhere. This makes it easier to save images locally. You can
// save the image in the documents directory, and then just save the
// path in CoreData or something similar.
func loadImageFromPath(_ path: String) -> UIImage? {
let image = UIImage(contentsOfFile: path)
if image == nil {
print("couldn't find image at path: \(path)")
}
return image
}
Hopefully this will help. It's the method I always use, and it works like a charm when I follow my own steps right ;-)
I am developing some tumblr client. And i want to download all photos in dashboard and save them to documentDirectory. Some of them is jpg some are gif. I have successfully download jpg images with this code:
do {
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentsURL.appendingPathComponent(fname)
if let pngImageData = UIImagePNGRepresentation(myImage!) {
try pngImageData.write(to: fileURL, options: .atomic)
print(fname + " - saved")
}
} catch {print(fname + " - not saved") }
myImage is the image which is downloaded from URL. This code is work for jpg images but not good for gifs.
And lastly i read these files with this:
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let filePath = documentsURL.appendingPathComponent(fname).path
if FileManager.default.fileExists(atPath: filePath) {
return UIImage(contentsOfFile: filePath)!
}
It's work for jpg but not for gifs. when i try this writing/reading codes on gifs images, i got just image not animation.
Can you show me the way pls with an example will be awesome.
Thank you.
I personally used this tinnie tool for GIFs. Simply add the iOSDevCenters+GIF.swift file directly to your project and use it as shown below
1. Online URL
let imageURL = UIImage.gifImageWithURL(gifURL)
let yourImageView = UIImageView(image: imageURL)
2. Local Filename
let imageName = UIImage.gifImageWithName(imageName)
let yourImageView = UIImageView(image: imageName)
3. Using Data
let imageData = NSData(contentsOf: Bundle.main.url(forResource: "name", withExtension: ".gif"))
let imageData = UIImage.gifImageWithData(imageData)
let yourImageView = UIImageView(image: imageData)
Actually your first code is not working correctly either.
What you are receiving is the image. You do not need or want to translate it into some other kind of image (UIImagePNGRepresentation). Just save the data. Later, read the data directly into a UIImage.
I think there is no problem with downloading and you are just trying to present it as a png; instead try to present this saved data with this library, for example
Try this:
#import AssetsLibrary
let lib = ALAssetsLibrary()
let data = NSData(contentsOfURL: getCurrentGIFURL)
lib.writeImageDataToSavedPhotosAlbum(data, metadata: nil) { (url, err) in
}