I am using this ImagePicker to select multiple images from library or camera. Once user is done selecting images, I am storing those images in to an array. I want display images to the Frame according to number of images selected. for example, if more than 5 images selected the result will be something like this from the selected Images.
Imagepicker is new for me. I don't know how to achieve this. I've read many posts but not getting clear idea how to implement in my case.
I am testing it on Demo project given,
func doneButtonDidPress(_ imagePicker: ImagePickerController, images: [UIImage]) {
imagePicker.dismiss(animated: true, completion: nil)
imageArray = images
createCollage()
}
func createCollage() {
}
If I use UIimageView to display/load images it shows massive memory usage.
Can please anyone help me here with any of these issue? Any help will be much appreciated!!
look at the doc and code of ImagePicker, they are recommend to use
public var imageAssets: [UIImage] {
return AssetManager.resolveAssets(imagePicker.stack.assets)
}
by looking for AssetManager.resolveAssets implementation we will se some config size
open static func resolveAsset(_ asset: PHAsset, size: CGSize = CGSize(width: 720, height: 1280), completion: #escaping (_ image: UIImage?) -> Void) {
set size depends from your imageView size
--- UPD
or use the property
open var preferredImageSize: CGSize?
Tested the same code on real device and it is working fine. In my case, testing on simulator was causing massive memory usage issue here.
Related
I'm using SwiftGif framework to animate a GIF I made, problem is I need to know which image is currently displaying.
The extension is using UIImage.animatedImage(with images: [UIImage], duration: TimeInterval) -> UIImage? to display the animated image.
Here is how I load my gif :
spikes.loadGif(name: "Trap")
and here is how I get the image I'd like to compare it to :
spikes.image.images[2]
I know those are weak explanations but I can't find any more relevant informations, however I can give you more informations if it can help you.
If you know any other solution that could involve me using another framework I would take it too.
If someone ever needs an answer as I did, I found a way to do it.
Load GIF with the extension's loadGif() method
Since the images that are composing the GIF are now stored in spikes.image.images, I store those images in another var
Set spikes.image = nil to cancel animations generated from loadGif() method
Make a timer that keeps changing the actual image of the view
Here's how it looks like :
spikes.loadGif(name: "Trap", completion: { _ in
self.spikesImages = self.spikes.image?.images
self.spikes.image = nil
self.spikes.image = self.spikesImages.first?.img
self.animateSpikes()
})
func animateSpikes() {
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { _ in
if let currentImage = self.spikesImages.first {
self.spikes.image = currentImage
self.spikesImages.append(currentImage)
self.spikesImages.remove(at: 0)
}
})
}
I'm pretty sure this is not the best way to do it but it works
I need to record the screen to make a ten-seconds video when someone is broadcasting like the record function of "live.me" app. I can't use replaykit because I need to support iOS8.
when user click the record button,I start to screen shot twenty-four times in a second.
public func screenShot() -> UIImage? {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, true, 0)
self.drawViewHierarchyInRect(self.bounds, afterScreenUpdates: true)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img
}
then I use AVasset to put all pictures to video
This way, there are too many disadvantages,such as high cpu low performance of mobile phones can't use it。
Is this way wrong or the way works I need to optimize?
I uploaded some photos to Firebase Storage following the sample project on github.
Before using Firebase Storage, I was saving my photos to some other website. And when I download photos from those image URLs that I saved before on the other website, nothing is wrong and memory usage is reasonable. But when I paste images' URL links to corresponding childs on Firebase Database and then download from those URLs, I seem to have a terrible memory issue. For every ~200kb image, memory usage goes ~10mb up. Since I don't have this problem downloading images from other URLs, I believe this is a firebase specific issue. Does anyone else encounter the same memory issue? Any suggestions/help?
NOTE: I saved the URLs of the images to the firebase realtime database. I download URL links from there and give them to my photo collection view cells. Here is the code I wrote for my photo collection view cells:
class PhotosCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imageView: UIImageView!
private var downloadTask: FIRStorageDownloadTask!
var imageURL: String! {
didSet {
downloadTask = FIRStorage.storage().referenceForURL(imageURL).dataWithMaxSize(1*1024*1024) { (imageData, error) in
guard error == nil else { print(error); return }
if let imageData = imageData {
self.imageView.image = UIImage(data: imageData)
}
// imageView.kf_showIndicatorWhenLoading = true
// imageView.kf_setImageWithURL(NSURL(string: imageURL)!)
}
}
}
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil
// imageView.kf_cancelDownloadTask()
downloadTask.cancel()
}
}
The only thing I want to solve is that I want to be able to download the images that I saved to Firebase Storage from their URLs that I also save in the real time database. One important fact is that kingfisher downloads images from URLs without having any memory issue. The problem just occurs when those image URLs are from firebase storage.
NOTE: I also get memory issue when download those images from Firebase Storage function. I know to some extent it's normal for memory usage to go up but my images in Firebase Storage are just about 200KB.
While you are only downloading 200kb blobs of data, it costs much more memory than that to display that as an image. While the "clarity" of the image may be compressed, it will still remain the same dimensions. An image usually requires 4 bytes per pixel - one for each of red, blue, green, and alpha. So a 2000x1000 pixel image requires ~8mb of memory, which is close to what you are describing. I would first ask you if you are caching the images, and if you are, instead cache the data. What will probably help you more though is to resize the image that you are displaying, unless you need it at full size. Use something like:
extension UIImage {
/// Returns a image that fills in newSize
func resizedImage(newSize: CGSize) -> UIImage {
// Guard newSize is different
guard self.size != newSize else { return self }
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
}
And do something like half of the dimensions of the original image, which will make it cost 4x less memory. Make sure to modify the original image and not to create a new image. Hope this helps.
I faced with the same problem, and one thing which helped me it is SDWebImage. It can load images from refs and direct url.
My ViewController looks like: Camera View on top and Photo Gallery on the bottom, like in Instagram.
When I try to load user's image library and display it on UICollectionView, app crashes with the Memory Warning. How can I prevent it and improve my function?
My function:
func getImagesFromLibrary(from: Int = 0, to: Int = 5, completion: (loaded: Bool) -> Void) {
if images.count > 0 {
for i in from..<to {
let asset: PHAsset = self.images[i] as! PHAsset
let imageFetchOptions = PHImageRequestOptions()
self.imageManager.requestImageForAsset(asset, targetSize: CGSize(width: 75, height: 75), contentMode: .AspectFit, options: imageFetchOptions, resultHandler: { (image: UIImage?, info: [NSObject : AnyObject]?) in
if (image != nil) {
if let img = image {
self.croppedImagesArray[i] = img
self.imagesCollectionView.reloadData()
}
}
})
}
completion(loaded: true)
} else {
print("Images Empty")
}
}
and I call it via:
if AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo) == AVAuthorizationStatus.Authorized {
print("GRANTED")
self.getImagesFromLibrary { (loaded) in
if loaded {
print("Images Count: \(self.images.count)")
if self.images.count > 5 {
print("Second part")
self.getImagesFromLibrary(5, to: self.images.count / 2, completion: { (loaded) in
if loaded {
self.getImagesFromLibrary(self.images.count / 2, to: self.images.count, completion: { (loaded) in })
}
})
}
}
}
}
So, now I have in my gallery 300 images. It's a lot and that's why my app crashes on loading process.
How can I solve it? Any solutions?
Apparently, you simply hold too much images in memory, and thus get a memory warning.
When you get a memory warning, iOS gives you the opportunity to release data that are easily be recreated. If you don’t do so, your app can be terminated anytime.
So the question is if you really need to hold all those images in memory.
If so, you have a real problem, and iOS might not be the right platform for your app.
If not, e.g. if you want to show only part of the loaded images at a time, you should use placeholder images that are shown when a image that should be shown is not in memory, download the image, and replace the placeholder by the real image as soon as it has been downloaded.
One way to store images so that you won’t get a memory warning is to use a NSCache <Docs>, which is something like a NSMutableDictionary, in which you can store images, but images which have not been used long will be cleared automatically when memory becomes tight. So if you have to display an image, you could first display the placeholder, and then try to load it from the cache, and if this fails, to download it.
Of course, there are also frameworks that do the caching automatically for you, e.g. AFNetworking <Github>.
By default requestImageForAsset: is asynchronous. The code you have written will immediately fire off requests for all 300 images, and as you see run out of memory. So the code where you load 5 images, and then the first half, and then the second half is all just being run at once.
I would recommend in UICollection cellForRowAtIndexPath: you call self.imageManager.requestImageForAsset(self.images[indexPath.item] .... and set the UImageView for that cell in the result handler block. No need to preload all 300 images, the user may never even scroll to see them all. And someone else may have 3000 images or more.
Also in your result handler your calling collectionView reloadData every time an image is fetched, even reloading when the image that was fetched isn't even currently displayed. Use reloadItemsAtIndexPath: to just load the cell associated with the image.
Hey so I'm trying to have a button that when pressed allows the user to choose 2-5 pictures from their photo library then have whatever photo chosen be set onto a uiimageview? I was looking online and couldn't find anything related to how to do it in swift?
Thanks
I worked out using this : https://github.com/zhangao0086/DKImagePickerController .
Getting selected image's thumbnail images:
let pickerController = DKImagePickerController()
pickerController.sourceType = .Photo
pickerController.didCancelled = { () in
println("didCancelled")
}
pickerController.didSelectedAssets = { [unowned self] (assets: [DKAsset]) in
println("didSelectedAssets")
println(assets)
for(var i = 0; i<(assets.count); i++){
print(assets[i].url)
self.PickedArray .addObject(assets[i].thumbnailImage!)
}
self.performSegueWithIdentifier("SegueToPhotoLibraryView", sender: self)
Getting selected image's urls :
assets[i].url instead of assets[i].thumbnailImage
Hope it helps!
Currently iOS does not provide an image picker out of the box that lets you pick multiple images from the photo library. UIImagePickerController only lets you select one image.
But there are several image picker implementations available that let you pick multiple images. You can find a whole bunch at cocoacontrols.com as #ytbryan already mentioned.
I am currently not aware of any multiple image picker implemented in Swift. If someone finds one, please edit and post the link.