SceneKit UIImage material is black - ios

I'm loading images from the photo library via UIImagePickerController and with that image I'm setting the material of a SCNPlane:
let imageView = UIImageView(image: image)
imageView.contentMode = .scaleAspectFit
plane.firstMaterial?.diffuse.contents = imageView
With some images, this works fine, no problem at all, the image shows up properly. However, with other images, the texture of the plane shows up as entirely black and Xcode prints "Unsupported IOSurface format: 0x00000000". It seems to be only images that were screenshots causing this, although some screenshot images work just fine.

SceneKit can display both PNGs and JPGs, some PNGs just seem to cause issues. Not sure why or whether it's a bug or not. What you can do that's probably better than converting everything to JPGs (so you can retain transparency) is set your material contents to the image's CGImage:
if let cgImage = image.cgImage {
geometry.firstMaterial?.diffuse.contents = cgImage
}
You can also convert your image to a JPEG via something like this, as SceneKit doesn't seem to have issues with JPGs:
if let jpegData = image.jpegData(compressionQuality: 1.0) {
image = UIImage(data: jpegData)!
}
You will lose transparency doing it this way however.

Related

Scale an Image in ImageView (Scale x,y) - IOS

I usually scale the image of an imageView in Android with the scaleX and scaleY properties.
How can I do the same in IOS? I'm really new with IOS,I'm using swift 3 and I didn't find any analog thing like that.
If you need to scale the image proportionally, the following code might work for you:
if let cgImage = imageView.image?.cgImage, let orientation = imageView.image?.imageOrientation {
imageView.image = UIImage(cgImage: cgImage, scale: newScale, orientation: orientation)
}
However, if you only want to display it with a size different than that of the original image, you should control the size of the image using the size of the UIImageView that presents it. To make sure the image scales correctly with the size of the view, take a look at the UIImageView.contentMode property: https://developer.apple.com/reference/uikit/uiview/1622619-contentmode

Converting PNG to JPG with UIImage giving odd result

My UIImage holds a .png image loaded from disk and is used to set backgroundColor in a background view. That works.
I now want to convert to .JPG to remove transparency / alpha channel. I have tried a few variations, but here's an example:
var orgImage: UIImage? = nil;
var newImage: UIImage? = nil;
orgImage = UIImage(contentsOfFile: "...");
let tmpData: NSData? = UIImageJPEGRepresentation(orgImage!, 1.0);
newImage = UIImage(data: tmpData);
However, when using newImage for the background, the image appears zoomed in. I don't want that. I want the same image, simply converted to JPG.
The code I use for this is:
// works
myView.backgroundColor = UIColor(patternImage: orgImage!)
// appears zoomed/scaled
myView.backgroundColor = UIColor(patternImage: newImage!)
I have tried (for testing purposes) to do a PNG to PNG (over disk or NSData) and saving/loading to/from disk instead. All tests yielding the same result.
Any idea what I am doing wrong? I am testing in iOS simulator.

swift: avfoundation to capture images

i basically have two UIImages. One called previewImage that displays what the AVFoundation Camera displays, and captureImage that displays the image taken using the camera. When I had:
previewLayer!.videoGravity = AVLayerVideoGravityResize
the two images displayed the same formatting, but when I changed it to:
previewLayer!.videoGravity = AVLayerVideoGravityResizeAspectFill
it seems that the previewImage is horizontally flattened. Is there a way to adjust the captureImage UIImage so that it displays what the previewImage displays through the video feed?Part of code that assigns image to imageView UIImage

UIImage slow loading in a UIPageViewController

I have a UIPageViewController showing a UIViewController that contains a UIImageView.
The images displayed in the UIImageView originally come from the camera roll. I copy them in the application's folder. When I display the UIPageViewController, it loads the image for the current page and displays it:
if let image = UIImage(contentsOfFile: imagePath) {
imageView.image = image
}
The problem is that it's really slow. Loading the first image is slow and then swiping is very slow.
I am testing this on my iPhone 5. I installed the app through XCode. Is there a way to make it faster? Should I save a smaller version of the image when I save the images from the camera roll into my application's folder?
You could preload the images like Sergii suggested or load the images a background thread to avoid blocking the main thread.
NSOperationQueue().addOperationWithBlock {
if let image = UIImage(contentsOfFile: imagePath) {
NSOperationQueue.mainQueue().addOperationWithBlock {
self.imageView.image = image
}
}
}
You can load images you'll need before transitioning to UIPageViewController. Also, take a look at some projects for image caches
FastImageCache, SDWebImage, Haneke
Also, you can be interest in this article Avoiding Image Decompression Sickness
To increase the speed of swiping you'd need to move where you are assigning the image to the UIImageView from the main thread to a background thread.
There are a few ways to do this...
Using NSOperationQueue
NSOperationQueue().addOperationWithBlock {
if let image = UIImage(contentsOfFile: imagePath) {
NSOperationQueue.mainQueue().addOperationWithBlock {
self.imageView.image = image
}
}
}
Or you can use GCD and calling dispatch_async()
if let image = UIImage(contentsOfFile: imagePath) {
dispatch_async(dispatch_get_main_queue()) {
imageView.image = image
}
}
With regards to saving an image from the Camera Roll when/if you save it to your apps file system you could try using:
let qualityFloat = 1.0
let imageData = UIImageJPEGRepresentation(imageFromCameraRoll, qualityFloat)
Playing around with qualityFloat (between 0.0 - 1.0) will change the file size of the image which could help you with the loading times.

Slow UICollectionView with asynchronous loading

I have an UICollectionView which loads images of the iPad's memory and displays them in a grid,like Apple's Photos app. The UICollectionViewCell loads thumbnails asynchronously:
func setImage(img:String){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
//load the image in the background
let image = UIImage(contentsOfFile: img)
//when done, assign it to the cell's UIImageView
dispatch_async(dispatch_get_main_queue(), {
if let imageView = self.imageView{
imageView.image = UIImage(contentsOfFile: img)
}
})
})
}
However, while scrolling the view lags as if it is waiting for the images to load, especially with Retina graphics. The cells and images are about 240x180px big. Is there anything wrong with the image loading above or further optimisations need to be made?
UPDATE: Time profiler results
You've already found that you're loading the UIImage again on the main queue; fixing that will help.
UIImage lazy loads its internal image data in most cases. One trick is to call its CGImage property while still on the background queue to force it to actually create its internal image data instead of lazily loading it when the image view is drawn the first time:
func setImage(img:String){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
//load the image in the background
let image = UIImage(contentsOfFile: img)
image.CGImage // <- Force UIImage to not lazy load the data
//when done, assign it to the cell's UIImageView
dispatch_async(dispatch_get_main_queue(), {
if let imageView = self.imageView {
imageView.image = image
}
})
})
}
Note: If you have a lot of images you may end up getting a memory warning fairly quickly doing this. If you do, this probably won't help because the memory warning will typically cause UIImage to clear its internal image data again to free up resources.
On the line
imageView.image = UIImage(contentsOfFile: img)
I was loading the image again on the main thread, not the image loaded asynchronously. Changed to
imageView.image = image
Scrolling is a bit better, but yet choppy. The time profiler shows similar results as before. May the bottleneck be in the UIImageView drawing? It works fine with non-retina thumbnails.
The bottleneck was that some thumbnails were scaled improperly and were a lot bigger than the UIImageView, which caused the longer loading time. I also presume this caused slower drawing since the UIImage had to be downscaled to fit in the UIImageView.
I fixed the thumbnail-generating code and scrolling is smooth again.
P.S. I also fixed the misplaced UIImage(contentsOfFile: img) variable in the initial code, see my other answer.
in Swift:
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
let imagem = UIImage(named :"image")
dispatch_async(dispatch_get_main_queue()) {
cell.IMG_Novidades.image = imagem
}
}
//THIS IS VERY IMPORTANT
cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.mainScreen().scale

Resources