MyLocations: p.253 exercise aspect fill thumbnails [SOLVED]

The tutorial only shows how to resize the image (with a constant aspect ratio) to fit within the 52x52 point bounds of the thumbnail (“aspect fit” rules). That leaves white space top+bottom or left+right of the thumbnail, if the original image is not square as well.

The task is to use the “Aspect Fill” rules to make thumbnails that always fill the boundaries of the thumbnail while showing a centered part of the image with the correct aspect ratio.

That requires the following steps in my opinion:

  1. compare the aspect ratios of the original image as well as the thumbnail
  2. calculate size and (centered) location of the part of the original image to be resized as the thumbnail
  3. write the part of the original image determined in 2. to a thumbnail with the correct size.

I have solved steps 1+2 (I think) with the following code:

    let horizontalRatio = bounds.width / size.width
    let verticalRatio = bounds.height / size.height
    let newAspectRatio = bounds.height / bounds.width
            
    if horizontalRatio > verticalRatio {

      let tempHeight = size.width * newAspectRatio
      let originY = (size.height - tempHeight) / 2
      let tempSize = CGSize(width: size.width, height: tempHeight)
      
    } else if horizontalRatio < verticalRatio {

      let tempWidth = size.height / newAspectRatio
      let originX = (size.width - tempWidth) / 2
      let tempSize = CGSize(width: tempWidth, height: size.height)
      
    } else {
      // aspect ratio of image and thumbnail are identical --> no cropping needed
    }
  • I calculate the horizontalRatio and verticalRatio as in the aspect fit example.
  • I then determine the newAspectRatio of the thumbnail to be generated.
  • if horizontalRatio > verticalRatio means that the original image is taller than the thumbnail.
  • Therefore the part to be cut-out has the original size.width and a new tempHeight that is calculated by applying the newAspectRatio to the original width!
  • The starting point of the cut-out part is at x=0 and originY = (size.height - tempHeight) / 2

I have tested that in the simulator it seems to produce the correct results.

What I haven’t figured out yet is how to crop the original image with the calculated data to the correct aspect ratio of the thumbnail.

Writing the cropped image to the thumbnail size should work as in the aspect fit example.

If anyone has a hint or solution for that I’d be happy to hear that. Improvements to my code above are also always welcome. :slight_smile:

I’ll update this post if I find a solution myself.

When finishing the MyLocations tutorial I found out, that I was thinking way to complicated. :blush:

The solution requires just two small steps.

  1. In the UIImage extension change min to max in the following line:
    let ratio = max(horizontalRatio, verticalRatio)

  2. Add the following line to the awakeFromNib() function in Location Cell:
    photoImageView.clipsToBounds = true

Step 1 resizes the image so the smaller side is 52 points, making sure that the image fills the 52x52 points thumbnail.
Step 2 clips the longer side of the image to 52 points so it fits the square perfectly.

If not the center of the image is shown in the thumbnails, check the image view in the storyboard. In the attributes inspector under “View” the “Mode” property should be set to center.

2 Likes

You should use built-in min and max functions instead of doing it by hand.

Here’s mine solution: