Using Swift 3 for iOS, I am able to use cinemagraphs (animated gifs) that I download through a UIWebView without any problem. I am also trying to get them to work from the iPhone library. However, there is no way that I have found to get the data representation of a GIF stored in the library.
Someone will say that "there is no such thing as an animated gif in the library", but they would be wrong. Go to a web page in Safari, long-tap on an animated gif, and save it to your library. Then send a text message to yourself and copy in that image from the library. You'll see that the animated gif is intact and works perfectly.
My problem is that I need to copy the image from the library programmatically, and I'm not sure how to do it with no specific function built for GIFs. I would like to create the equivalent of UIImagePNGRepresentation or UIImageJPEGRespresentation, except for GIF images. Alternatively, is there a way to get an image from the library as a UIImage, so I don't have to try to convert it to data?
Here's the code I am using for other image formats:
* Edited to be latest version *
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let origImage = info[UIImagePickerControllerOriginalImage] as! UIImage
let refURL : URL = info[UIImagePickerControllerReferenceURL] as! URL
var resizedImage: UIImage!
var ext: String!
ext = refURL.pathExtension
if ext == "GIF" {
resizedImage = origImage
} else {
resizedImage = resizeImage(origImage: origImage, ext: ext)
}
DispatchQueue.main.async(execute: { () -> Void in
self.photoUpdated(newImage: resizedImage)
})
picker.dismiss(animated: true, completion: nil)
}
For GIFs, I tried the following, using the SwiftGif project, which was not successful:
let url = Bundle.main.url(forResource: refURL.absoluteString, withExtension: "GIF")
let data = try! Data(contentsOf: url!)
let advTimeGif = UIImage.gifWithData(data)
let imageView = UIImageView(image: advTimeGif)
newImage = imageView.image
Anyone have any suggestions as to how I might get this to work? Thanks.
Edit:
I figured out a few more pieces of the puzzle. Specifically, I can get the image name and the local path to it.
let refURL : URL = info[UIImagePickerControllerReferenceURL] as! URL
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! as String
let localPath = URL(fileURLWithPath: documentDirectory).appendingPathComponent(imageName)
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
Still can't figure out how to get it from there to Data.
Related
I'm working on image picker with camera and gallery and using following code to get image captured from camera but imageurl and image name is nil.I'm testing on mobile with os version of 11.2.2.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
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!)
if !FileManager.default.fileExists(atPath: localPath!.path) {
do {
try UIImageJPEGRepresentation(image, 1.0)?.write(to: localPath!)
print("file saved")
}catch {
print("error saving file")
}
}
else {
print("file already exists")
}
}
Use UIImagePickerControllerImageURL instead of UIImagePickerControllerReferenceURL like this:
let imageUrl = info[UIImagePickerControllerImageURL] as? NSURL
You will not get any imageUrl or imageName because you are using the camera mode and that image is still not saved in your gallery and hence no image path is created for that camera clicked pic. So they will be nil. You can only get the UIImage object info[UIImagePickerControllerOriginalImage] in this case.
If you pick the image from photo album, then you will get everyhting. You can get the url by info[UIImagePickerControllerImageURL] and you can grab the name using the last path component.
Change your imagePickerController source to photo imagePickerController.sourceType = .photoLibrary and then you will get the urls.
I'm still new in iOS development and I'm creating an app that allows to select some photos and access them quickly.
In CoreData, I store the referenceUrl of the photo instead of the photo itself. I'm able to load photos when starting the app this way.
But, before loading photos, I need to check that they still exist and cannot figure out how to check, using the referenceUrl, if a photo exists or not.
Even using the localPath does not work. It returns false all the time.
If you have any idea how I can proceed, I'll be very grateful.
Thanks.
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 localPathString = String(describing: localPath)
let fileManager = FileManager.default
if fileManager.fileExists(atPath: localPathString){
print ("Photo exists")
} else{
print ("Photo does not exist")
}
}
I found a solution, here it is.
I use imageUrl from my code above like that:
let assets = PHAsset.fetchAssets(withALAssetURLs: [imageUrl as URL], options: nil)
if assets.firstObject != nil {
//Then the image is still there
}
else{
//The image is not present anymore
}
Hope that helps.
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 surely hope I am missing something because I do not understand why this is working the way it does. I have a PNG Image, which has a fully transparent background because I want to overlay it on other images inside a UIImageView.
PNG images included in the XCode project all work fine as they should. The problem is when I select these same PNG images on the fly using UIImagePickerController and then assigning it to the UIImageView, for some really bizarre reason, it is not respecting it as a PNG Image with transparency and instead it adding a white background.
Anyone seen this before and how do I get around this?
* UPDATE #1: I decided to try something that seems to confirm my theory. I decided to email myself the original PNG images I saved to my device and lo and behold, the images came to me as JPG. Seems to me that when you save an image to Photos on iPhone it converts it to JPG, this is rather shocking to me. Hope someone has a way around this. The original images testImage1.png and testImage2.png saved to Photos and then emailed back to myself, returned as IMG_XXXX.jpg and IMG_XXXX.jpg
* UPDATE #2: I kept playing around we this more and found out a few things and in the process was able to answer my own question. (1) My theory in UPDATE #1 is partially correct, but the conversion does not happen when saving the Photo, seems like it is on the fly. Internally photos stores the original image extension (2) I was able to validate this when I realized in my UIImagePickerControllerDelegate that I was using
let imageData = UIImageJPEGRepresentation(image, 1.0)
instead of this
let imageData = UIImagePNGRepresentation(image)
When I used the second line of code, it was recognizing the original transparency properties for the image.
Yes, the call to UIImageJPEGRepresentation will convert the resulting image into a JPEG, which doesn't support transparency.
BTW, if your intent is to get the NSData for the image for other reasons (e.g. uploading to server, emailing, etc.), I would recommend against both UIImageJPEGRepresentation and UIImagePNGRepresentation. They lose meta data, can make the asset larger, if suffer some image degradation if you use quality factor of less than 1, etc.
Instead, I'd recommend going back and get the original asset from the Photos framework. Thus, in Swift 3:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let url = info[UIImagePickerControllerReferenceURL] as? URL {
let result = PHAsset.fetchAssets(withALAssetURLs: [url], options: nil)
if let asset = result.firstObject {
let manager = PHImageManager.default()
manager.requestImageData(for: asset, options: nil) { imageData, dataUTI, orientation, info in
if let fileURL = info!["PHImageFileURLKey"] as? URL {
let filename = fileURL.lastPathComponent
// use filename here
}
// use imageData here
}
}
}
picker.dismiss(animated: true)
}
If you have to support iOS 7, too, you'd use the equivalent ALAssetsLibrary API, but the idea is the same: Get the original asset rather than round-tripping it through a UIImage.
(For Swift 2 rendition, see previous revision of this answer.)
Swift 3 version of answer by #Rob
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let URL = info[UIImagePickerControllerReferenceURL] as? NSURL {
let result = PHAsset.fetchAssets(withALAssetURLs: [URL as URL], options: nil)
if let asset:PHAsset = result.firstObject! as PHAsset {
let manager = PHImageManager.default()
manager.requestImageData(for: asset, options: nil) { imageData, dataUTI, orientation, info in
let fileURL = info!["PHImageFileURLKey"] as? NSURL
let filename = fileURL?.lastPathComponent;
// use imageData here
}
}
}
picker.dismiss(animated: true, completion: nil)
}
An alternative solution uses the PHAssetResourceManager rather than PHImageManager. Using Xcode 10, Swift 4.2.
func imageFromResourceData(phAsset:PHAsset) {
let assetResources = PHAssetResource.assetResources(for: phAsset)
for resource in assetResources {
if resource.type == PHAssetResourceType.photo {
var imageData = Data()
let options = PHAssetResourceRequestOptions()
options.isNetworkAccessAllowed = true
let _ = PHAssetResourceManager.default().requestData(for: resource, options: options, dataReceivedHandler: { (data:Data) in
imageData.append(data)
}, completionHandler: { (error:Error?) in
if error == nil, let picked = UIImage(data: imageData) {
self.handlePickedImage(picked: picked)
}
})
}
}
}
Use it like this:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
dismiss(animated: true)
let mediaType = info[UIImagePickerController.InfoKey.mediaType] as! NSString
if mediaType == kUTTypeImage || mediaType == kUTTypeLivePhoto {
if #available(iOS 11.0, *) {
if let phAsset = info[UIImagePickerController.InfoKey.phAsset] as? PHAsset {
self.imageFromResourceData(phAsset: phAsset)
}
else {
if let picked = (info[UIImagePickerController.InfoKey.originalImage] as? UIImage) {
self.handlePickedImage(picked: picked)
}
}
}
else if let picked = (info[UIImagePickerController.InfoKey.originalImage] as? UIImage) {
self.handlePickedImage(picked: picked)
}
}
}