i'm a baby of xcode developer, and i really need a help. Below is one of my json data, that i have print in output, for the text i already got display into my screen, but now i'm trying to get the image from the server, and i don't know how to do it.
JSON :
"MoviePhotoL" : "\/Data\/UploadFile\/cnymv-01_1.jpg",
"MoviePhotoP" : "\/Data\/UploadFile\/cnymv-02_1.jpg"
XCODE:
let userImage = iP["MoviePhotoP"] as? String
cell.imageView.image = userImage (??????)
i know that String cannot be converted into UIImage, and i already try to convert it to NSData and convert the NSData to UIImage(data), but still not get the picture :'(.... can somebody please help me?? i really need some help
Those paths seem relative to another source.
You need to generate or get an absolute URL that will let you access the image.
Right now you have a simple string and that's all, you can't convert this to data or image.
You need a string that you can put in a browser and load an image.
Once you're able to do that, you can load the image in your app.
Example:
func getImage(from string: String) -> UIImage? {
//2. Get valid URL
guard let url = URL(string: string)
else {
print("Unable to create URL")
return nil
}
var image: UIImage? = nil
do {
//3. Get valid data
let data = try Data(contentsOf: url, options: [])
//4. Make image
image = UIImage(data: data)
}
catch {
print(error.localizedDescription)
}
return image
}
//1. Get valid string
let string = "https://images.freeimages.com/images/large-previews/f2c/effi-1-1366221.jpg"
if let image = getImage(from: string) {
//5. Apply image
cell.imageView.image = image
}
NOTE: Data(contentsOf:options:) is synchronous and can reduce performance. The larger the image, the longer it will lock it's thread.
Generally you would do such intensive tasks in a background thread and update UI on the main thread, but... to keep this answer simple, I chose not to show that.
Related
I have an UIImageView in which I draw handwritten text, using UIGraphicsBeginImageContext to create the bitmap image.
I pass this image to an OCR func:
func ocrText(onImage: UIImage?) {
let request = VNRecognizeTextRequest { request, error in
guard let observations = request.results as? [VNRecognizedTextObservation] else {
fatalError("Received invalid observations") }
print("observations", observations.count) // count is 0
for observation in observations {
if observation.topCandidates(1).isEmpty {
continue
}
}
} // end of request
request.recognitionLanguages = ["fr"]
let requests = [request]
DispatchQueue.global(qos: .userInitiated).async {
let ocrGroup = DispatchGroup()
guard let img = onImage?.cgImage else { return }
crGroup.enter()
let handler = VNImageRequestHandler(cgImage: img, options: [:])
try? handler.perform(requests)
ocrGroup.leave()
crGroup.wait()
}
}
Problem is that observations is an empty array.
But, If I save UIImage to the photo album:
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
and read back image from the album with imagePicker and pass this image to ocrText, it works.
So it seems there is a format change to the image (or metadata?) when saved to album and that VNRecognizer needs those data.
Is there a way to change directly the original bitmap image format, without going through the storage on photo album ?
Or am I missing something in the use of VNRecognizeTextRequest ?
I finally found a way to get it.
I save the image to a file as jpeg and read the file back.
This didn't work with png, but works with jpeg.
I have an image stored inside an AppGroup, but I'm unable to show the image and I'm not sure why.
I have this inside my view:
Image(uiImage: getImageFromDir(imageName: name)!)
.resizable()
I get the image using the following function:
func getImageFromDir(imageName: String) -> UIImage? {
let appGroupPath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myId")!
let imagePath = appGroupPath.appendingPathComponent(imageName)
do {
let imageData = try Data(contentsOf: imagePath)
return UIImage(data: imageData)
} catch {
print("Error loading image : \(error)")
}
return nil
}
This runs fine and the catch block is never hit, but the image still isn't visible. My initial thought was that I had an invalid path, but this doesn't seem the case since I can load the image as expected in React Native using the path.
There's also nothing wrong with my styles since a different image loaded from Assets.xcassets works fine.
Assuming the file is really existed at specified location (you can verify generated URL for that) try with security scoped resource wrapper, like below
func getImageFromDir(imageName: String) -> UIImage? {
let appGroupPath = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.myId")!
let imagePath = appGroupPath.appendingPathComponent(imageName)
do {
if imagePath.startAccessingSecurityScopedResource() { // << this !!
defer {
imagePath.stopAccessingSecurityScopedResource() // << and this !!
}
let imageData = try Data(contentsOf: imagePath)
return UIImage(data: imageData)
}
} catch {
print("Error loading image : \(error)")
}
return nil
}
While my solution is working, it is NOT a valid answer to why my images aren't showing and I would still like to know why, if anyone knows who comes across this post in the future.
To solve this, instead of using an absolute path to the image, I used a base64 string to use as the data. The image now succesfully shows.
I am trying to save images in a directory. Images are correctly saved in the right place, but when I inspect these with the path in the finder, all the images are damaged and unsable.
damaged images
Below the static method:
static func writeImageFile(with data: Data, issue: Issue, page: Int, isThumbnail: Bool) throws -> URL {
let url = MediaFileManager.issueImagesDirectoryURL(issue: issue).ensuringDirectoryExists()
let imageURL = url.appendingPathComponent(imageName(for: page, isThumbnail: isThumbnail))
try data.write(to: imageURL)
return url
}
And the call in the class:
DispatchQueue.main.async {
guard let data = result.data else {
self.downloadDidFail(for: result.page)
return
}
do {
let writeImageFile = try MediaFileManager.writeImageFile(with: data, issue: self.issue, page: result.page, isThumbnail: false)
let writeThumbFile = try MediaFileManager.writeImageFile(with: data, issue: self.issue, page: result.page, isThumbnail: true)
print(writeImageFile)
print(writeThumbFile)
} catch let error as NSError {
print(error.localizedDescription)
}
}
I will assume, since you don't quite specify this, that you have a bunch of UIImage objects.
And I also noticed that you want your images to be saved as JPEG, which is no trouble at all, don't worry.
I would go with something like this:
if let image = UIImage(named: "example.png") {
if let data = UIImageJPEGRepresentation(image, 1.0) {
let filename = getDocumentsDirectory().appendingPathComponent("copy.png")
try? data.write(to: filename)
}
}
Where the func getDocumentsDirectory() is the following:
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
You might wonder why I used 1.0 for the second parameter in UIImageJPEGRepresentation, well that's the JPEG quality mapped between 0.0 and 1.0 (it's a float).
If you have any details that I am not aware of, please reply and I will try to help accordingly.
Hope it helps you, cheers!
Source: link
Have you tried to load the image to a UIImageView to see if the images are being properly downloaded? imageView.image = UIImage(data: data).
But I also detect that you're saving Data instead of the image, in order to make sure that you're saving an image I would try the following
static func writeImageFile(with data: Data, issue: Issue, page: Int, isThumbnail: Bool) throws -> URL {
let url = MediaFileManager.issueImagesDirectoryURL(issue: issue).ensuringDirectoryExists()
let imageURL = url.appendingPathComponent(imageName(for: page, isThumbnail: isThumbnail))
let image = UIImage(data: data)
let imgData = UIImageJPEGRepresentation(image, 1)
try imgData.write(to: imageURL)
return url
}
Yes, it might have unnecessary steps, worth trying, this way we're making sure that it's saved as Jpeg. But again, I would check if the images are being properly downloaded first.
I've been trying to save a single picture to an entity containing a single property titled "prof" and configured as a Binary Data type.
I go through the hoops to select a picture from UIImagePickerViewController, then I call up my method that handles saving the picture in Core Data in the desired NSData format.
My issue stems from loading the picture, in my loadImage method the entity for the image is not nil, meaning it does exist. However, I get nil when I try to parse the fetched NSData to a UIImage format to recreate the picture and then be able to use it.
Now i am using Swift 3 and Xcode 8, so far all the troubleshooting questions on here have the solution of casting the NSData to UImage like so:
let image : UIImage = UIImage(data: imageData)
however, xcode gives me a compiler error when I do this, and instead forces me to cast it as:
let image : UIImage = UIImage(data: (imageData as Data?)!)
which is where i get the nil that's throwing up my flow in the air... i've tried saving the data in many different ways, but still nothing.
if anyone could go through my following methods, see if i might be doing something wrong in the saving part, or the formating of NSData on the fetch method... anything would help.
My configuration:
-the prof property has "Allow external storage" set to true
-my persistent store is seeded blank at the app installation, meaning all the needed properties are already set up when the app is launched for the first time, but obviously set to nil until changed or modified by my various data flows.
-There is no other picture entity in my data model, this is the only one.
func saveProfilePicture(_ pic: UIImage){
let picData = UIImagePNGRepresentation(pic)
let request: NSFetchRequest<UsePics> = UsePics.fetchRequest()
do {
let records = try coreDataManager.managedObjectContext.fetch(request) as [UsePics]
let first = (records.first)
first?.setValue(picData, forKey: "prof")
try context.save()
} catch let err {
print(err)
}
}
func getProfilePicture() -> UIImage? {
let request: NSFetchRequest<UsePics> = UsePics.fetchRequest()
var image : UIImage?
do {
let records = try coreDataManager.managedObjectContext.fetch(request) as [UsePics]
let first = (records.first?.prof) as NSData
if let parsedImage : UIImage = UIImage(data: (first as Data?)!) as? UIImage {
image = parsedImage
}
} catch let err {
print(err)
}
return image
}
EDIT
The solution was found by noticing that in Swift 3, the UIImage class adheres to the Transformable protocol. Swapping my property type for the image from Binary Data to Transformable actually made it possible to save the UIImage as UIImage directly into Core Data without parsing it to another data type.
func saveProfilePicture(_ image: UIImage){
let request: NSFetchRequest<UsePics> = UsePics.fetchRequest()
do {
let records = try coreDataManager.managedObjectContext.fetch(request) as [UsePics]
let first = (records.first)
first?.prof = image
print(first)
coreDataManager.saveData()
} catch let err {
print(err)
}
}
func loadProfilePicture() -> UIImage? {
var image : UIImage?
let request: NSFetchRequest<UsePics> = UsePics.fetchRequest()
do {
let records = try coreDataManager.managedObjectContext.fetch(request) as [UsePics]
let first = records.first
if let img = first?.prof {
image = img as? UIImage
} else {
print("no image")
}
} catch let err {
print(err)
}
return image
}
I'm using KingFisher https://github.com/onevcat/Kingfisher
library so i can cache the images and if there is anyone familiar with it i want some hints.
So i have the following code
let myCache = ImageCache(name: recipesClass.objectId!)
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
let optionInfo: KingfisherOptionsInfo = [
.DownloadPriority(0.5),
.CallbackDispatchQueue(queue),
.Transition(ImageTransition.Fade(1)),
.TargetCache(myCache)
]
if let imageFile = recipesClass[RECIPES_COVER] as? PFFile {
let URL = NSURL(string: imageFile.url!)!
cell.coverImage.kf_setImageWithURL(URL, placeholderImage: nil,
optionsInfo: optionInfo,
progressBlock: { receivedSize, totalSize in
print("\(indexPath.row + 1): \(receivedSize)/\(totalSize)")
},
completionHandler: { image, error, cacheType, imageURL in
print("\(indexPath.row + 1): Finished")
})
} else {
cell.coverImage.image = UIImage(named:"logo")
}
When i first enter the View it loads normally the images with this good anymation. But i also have a refresh button which makes a query to Parse and it checks if there is any new Recipe and then it reloads the data from the collection view and it prints "Finished"
Does this means that it downloads the images again? Or it loads them from Cache??
I'm asking because it appends the images in a different way inside the cells rather than the first time that it loads.
Any idea?
P.S. what i want to do is that in each cell i want to cache the image with the object ID of each recipe so when the cell loads and it has the image cached with this unique object id, to load it from cache and not to download it.
try this code:
var imageView:UIImageView!
let mCa = ImageCache(name: "my_cache")
let imagePath = getImagePath("image url")
imageView.kf_setImageWithURL(NSURL(string: imagePath)!,placeholderImage: UIImage(named: "DefaultImageName"),optionsInfo: [.TargetCache(mCa)])