I'm trying to copy a GIF image to the UIPasteboard in swift, at the moment it only copies the static version of the image and seems to convert it to PNG looking at the file extension when I upload it somewhere.
Wondered if anyone had any idea how to achieve this? All other soltions I've found only seem to work when getting NSData from a URL rather than from an image in the bundle
For anyone who ever encounters this problem I managed to find a solution
let url: NSURL = NSBundle.mainBundle().URLForResource("\(self.imageNames[indexPath.row])", withExtension: ".gif")!
let data: NSData = NSData(contentsOfURL: url)!
UIPasteboard.generalPasteboard().setData(data, forPasteboardType: "com.compuserve.gif")
As it turns out you do need to use a URL and extract the NSData of the GIF from that URL.
Here I am getting the URL of the GIF that is in my bundle, searching for it using the name and extension of the image. I am then setting the data in the pasteboard and bingo we have an animated GIF when pasting the result from the pasteboard
It doesn't look like the image property on the pasteboard supports the GIF type.
The associated array of representation types is UIPasteboardTypeListImage, which includes types kUTTypePNG and kUTTypeJPEG.
You could probably do this using the NSData from the GIF though:
import MobileCoreServices
// ...
var image = UIImage(...)
let data = NSData(bytes: &image, length: sizeof(UIImage))
UIPasteboard.generalPasteboard().setData(data, forPasteboardType: kUTTypeGIF as String)) // com.compuserve.gif
Related
I'm currently trying to do something fairly simple... just trying to decode then encode an image in Swift 5.
I've been able to see that my image is indeed correct, but it seems like whenever I try to encode the base64 string in Swift, it won't load at all into my UIImageView.
I've run the base64 decoded string in online converters and the image is correctly formatted.
Did I do anything stupid? Thanks so much for any help you can provide!
The Decode Process (currently seems to be working)
let b64 = UIImagePNGRepresentation(tempImage);
var tempImage2 = b64?.base64EncodedString(options: .endLineWithLineFeed);
if (tempImage2 == nil) {
tempImage2 = "";
}
And the encoding process / loading into the image view:
if let data = Data(base64Encoded: tempImage2!, options: .ignoreUnknownCharacters) {
var useImage = UIImage(data: data);
imageView.image = useImage
print("and now the image view should show it??");
}
On printing the decoded base64, everything seems correct. As soon as I run the encoding, however, nothing is being loaded into my UIImageView - just blankness.
Turns out that the above code works for decoding and encoding base64 in Swift. The issue, however, was with respect to what happened after this code.
Turns out I was messing up some things with the imageView, reusing it as a subview and greatly complicating the process.
Thanks for the help, everyone!
I am getting an Image as Data from server.To show it I am using UIImage?(data:) to show it.For a specific image application is getting crash because of memory pressure. What could be the reason, how to fix it.
if let imgData = Utils.fetchDataFromDocumentDirectory(imageName:"test.jpg"){
attachmentImgView.image = UIImage(data:imgData)
}
How big is the Image? and are you downloading only 1 image or an array?
This might be caused from the size of the image you are trying to download.
My advice if you are trying to show an image, only giving it the url like so:
let url = URL(string: "http://i.imgur.com/w5rkSIj.jpg")
let data = try? Data(contentsOf: url)
if let imageData = data {
let image = UIImage(data: data)
}
even better you can try to use AsyncImageView 3rd party library where you give it the url of the image and it shows it asynchronously without delays in the app.
Hope this helps!
i want to cache image and few data from json to make persistent I know Alamofire Image has it own chade method, but i guess is only while app is alive when app close and open again chache is cleared so i have to download again image. so
if my image are download like so
image.af_setImage(withURL: url)
it posible to save
imageEntity.save(image.image)
not sure to be exactly code but the idea is to save the image downloaded an set to image in CoreData.
and any idea behind the logic of this approach to cjeck if image exist in coreData and show from the if not download and save to coreData
CoreData is not designed to store ImageData or large data (files) but only String, Dates, integer... Just like a normal database.
If you want to save a data you could use AlamofireImageCache and save the image identifier in the CoreData Entity as a string. It's the most easy way to do it.
let imageCache = AutoPurgingImageCache(
memoryCapacity: 100_000_000,
preferredMemoryUsageAfterPurge: 60_000_000
)
imageCache.add(yourImage, withIdentifier: "YourImageIdentifier")
imageEntity.identifier = "YourImageIdentifier"
Then if you want to get your image you can do for example:
let cachedAvatar = imageCache.image(withIdentifier: imageEntity.identifier)
please check AlamofireImage documentation for more information about cache: https://github.com/Alamofire/AlamofireImage
Update
If you want to make your own ImageCache on the hard-drive here you have an example of storing an Image:
func saveImage(image:UIImage){
if let data = UIImagePNGRepresentation(image) {
let documentPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]!
let filename = documentPath.appendingPathComponent("YourImageName")
try? data.write(to: filename)
}
}
func getImage(ForName name:String) -> UIImage?{
let documentPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]!
let filename = documentPath.appendingPathComponent("YourImageName")
return UIImage(contentsOf:URL(fileURLWithPath: filename))
}
Hope it helps !
Pierre
This might be an amateur question, but although I have searched Stack Overflow extensibly, I haven't been able to get an answer for my specific problem.
I was successful in creating a GIF file from an array of images by following a Github example:
func createGIF(with images: [NSImage], name: NSURL, loopCount: Int = 0, frameDelay: Double) {
let destinationURL = name
let destinationGIF = CGImageDestinationCreateWithURL(destinationURL, kUTTypeGIF, images.count, nil)!
// This dictionary controls the delay between frames
// If you don't specify this, CGImage will apply a default delay
let properties = [
(kCGImagePropertyGIFDictionary as String): [(kCGImagePropertyGIFDelayTime as String): frameDelay]
]
for img in images {
// Convert an NSImage to CGImage, fitting within the specified rect
let cgImage = img.CGImageForProposedRect(nil, context: nil, hints: nil)!
// Add the frame to the GIF image
CGImageDestinationAddImage(destinationGIF, cgImage, properties)
}
// Write the GIF file to disk
CGImageDestinationFinalize(destinationGIF)
}
Now, I would like to turn the actual GIF into NSData so I can upload it to Firebase, and be able to retrieve it on another device.
To achieve my goal, I have two options: Either to find how to use the code above to extract the GIF created (which seems to directly be created when creating the file), or to use the images on the function's parameters to create a new GIF but keep it on NSData format.
Does anybody have any ideas on how to do this?
Since nobody went ahead for over six months I will just put the answer from #Sachin Vas' comment here:
You can get the data using NSData(contentsOf: URL)
I have created a share extension for my ios app. When I click on the share option in the photo app my share extension is shown and I click on it and my controller is shown. Everything is working fine up to this. I am uploading video to youtube using the youtube api. I am using this method to create the parameter
GTLUploadParameters *uploadParameters = [GTLUploadParameters uploadParametersWithData:fileData MIMEType:#"video/*"];
Now if the video is small then it is easily converted to NSData using this code
NSData *fileData = [NSData dataWithContentsOfURL:[NSURL URLWithString:videoURL]];
and everything is working and video is uploaded.
But if the video is large then it simply crash and exit from the share extension(I put breakpoint and found this problem. If I remove the fileData conversion then its not crashing.). So what I did was instead of converting it to NSData I used this youtube api method
GTLUploadParameters *uploadParameters = [GTLUploadParameters uploadParametersWithFileURL:[NSURL URLWithString:videoURL] MIMEType:#"video/*"];
Now app is not crashing but I am getting network error. The error is
Error Domain=NSURLErrorDomain Code=-995 "(null)"
little searching found that it is because of NSURLSession and told to use something like this
sessionConfiguration.sharedContainerIdentifier = #“com.me.myapp.containerIdentifier”;
I am using youtube api. I am not sure where to use it OR is there any other way to use youtube api in share extension with large video file.
NOTE: I am using youtube api in my app and its working fine with NSData.
Hope question is clear. I am stuck on it for a day now. Please help.
Thanks in advance.
EDIT 1:
I used this code
NSData *fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:videoURL] options:0 error:&error];
filedata is nil. The error I am getting is
Error Domain=NSCocoaErrorDomain Code=260 "The file “IMG_2187.MOV”
couldn’t be opened because there is no such file."
UserInfo={NSFilePath=/file:/var/mobile/Media/DCIM/102APPLE/IMG_2187.MOV,
Consider this line:
var videoDataURL = info[UIImagePickerControllerMediaURL] as! NSURL!
This does a forced unwrapping of info[UIImagePickerControllerMediaURL] (which is bad, because if it was nil, the app would crash) and that casts it as an implicitly unwrapped optional NSURL!. That doesn't make sense. Just do a conditional unwrapping (and unwrap to a NSURL, not a NSURL!):
if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL { ... }
The next line calls filePathURL:
var videoFileURL = videoDataURL.filePathURL
If you wanted a file URL, you already have one, so no conversion is needed, but instead just use videoDataURL. If you really wanted a path, you'd use path method:
let videoPath = videoDataURL.path
Frankly, Apple is trying to shift us away from using string paths, so just use the original videoDataURL and avoid the use of both path and filePathURL.
You are using dataWithContentsOfMappedFile:
var video = NSData.dataWithContentsOfMappedFile("\(videoDataURL)")
If you really wanted to use dataWithContentsOfMappedFile, the proper Swift syntax is:
let video = NSData(contentsOfMappedFile: videoPath!)
But dataWithContentsOfMappedFile deprecated, so you should instead use:
let video = try NSData(contentsOfFile: videoPath!, options: .DataReadingMappedIfSafe)
Or, bypassing that videoPath altogether, you could:
let video3 = try NSData(contentsOfURL: videoDataURL, options: .DataReadingMappedIfSafe)
Obviously, those try renditions should be done within a do block with a catch block.
By the way, as you'll see in all of my above examples, one should use let where possible.
Quite frankly, I would advise against loading it into a NSData at all. Just copy it with NSFileManager, which is a more efficient use of memory. If the video is long, it could be quite large, and you should avoid loading the whole thing into memory at any given point in time.
So you could:
if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL {
do {
// build your destination URL however you want
//
// let tempFolder = NSURL(fileURLWithPath: NSTemporaryDirectory())
// let destinationURL = tempFolder.URLByAppendingPathComponent("test.mov")
// or
let documents = try NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
let destinationURL = documents.URLByAppendingPathComponent("test.mov")
// but just copy from the video URL to the destination URL
try NSFileManager.defaultManager().copyItemAtURL(videoDataURL, toURL: destinationURL)
} catch {
print(error)
}
}
If you're uploading this to a web service, you'd then use a NSURLSessionUploadTask, using file or stream options. The construction of this request is a separate question, but hopefully you get the idea: With large assets like photos or, especially, videos, don't instantiate a NSData with the asset if you can possibly avoid it.
Please try this if your file exist in your phone instead of [NSURL URLWithString:videoURL].
NSData *fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:videoURL]];