Achieving desired resolution of UIImage issue - ios

I am trying to create a custom annotationView.
I have a base.png image with the following parameters 60x100 pixels with 72pixels/inch resolution.
In my custom Annotation object I set annotationView's image with the following method:
-(MKAnnotationView *)annotationView
{
MKAnnotationView *annotationView = [[MKAnnotationView alloc] initWithAnnotation:self reuseIdentifier:#"MyAnnotation"];
annotationView.image = [UIImage imageNamed:#"base.png"];
return annotationView;
}
Everything is working as desired except for resolution of the custom annotationView. It looks like this:
Although, original image looks like this:
As you can see it looks over sized with pixels clearly noticeable. I don't have any front-end experience to speak of and I don't understand much about resolution and how UIImage sets it's image under the hood by calling imageNamed method.
What is the issue here? Do I need a higher resolution image to begin with or different size image or something else??? How does iOS translate the original .png image (it's size, resolution etc.) to the image that is actually displayed on the device?

Have a look at Apple's high resolution resources webpage.
Essentially, there are two parts to this.
Are you using #2x images for retina? You should have a double resolution copy of your image (in your case, 120 x 200) named base#2x.png.
You UIImageView will automatically take the size of its image property unless you specify a frame.
It looks like your pin and your coffee cup are two different images. I'd start by making that base#2x.png image at double resolution. When you write your code, you don't actually specify the #2x version of your image. You code as you did, and iOS will look for the Retina resolution copy and magically load it instead of the standard resolution. You'll need both images, like so:
Make sure to add both of them to your project. In code, you'd write [UIImage imageNamed:#"base.png"] and on retina devices, you'll get the sharper version of the picture.
As for the offset of the coffee on the pin, you need to play with the frame (or constraints, if you're using auto layout) of that view a bit.

Related

Xcode #2x image suffix not showing as Retina in iOS

I am having difficulties with retina images.
The screenshot below shows the UICollectionView with a UIImageView contained within each UICollectionViewCell.
Within the app I have a large image 512x512 pixels called travel.png.
The green circle shows what is displayed on the app when I name this file: travel.png. The blue circle shows what I see when I update the image name to be travel#2x.png (i.e. retina naming).
I was hoping due to the large size of the image (512x512) that simply adding the #2x suffix would be enough to convert it to twice the definition (i.e. retina) but as you can see from the two screenshots, both version images show as non-retina.
How can I update the image so that it will display in retina?
travel.png:
travel#2x.png:
* Updated *
Following request in comments below:
I load this image by calling the following function:
// Note - when this method is called: contentMode is set to .scaleAspectFit & imageName is "travel"
public func setImageName(imageName: String, contentMode: ContentMode) {
self.contentMode = contentMode
if let image = UIImage(named: imageName) {
self.image = image
}
}
Here is how the image appears in Xcode before the app renders it (as you can see it is high enough definition):
The reason why you see the low quality image is anti-aliasing. When you provide images bigger then an actual frame of UIImageView (scaleAspectFit mode) the system will automatically downscale them. During scaling some anti-aliasing effects can be added at curve shapes. To avoid the effect you should provide the exact image size you want to display on the screen.
To detect if UIImageView autoscale the image you can switch on Debug->Color Misaligned Images at Simulator menu:
Now all scaled images will highlight at simulator with yellow color. Each highlighted image may have anti-aliasing artifacts and affect CPU usage for scaling algorithms:
To resolve the issue you should use exact sizes. So the system will use them directly without any additional calculations. For example, if your button have 80x80px size you should add three images to assert catalog with following sizes and dpi: 80x80px (72 dpi), 160x160px (144 dpi) and 240x240px (216 dpi):
Now the image will be drawn at the screen without downscaling with much better visual quality:
If your intention is to have just one image for all the sizes, I would suggest it having under Assets.xcassets. It is easy to create the folder structures and manage media assets here.
Steps
On clicking + icon, you will displayed a list of actions. Choose to create a New folder.
Choosing the new folder that is created, click on the + icon again and click on New Image Set.
Choose the imageset. And choose the attributes inspector.
Select Single Scale, under Scales.
Drag and drop the image.
Rename the image name and folder names as you wish.
Now you can use this image using the image name for all the screen sizes.
TL;DR;
Change the view layer's minificationFilter to .trilinear
imageView.layer.minificationFilter = .trilinear
as illustrated by the device screenshot below
As Anton's answer correctly pointed out, the aliasing effet you observe is caused by the large difference in dimensions between the source image and the image view it's displayed in. Adding the #2x suffix won't change anything if you do not change the dimensions of the source image itself.
That said there is an easy way to improve the situation without resizing the original image: CALayer offers some control over the method used by the graphics back-end to resize images : minificationFilter and magnificationFilter. The first one is relevant in your case since the image size is being reduced. The default value is CALayerContentsFilter.linear, just switch to .trilinear for a much better result (more info on those wikipedia pages). This will require more GPU power (thus battery), especially if you apply it on many images.
You should really consider resizing the images before displaying them, either statically or at run-time (and maybe cache the resized versions). In addition to the bad visual quality, using such large images in quantities in your UI will decrease performance and waste lots of memory, leading to potentially other issues.
I have fixed, #DarshanKunjadiya issue.
Make sure (if you are already using assets):
Make sure images are not un-assigned
Now use images in storyboard or code without extensions. (e.g. "image" NOT "image.png")
If you are not using images from assets, move them to assets.
Demo Projects
Hope it helps.
Let me know of your feedback.
I think images without the #2x and #3x are rendered for devices with low resolutions (like the iphone 4 an 3G).
The solution I think is to always use the .xcassets file or to add the #2x or #3X in the names of your images.
In iOS, content is placed on the screen based on the iOS coordinate system. for displaying an image on a standard resolution system having 1:1 pixel density we should supply image at #1x resolution. for higher resolution displays the pixel density will be a scale factor of 2.0, 3.0 which refers in the iOS system as #2x and #3x respectively. That is high-resolution displays demands images with higher density.
For example, if you want to display an image of size 128x128 in standard resolution. You have to supply the #2x and #3x size image of the same. ie., 256x256 at #2x version and 384x384 image at #3x version.
In the following screenshot, I have supplied an image of size 256x256 for 2x version to display a 128x128 pixel image in iPhone 6s. iPhone 6s render images at #2x size. Using the three version of images such as 1x, 2x and 3x with asset catalogue will resolve your issues. So the iPhone will automatically render the correct sized image automatically with the screen resolution.

Why is UIImage rotated after being initialised from asssets?

I have an image in my xcassets folder which is in PDF format and I init and assign to an UIImageView this way:
imageView.image = UIImage(named: "myImage", in: Bundle.current, compatibleWith: nil)?.withRenderingMode(.alwaysTemplate)
When I run the app, this image is displayed rotated/flip, but I'm not rotating it in code. The image file looks ok. What could it be happening there?
I had the same issue which is completely ununderstandable. But it only happened to a tiny rectangular vector image oriented vertically, placed in xcassets. I tried a few things like changing all the settings xcasset gives us. Alas, the only thing that worked for me was to increase the image size. Then iOS stopped changing the orientation.
It really looks like a bug from xcode trying to compress/optimize images and mistakenly rotate images...
Anyway, try to change the image size (scale it up - or insert margins). Also, try to export to another media type.

Using a high-res image for a custom swipe mechanism in a UITableViewCell

I have a UITableViewController where the UITableViewCell is dynamic and inheriting from a custom UITableViewCell class. I have introduced a swipe gesture on the cell to favourite the cell, but I'm having a bit of issues with the image that shows when the cell is swiped.
This is what it currently looks like:
On anything but the iPhone 5s, it looks pixelated and terrible. The image is currently a square image of size 50x50.
If I upped the size to 200x200, I get:
This looks less pixelated, but also at the same time looks absolutely terrible.
In my cellForRow, this is the code I am using to apply the image: [self.rightUtilityButton sw_addUtilityButtonWithColor:
[UIColor orangeColor] icon:[UIImage imageNamed:#"Star.png"]];
I am using the SWTableViewCell open source code (https://github.com/CEWendel/SWTableViewCell) as my reference for this, but I can't find in the code where this size is actually set on the UITableViewCell custom image and I can't get in touch with the author.
Issues
I basically want to use the 200x200 image, but in the frame size of the 50x50 image. How can I force this? Perhaps I can put the 200x200 image into another UIImageView with a clear background? If that is the way, I'm not sure how to achieve it. Any guidance would be appreciated.
You should include multiple resolutions for the same image and use the #nx naming scheme.
For example: You have set the imageView as 50 x 50 px in the interface builder or code.
For the above imageView, you should provide the following images:
star.png - 50x50 px (For screens with scale 1 resolution like in iPhone 3GS, iPad 2)
star#2x.png - 100x100 px (For screens with scale 2 resolution like in iPhone 4s - iPhone 6)
star#3x.png - 150x150 px (For screens with scale 3 resolution like in iPhone 6S)
Then, simply set the image for the imageView as:
[imageView setImage:#"star"]; //Dont use the extension
At this point, the app will automatically pick up the best image based on the current screen and show the right image.

obj-c images resizing automatically...?

I just started learning obj-c the other day and i'm putting together a crappy game as practice. I have an IMG as a main character to the game and every time this character hits certain obstacles, i wanted the size of the image to change (decrease or increase depending on the circumstance).
I used photoshop the change the size of the images to the appropriate sizes but for some reason, when i run the game, the images change when i want them too, but they are way smaller than the size i set them to in photoshop......
any ideas?
i don't think its necessary to post my code for something as simple as this, right? its just a simple "if" statement followed by the instance and the UIimage named for the image name...
I assume you display the image in an UIImageView? Or do you use SpriteKit? If you use an UIImageView the image is actually automatically scaled to the size of the UIImageView.
Therefore you would just change the size of the UIImageView (you can of course also change the image inside the UIImageView.
If you are using SpriteKit, you have to remember, that your are probably testing on a 'retina' device and for this reason the image's width and height is divided by 2 (the real resolution of the current iPhone 5/5s is 1136x640 and not 568x320 !

iOS UIImageView - Top of Image Chopped Off?

I'm new to iOS Development, I'm using a UIImageView to display an image. I've made a 320x480 and a 640x960 image called "red.png" and "red#2x.png".
No matter how I scale or align the UIImageView, the image always chops off half way at the top.
Is there something I'm meant to do to combat this, as I thought those resolutions were correct?
The UIImageView is sized at 320x568 to fill the storyboard.
Thanks :)
My comment above is hard to read, and it's probably an answer:
myImageView.contentMode = UIViewContentModeScaleAspectFit;
Try changing to image name as follows:
self.colourImage.image = [UIImage imageNamed: #"red.png"];
You should not directly specify '#2x' in image names.
It is automatically used if a device supports retina display.
That is why you need to create 2 sets of images; one for non-retina and one for retina (using #2x) and the OS selects the correct one for you.

Resources