How to pick GIF image from UIImagepicker in swift 4? - swift

In my project trying to import GIF from UIImage picker. GIF image picked from gallery will certain actions like play and stop. Right now I can able to select GIF mage from gallery but result shows as image not gif image.
Can anyone help me out of this.

Try this it will help you.
Step1: Create a global variable
var IMG:String?
Step2: put this function in your code.
func getFileName(info: [String : Any]) -> String {
if let assetPath = info[UIImagePickerControllerReferenceURL] as? URL {
let result = PHAsset.fetchAssets(withALAssetURLs: [assetPath], options: nil)
let asset = result.firstObject
let fileName = asset?.value(forKey: "filename")
let fileUrl = URL(string: fileName as! String)
if let name = fileUrl?.deletingPathExtension().lastPathComponent {
print(name)
//let assetPath = info[UIImagePickerControllerReferenceURL] as! NSURL
if (assetPath.absoluteString.hasSuffix("JPG")) {
sonu = "JPG"
print("JPG")
}
else if (assetPath.absoluteString.hasSuffix("PNG")) {
sonu = "PNG"
print("PNG")
}
else if (assetPath.absoluteString.hasSuffix("GIF")) {
sonu = "GIF"
print("GIF")
}
else {
sonu = "Unknown"
print("Unknown")
}
return name
}
}
return ""
}
Step3: Set this code in your ImagePickerController
if let image = info[UIImagePickerControllerEditedImage] as? UIImage
{
imageview.image = image
let IMG = getFileName(info: info)
print(IMG)
if IMG == "JPG"
{
imageDataForApi = UIImagePNGRepresentation(image)
}
else if IMG == "GIF"
{
imageDataForApi = UIImageJPEGRepresentation(image, 0)
}
}
self.dismiss(animated: true) { () -> Void in
}

Related

Swift. How to extract the individual sub images from an HEIC image

I need to be able to load an heic image and extract and output all of the sub images as pngs similar to how preview does it. For example, if you open a dynamic heic wallpaper in preview, it shows all the images in the sidebar with their names:
How do you do this? I've tried to use NSImage like below. But that only outputs a single image:
let image = NSImage(byReferencing: url)
image.writePNG(toURL: newUrl)
You need to load the HEIC data, get its CGImageSource and its count. Then create a loop from 0 to count-1 and get each image at the corresponding index. You can create an array with those CGImages in memory or write them to disk (preferred). Note that this will take a while to be executed because of the size of the HEIC file 186MB. Each image extracted will be from 19MB to 28MB.
func extractHeicImages(from url: URL) throws {
let data = try Data(contentsOf: url)
let location = url.deletingLastPathComponent()
let pathExtension = url.pathExtension
let fileName = url.deletingPathExtension().lastPathComponent
let destinationFolder = location.appendingPathComponent(fileName)
guard pathExtension == "heic", let imageSource = CGImageSourceCreateWithData(data as CFData, nil) else { return }
let count = CGImageSourceGetCount(imageSource)
try FileManager.default.createDirectory(at: destinationFolder, withIntermediateDirectories: false, attributes: nil)
for index in 0..<count {
try autoreleasepool {
if let cgImage = CGImageSourceCreateImageAtIndex(imageSource, index, nil) {
let number = String(format: "#%05d", index)
let destinationURL = destinationFolder
.appendingPathComponent(fileName+number)
.appendingPathExtension(pathExtension)
try NSImage(cgImage: cgImage, size: .init(width: cgImage.width, height: cgImage.height))
.heic?
.write(to: destinationURL)
print("saved image " + number)
}
}
}
}
You will need these helpers as well to extract the cgimate from your image and also to get a HEIC data representation from them:
extension NSImage {
var heic: Data? { heic() }
var cgImage: CGImage? {
var rect = NSRect(origin: .zero, size: size)
return cgImage(forProposedRect: &rect, context: .current, hints: nil)
}
func heic(compressionQuality: CGFloat = 1) -> Data? {
guard
let mutableData = CFDataCreateMutable(nil, 0),
let destination = CGImageDestinationCreateWithData(mutableData, "public.heic" as CFString, 1, nil),
let cgImage = cgImage
else { return nil }
CGImageDestinationAddImage(destination, cgImage, [kCGImageDestinationLossyCompressionQuality: compressionQuality] as CFDictionary)
guard CGImageDestinationFinalize(destination) else { return nil }
return mutableData as Data
}
}
Playground testing. This assumes the "Catalina.heic" is located at your desktop.
let catalinaURL = FileManager.default.urls(for: .desktopDirectory, in: .userDomainMask).first!.appendingPathComponent("Catalina.heic")
do {
try extractHeicImages(from: catalinaURL)
} catch {
print(error)
}
Each subimage is represented by a NSBitmapImageRep. Loop the image reps, convert to png and save:
let imageReps = image.representations
for imageIndex in 0..<imageReps.count {
if let imageRep = imageReps[imageIndex] as? NSBitmapImageRep {
if let data = imageRep.representation(using: .png, properties: [:]) {
do {
let url = folderURL.appendingPathComponent("image \(imageIndex).png", isDirectory: false)
try data.write(to: url, options:[])
} catch {
print("Unexpected error: \(error).")
}
}
}
}
The conversion to png takes some time. Running the conversions in parallel is faster but I'm not sure if it's save:
DispatchQueue.concurrentPerform(iterations: imageReps.count) { iteration in
if let imageRep = imageReps[iteration] as? NSBitmapImageRep {
if let data = imageRep.representation(using: .png, properties: [:]) {
do {
let url = folderURL.appendingPathComponent("image \(iteration).png", isDirectory: false)
try data.write(to: url, options:[])
} catch {
print("Unexpected error: \(error).")
}
}
}
}

Save (override) my jpg file with editing EXIF data

Im open and edit EXIF (or TIFF...) data in my jpg file.
Please help me save (override) my jpg file with editing data.
Working with this simple code:
let fileURL = URL(fileURLWithPath: "/Users/test/Pictures/IMG_2808.jpg")
if let imageSource = CGImageSourceCreateWithURL(fileURL as CFURL, nil) {
var imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as Dictionary?
let exifDict = imageProperties?[kCGImagePropertyExifDictionary]
if let UserComment = exifDict?[kCGImagePropertyExifUserComment] ?? nil {
print("kCGImagePropertyExifUserComment: \(UserComment)")
}
else {
exifDict!.setValue("My comment...", forKey: kCGImagePropertyExifUserComment as String)
imageProperties![kCGImagePropertyExifDictionary] = exifDict
// What I should do in the next step for update and override my jpg file on disk?
// Maybe this is not nice way for this realisation? Please help
//
}
}
After some test Im found a solution:
let fileURL = URL(fileURLWithPath: "/Users/test/Pictures/IMG_2808.jpg")
if let imageSource = CGImageSourceCreateWithURL(fileURL as CFURL, nil) {
var imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as Dictionary?
let exifDict = imageProperties?[kCGImagePropertyExifDictionary]
if let UserComment = exifDict?[kCGImagePropertyExifUserComment] ?? nil {
print("kCGImagePropertyExifUserComment: \(UserComment)")
}
else {
exifDict!.setValue("My comment...", forKey: kCGImagePropertyExifUserComment as String)
imageProperties![kCGImagePropertyExifDictionary] = exifDict
if let imageDestination = CGImageDestinationCreateWithURL(fileURL as CFURL, kUTTypeJPEG, 1, nil) {
CGImageDestinationAddImageFromSource(imageDestination, imageSource, 0, imageProperties as CFDictionary?)
CGImageDestinationFinalize(imageDestination)
}
}
}
I don't know if this solution is true but it works!
Please comment if you know more perfected way

How do I update an MKPointAnnotation image after downloading the right image?

I have a bunch of annotations on a map, which all have a custom photos. Some of the photos may not be downloaded to the application yet from Firebase, so if they do not the image available, it defaults to a white circle image and initiates a download. When the download completes, it does not set the new image. How can I go about this?
Heres some code:
func generateAnnotations() {
for photo in photos {
let annotation = DetailPhotoPointAnnotation()
let latitude = photo.latitude
let longitude = photo.longitude
annotation.coordinate.latitude = latitude
annotation.coordinate.longitude = longitude
if photo.image != nil {
annotation.image = photo.image
} else {
annotation.image = #imageLiteral(resourceName: "whiteCircle")
let path = getDocumentsDirectory().appendingPathComponent(photo.uid)
if let image = UIImage(contentsOfFile: path) {
annotation.image = image
} else {
let ref = FIRStorage.storage().reference(forURL: photo.imageUrl)
ref.data(withMaxSize: 5*1024*1024, completion: { (data, error) in
if error != nil {
print(error!)
} else {
if let imageData = data {
if let image = UIImage(data: imageData) {
photo.assignImage(image: image)
annotation.image = image
}
}
}
})
}
}
self.coordinates.append(CLLocationCoordinate2DMake(latitude, longitude))
self.mapView.addAnnotation(annotation)
}
generateOverlay()
}
As you can see, it first looks to if the photo object contains an image. If it doesn't, it looks in the documents directory for that image. If its not there, it will finally download it. Any suggestions?
You need to do something like this. Go to main thread. And then update
DispatchQueue.main.async(execute: {
imageView.image = image
})
In my solution it works.
Hope this helps.

OSX - Loading an image and saving it as a smaller png file using Swift

I am looking for a way to to upload an image file, resize it (in order to reduce the total file size), and then save it as a png. I think there must be a fairly straightforward way of doing this, but hours of searching around have yielded no effective results. I have been able to achieve the desired file size by exporting the image as a compressed JPEG, but I need to preserve transparency. Here is the code I used to get the JPEG:
func chooseImage () {
var image = NSImage()
//choose image from hard disk
let panel = NSOpenPanel()
panel.allowsMultipleSelection = false
panel.canChooseFiles = true
panel.canChooseDirectories = false
panel.runModal()
panel.allowedFileTypes = ["png", "jpeg", "jpg"]
let chosenFile = panel.URL
//convert to NSData and send to Jpeg function
if chosenFile != nil {
image = NSImage(contentsOfURL: chosenFile!)!
let imageData = image.TIFFRepresentation
self.saveAsJpeg(imageData!, compression: 0.5)
}
}
func saveAsJpeg (image:NSData, compression:NSNumber) {
// make imagerep and define properties
let imgRep = NSBitmapImageRep(data: image)
let props = NSDictionary.init(object: compression, forKey: NSImageCompressionFactor)
let pingy = imgRep?.representationUsingType(NSBitmapImageFileType.NSJPEGFileType, properties: props as! [String : AnyObject])
//save to disk
let documentURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
let folderURL = documentURL.URLByAppendingPathComponent("KKNightlife Data")
let g = GetUniqueID()
let fileName = g.getUniqueID() + ".jpeg"
do {
try NSFileManager.defaultManager().createDirectoryAtURL(folderURL, withIntermediateDirectories: false, attributes: nil)
} catch {
print("cannot create directory - folder Exists?")
}
let url = folderURL.URLByAppendingPathComponent(fileName)
if let pid = pingy {
pid.writeToURL(url, atomically: false)
} else {
print("error saving image")
}
}
I attempted to use the following code to scale the image in order to create a smaller .png file, but no matter what values I enter for the size, the resulting file is the same size (both in terms of height/width and overall file size):
func chooseImage (size:String) {
let panel = NSOpenPanel()
panel.allowsMultipleSelection = false
panel.canChooseFiles = true
panel.canChooseDirectories = false
panel.runModal()
panel.allowedFileTypes = ["png", "jpeg", "jpg"]
let chosenFile = panel.URL
if chosenFile != nil {
let image = NSImage(contentsOfURL: chosenFile!)
self.scaleImage(image!)
}
}
func scaleImage (image:NSImage) {
//create resized image
let newSize = NSSize(width: 10, height: 10)
var imageRect:CGRect = CGRectMake(0, 0, image.size.width, image.size.height)
let imageRef = image.CGImageForProposedRect(&imageRect, context: nil, hints: nil)
let resizedImage = NSImage(CGImage: imageRef!, size: newSize)
let imageData = resizedImage.TIFFRepresentation
//make imagerep
let imgRep = NSBitmapImageRep(data: imageData!)
let pingy = imgRep?.representationUsingType(NSBitmapImageFileType.NSPNGFileType, properties: [:])
//save to disk
let documentURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
let g = GetUniqueID()
let fileName = g.getUniqueID() + ".png"
let folderURL = documentURL.URLByAppendingPathComponent("KKNightlife Data")
do {
try NSFileManager.defaultManager().createDirectoryAtURL(folderURL, withIntermediateDirectories: false, attributes: nil)
} catch {
print("cannot create directory - folder Exists?")
}
let url = folderURL.URLByAppendingPathComponent(fileName)
if let pid = pingy {
pid.writeToURL(url, atomically: false)
print("image is at \(documentURL)")
} else {
print("error saving image")
}
}
Any suggestions would be greatly appreciated.
I was finally able to do this using the extensions found here:
https://gist.github.com/raphaelhanneken/cb924aa280f4b9dbb480
This is how I ended up calling them in case anyone encounters similar problems:
func chooseImage (size:String) {
let panel = NSOpenPanel()
panel.allowsMultipleSelection = false
panel.canChooseFiles = true
panel.canChooseDirectories = false
panel.runModal()
panel.allowedFileTypes = ["png", "jpeg", "jpg"]
let chosenFile = panel.URL
if chosenFile != nil {
let image = NSImage(contentsOfURL: chosenFile!)
self.scaleImageUsingExtensions(image!)
}
}
func scaleImageUsingExtensions (image:NSImage){
let size: NSSize = NSMakeSize(10, 10)
let resizedImage = image.resizeWhileMaintainingAspectRatioToSize(size)
let documentURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
let g = GetUniqueID()
let fileName = g.getUniqueID() + ".png"
let folderURL = documentURL.URLByAppendingPathComponent("KKNightlife Data")
do {
try NSFileManager.defaultManager().createDirectoryAtURL(folderURL, withIntermediateDirectories: false, attributes: nil)
} catch {
print("cannot create directory - folder Exists?")
}
let url = folderURL.URLByAppendingPathComponent(fileName)
do {
try resizedImage?.savePNGRepresentationToURL(url)
}
catch {
print("error saving file")
}
}

Load user image

I use this code to load users usernames when a user search for another user
var user: PFUser? {
didSet {
userNameLabel.text = user?.username
}
}
How can I do the same thing but for profile pictures?
Here is what you can do.
case 1
If you need to download the image and display then -
Create a property that holds url for the image.
Asynchronously download image and display
So code would look this this
var pictureURL: NSURL?
var user: PFUser? {
didSet {
userNameLabel.text = user?.username
pictureURL = user?.pictureURL
displayPicture()
}
}
private func displayPicture() {
// Async download pic and display
}
case 2
If you have the image locally then just display -
var user: PFUser? {
didSet {
userNameLabel.text = user?.username
userImage.image = UIImage(named: "Picturename")
}
}
You can not save your image file with UIImage format on Parse.com. You can store the file with PFFile and you have to convert your image to PFFile for saving and getting the image.
You can save your Image with this function;
private func saveLogo() {
let yourLogoImageFile = UIImage(named: "YourLogoFileName")
if let imageData = UIImageJPEGRepresentation(yourLogoImageFile!, 0.1) {
// You got the PFFile you can use this for save.
let imagePFFile = PFFile(name: "logo.png", data: imageData)
logo = imagePFFile // Send this PFFile to your variable or just save.
// Saving...
imagePFFile?.saveInBackground()
}
}
After that you can get your logo PFFile from Parse and you have to convert it to UIImage with this function;
private func getLogo() {
if let image = yourLogoVariable {
image.getDataInBackgroundWithBlock() {
(let imageData, error) in
if error == nil {
if let logoImageData = imageData {
if let logoImage = UIImage(data: logoImageData) {
// logoImage is the UIImage you can use this for your UIImageView.
}
}
}
}
}
}