3

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.png filename used

travel@2x.png: travel@2x.png filename used * 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):

enter image description here

Bhavesh Nayi
  • 3,626
  • 1
  • 27
  • 42
Charlie S
  • 4,366
  • 6
  • 59
  • 97
  • 1
    How do you load the image for display? Also could you please post the image itself somewhere? If the image looks jagged like that, renaming it is not going to magically smooth it out. – matt Apr 25 '19 at 16:46
  • @matt - Thanks for the request. I have added the method in the custom ImageView class that sets the image & provided how the image looks in xcode (fairly high definition). – Charlie S Apr 26 '19 at 04:36
  • And what are the parameters when you call `setImageName`? – matt Apr 26 '19 at 05:04
  • @matt - when the setImageName method is called: contentMode is set to .scaleAspectFit & imageName is set to "travel". I have updated the comment in the code above to include this. – Charlie S Apr 26 '19 at 07:50
  • 1
    Maybe consider creating a small example code which shows this problem. It would be easier then to check what’s wrong – manishg Apr 29 '19 at 00:38
  • @CharlieSeligman make sure your 2x Image is not un-assigned in xCode. – Muhammad Waqas Apr 29 '19 at 05:51
  • @manishg - I've added the image setting code just above the last image. Is that enought detail? – Charlie S Apr 29 '19 at 08:26
  • @iOS_Developer - by un-assigned do you mean where it shows in red font? – Charlie S Apr 29 '19 at 08:26
  • Are you storing your images in an XCAssets file? – Houcem Eddine Soued Apr 29 '19 at 09:02
  • @CharlieSeligman No, I mean if in Assets file – Muhammad Waqas Apr 29 '19 at 10:04
  • Can you attach the image plz and do you tried to show it without `collectionView` ? – Houcem Eddine Soued Apr 29 '19 at 10:18
  • i think image size is large then required ? can you reduce size and check it again ? – Abu Ul Hassan Apr 29 '19 at 10:49
  • also your seeing this on real device ? Or simulator if you are seeing it on simulator it is recommended to see it on device once ... – Abu Ul Hassan Apr 29 '19 at 10:50
  • @manishg Have created demo for it. Please see it in answer section. – Darshan Kunjadiya Apr 29 '19 at 10:59
  • 1. That is the size (mb) of the image file? 2. What are the dimensions of image view which is supposed to show this image? – Swapnil Luktuke Apr 30 '19 at 12:44
  • 1
    If image view's dimensions are much smaller than image size (which is what it looks like from the screenshots), have you tried to using smaller dimension images? Sometimes, images get pixelated even while being 'downsized'. So its sufficient to use an image resource which looks really crisp and non pixelated at correct 2x dimension i.e. for 80x80 uiimageview, the 2x resolution image's dimension only need to be around 160x160 px. – Swapnil Luktuke Apr 30 '19 at 12:57
  • 1
    “Really keen to work out how to add HD to my existing app.” But not keen enough to make a demo project that shows what you’re doing. – matt May 01 '19 at 17:01

6 Answers6

6

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:

Color Misaligned Images

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:

Scaled images will highlight

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):

Assets catalog

Now the image will be drawn at the screen without downscaling with much better visual quality:

The result

Anton Vlasov
  • 1,372
  • 1
  • 10
  • 18
2

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

  1. On clicking + icon, you will displayed a list of actions. Choose to create a New folder. create folder
  2. Choosing the new folder that is created, click on the + icon again and click on New Image Set.
  3. Choose the imageset. And choose the attributes inspector.
  4. Select Single Scale, under Scales. enter image description here
  5. Drag and drop the image.
  6. 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.
Arun Balakrishnan
  • 1,462
  • 1
  • 12
  • 24
1

TL;DR;

Change the view layer's minificationFilter to .trilinear

imageView.layer.minificationFilter = .trilinear

as illustrated by the device screenshot below enter image description here

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.

amadour
  • 1,600
  • 11
  • 20
0

I have fixed, @DarshanKunjadiya issue. Make sure (if you are already using assets):

  1. Make sure images are not un-assigned
  2. 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.

Muhammad Waqas
  • 904
  • 2
  • 10
  • 21
0

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.

-1

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.

Screen shot displaying image @128x

Febin Fathah
  • 417
  • 3
  • 9
  • Please read the following link to know more about iPhone's human interface guidelines for displaying high-resolution images. https://developer.apple.com/design/human-interface-guidelines/ios/icons-and-images/image-size-and-resolution/ – Febin Fathah Apr 29 '19 at 12:13
  • 1. I think it is clear from the question, that general information on how 2x and 3x works is not what is expected. 2. In the example in your answer (128x128 being 1x), 3x size will be 384x384 not 512x512. – Swapnil Luktuke Apr 30 '19 at 12:40
  • @SwapnilLuktuke sorry I typed 512x512 mistakenly – Febin Fathah May 01 '19 at 16:18