I'm developing an iOS today extension, that can read an image from UIPasteboard and save it on disk. This process fails with large images because iOS extensions can't use much memory. To workaround this issue, I'm checking the size of the image first and try to decide, if the widget can save it or should delegate this task to its host app:
let MAXIMUM_IMAGE_SIZE_BYTES = <SomeMagicNumber>
if let clipboardImage = UIPasteboard.generalPasteboard().image {
let imageSize = CGImageGetHeight(clipboardImage.CGImage) * CGImageGetBytesPerRow(clipboardImage.CGImage)
if imageSize > MAXIMUM_IMAGE_SIZE_BYTES {
// Open host app to save image
}
else {
// Save image directly
}
}
I have the following questions:
Is my size calculation correct? I took it from this thread. I cannot instantiate a JPEG or PNG representation and read its size because of the memory limitations mentioned above.
Can I get rid of that magic number for the maximum image size in bytes? If not, are there any official specifications from Apple that I can use? I cannot test my app on every available iOS model and don't want to risk crashes on older devices.
Thanks a lot for your help!
I'm just starting to look at the memory that a notification service extension is using. I found this presentation. Might be helpful for others.
https://cocoaheads.tv/memory-use-in-extensions-by-conrad-kramer/
What was your solution to this issue?
Related
iOS version: 13.1
iPhone: X
I'm currently using DBAttachmentPickerController to choose from a variety of images, the problem comes when I take a picture directly from the camera and try to upload it to our server. The SDImageWebPCoder.shared.encodedData loads for about 30 seconds more less. The same image in the Android app takes about 2-3 seconds.
Here is the code I use
let attachmentPickerController = DBAttachmentPickerController(finishPicking: { attachmentArray in
self.images = attachmentArray
var currrentImage = UIImage()
self.images[0].loadOriginalImage(completion: { image in
self.userImage.image = image
currrentImage = image!
})
//We transform it to webP
let webpData = SDImageWebPCoder.shared.encodedData(with: currrentImage, format: .webP, options: nil)
self.api.editImageUser(data: webpData!)
}, cancel: nil)
attachmentPickerController.mediaType = DBAttachmentMediaType.image
attachmentPickerController.allowsSelectionFromOtherApps = true
attachmentPickerController.present(on: self)
Should I change the Pod I'm using? Should I just compress it? Or am I doing something wrong?
WebP encoding speed is related slow, it use software encoding and VP8 compression algorithm (complicated), compared to the Hardware accelerated JPEG/PNG encoding. (Apple's SoC).
picture directly from the camera
The original image taken on iPhone camera may be really lark, like 4K resolution. If you don't do some pre-scale and try to encode it, you may consume much more time.
The suggestion can be like this:
Try to use the options like the compressionQuality, the higher cost
more time, but compress more.By default it's 1.0, which is the higest and most time consuming.
Try to pre-scale the original image. For image from Photos Libraray, you can always use the API to control the size. Or, you can use SDWebImage's transform method like - [UIImage sd_resizedImage:].
Do all the encoding in background thread, never block main thread
If all these is not suitable, the better solution, it's to use JPEG and PNG format instead of WebP. Then, on your image server side code, transcoding the JPEG/PNG to WebP. Server side processing is always the best idea for this thing.
If you're intersted the real benchmark or something, compared to JPEG/PNG (Hardware) and WebP (Software). You can try to use my benchmark code demo here, to help you do your decision.
https://github.com/dreampiggy/ModernImageFormatBenchmark
I am working on an app that connects multiple devices using the networking protocol UPnP.
Among others, I can exchange images and they are files stored inside a folder in my project folder.
For sending the images I am given predefined methods.
if let imageRequested = UIImage(named:"logo.png"){
let fileType = "image/png"
let pngRepresentation = [UInt8](UIImagePNGRepresentation(imageRequested)!)
let fileSize = UInt32(pngRepresentation.count)
writeBegin!(aWriterData, fileSize, fileType)
aWriteResource!(aWriterData, pngRepresentation, fileSize)
aWriteEnd!(aWriterData)
}
However, the receiver gets the image with black background when it is transparent. I know It is not a receiver issue because there is an Android version that sends the same images and they are received with transparency.
any ideas why?
UIImageJPEGRepresentation will convert the resulting image into a JPEG, which doesn't support transparency. Are you sure that you use UIImagePNGRepresentation, not UIImageJPEGRepresentation?
If you use UIImagePNGRepresentation - it's strange, it should work fine, could you provide more details?
I'm using a plugin CircleImage from https://github.com/jamesmontemagno/Xamarin.Plugins/tree/master/ImageCircle
I'm using it in a listview. I noticed it's working fine with image from a url but I can't find a way to show an image from embedded resources or files. Could you explain me how do that?
Thank you in advance!
Is the image in your Resources folder on iOS and Android platforms and in the root on Windows Phone?
You probably want to use the following to set the source of a local image:
Source = ImageSource.FromFile("someimage.png")
Or you might even try:
Source = (FileImageSource)ImageSource.FromFile("someimage.png")
Also be careful with upper and lower case file names. I suggest making everything lower case. The iOS simulator will not care about casing (since Macs do not care), but a real iOS device will care.
For other developers I write and describe my solution for that. I have a MVVM model. In this model there is property
ImageSource image
when I fill the data in the model (r in the example) I verify if taking an embedded image or an image from file system
if (images.Count == 0) {
// from file
r.Image = ImageSource.FromFile ("GenericImageFromResource.png");
} else {
// get the file image from file system
//(required an implementation for each platform)
r.Image = ImageFinder.GetImage (images.First().FileName);
}
Using this class I am trying to load a gif url into UIImageView.
The thing is , for some url's it takes 10 seconds to load, others 2 seconds.
I have tried almost anything, but still the process is too slow. 1 second would be good, but i had never succeed getting there.
I have also tried with UIWebview which had its own issues .
Here is the code :
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let fileUrl = NSURL(string:"http://45.media.tumblr.com/6785bae27b8f888fe825f0ade95796a3/tumblr_noenkbeTSw1qjmwryo1_500.gif" )
let gif = UIImage.animatedImageWithAnimatedGIFURL(fileUrl!)
dispatch_async(dispatch_get_main_queue()) {
self.player.image = gif
}
}
The problem with most of the GIF reading tools I have looked at is that they read all the data in at load time and that they allocate memory for all of the decoded frames and hold all that uncompressed data in memory at the same time. This will lead to runtime performance problems and it will crash your app and possibly your device on large/long gifs. On the issue of loading time, there is not all that much you can do since the data does need to be downloaded and read. You are also just assuming that the network cache is going to handle hitting the same GIF over and over without going to the network again, which may or may not work well for you. For a solution that addresses these issues, see this SO Question or you can also take a look at the flipboard solution here.
Im trying to load(and upload) images in my app(by picture path).
This is working in my simulator. everything works there. only when im trying to do this on the iphone itself it won't work and i see just the empty UIImageviews.
The paths are loaded the same as in the simulator. And originate from:
PHImageManager.defaultManager().requestImageDataForAsset(asset, options: nil)
{
imageData,dataUTI,orientation,info in
cell.setString(info["PHImageFileSandboxExtensionTokenKey"] as String,name:dataUTI as String)
}
And the PHImageFileSandboxExtentionTokenKey is split into the data and the url when loading the image.
this results in the simulator as :
/Users/Twizzler/Library/Developer/CoreSimulator/Devices/3E671415-8B83-44DA-870F-19BF2BC11F8F/data/Containers/Data/Application/8872109F-3784-40EB-BEB6-4E9FDABE013D/Documents/1613945_10200645161051698_4122753901212984922_n.jpg
and in the iphone as:
/private/var/mobile/Media/DCIM/102APPLE/IMG_2607.JPG
Im loading the image like this:
let image = UIImage(named: "/private/var/mobile/Media/DCIM/102APPLE/IMG_2607.JPG")
cell.imageView.image = image
in this case i put the image url hardcoded (this is in the final app an array of images)
I don't get an error or stack trace. When placeing a breakpoint im seeing the image information in the same way as the simulator
as suggested by the answer im now trying to load them as follows:
let image = UIImage(contentsOfFile: "/private/var/mobile/Media/DCIM/102APPLE/IMG_2607.JPG")
cell.imageView.image = image
This isn't working and i can't upload the files
That’s not how imageNamed works—as the documentation states, that looks for an image with the given name inside your app’s bundle. Try imageWithContentsOfFile.
Well i fixed it! after some puzzling days im now using this way to access upload and
cell.imageView.image = UIImage(data: array[indexPath.row][0] as NSData)
This shows the image. I can save the NSData in the CoreData and reload the image on this way.
To lighten the load on the system im using this:
cellData.checked = 1
var imageData = UIImageJPEGRepresentation(cell.imageView.image, 1)
self.array.append([imageData,cellData.imageData] )
let myObj : ViewControllerImagePicker = self.parentViewController as ViewControllerImagePicker
let textfield: UILabel = myObj.amountLabel! as UILabel
textfield.text = String(self.array.count )
cell.textLabel.alpha = 1
this code is being called when there is clicked on a cell. by setting the cellData.imageData i can recall the cells (when clicking back to the collection view)
I do not know if the way im doing it is correct or works with more that 10 files because of data usage problems. But in my case with a max of 6 selected pictures it works like a charm
The simulator works completely different than a real device when it comes to files, the app bundle and sandboxing.
For starters the simulator will let you write to and add or change files in your app bundle. iOS running on a real device won't let you do this.
You can't hardcode any paths in your app. Even if it works today or on your device in test mode that doesn't mean it will work on a released version. And even if it does it could stop working on any update. Apple several times has changed where things are stored and the path structure in the phone. And where you are allowed to write.
Make bundle calls to get the path locations of standard folders.
Use the assets library to load images from the photo library, or to save them there.
There are tons of resources and tutorials online on how to do this.