0

I have been trying for several days without succeeding, as said in the title, to crop any images as 16:9 rectangles.

In fact, I want to create thumbnails, doing the following: cropping, resizing and compressing. In reality, it looks like this: PhotosPicker -> selectedImage -> selectedImageData -> duplicated image data to selectedThumbData -> cropping function -> resizing function -> compressing function.

Here's an example to illustrate my point about what's a 16:9 rectangle:

Crop zone as 16:9 rectangles

About the function to resize and compress, I have no problem. I use .preparingThumbnail(of:) and it works fine:

func createThumbnail() {
    guard let selectedPhotoData, let image = UIImage(data: selectedPhotoData) else { return }

    let scale = image.size.height / image.size.width
    let width = UIScreen.main.bounds.width
    let height = UIScreen.main.bounds.width * scale
    let sizes = CGSize(width: width * 3, height: height * 3)

    let thumbnail = image.preparingThumbnail(of: sizes)
    selectedThumbData = thumbnail?.jpegData(compressionQuality: 0.80)
}

But about the function to crop it's different, I haven't found any other way than to use .cropping(to:) (except draw(at:) but it's too much complex) and in addition I can't do better than a square:

func cropImage() {
    guard let selectedPhotoData, let image = UIImage(data: selectedPhotoData) else { return }

    let sourceImage = image.size
    let minSide = min(sourceImage.width, sourceImage.height)
    let xOffset = (sourceImage.width - minSide) / 2
    let yOffset = (sourceImage.height - minSide) / 2
    var square = CGRect()
    if sourceImage.width < sourceImage.height {
        square = CGRect(x: yOffset, y: xOffset, width: minSide, height: minSide) // .integral
    } else {
        square = CGRect(x: xOffset, y: yOffset, width: minSide, height: minSide) // .integral
    }

    guard let croppedCGImage = image.cgImage?.cropping(to: square) else { return }

    let croppedImage = UIImage(cgImage: croppedCGImage, scale: image.imageRendererFormat.scale, orientation: image.imageOrientation)
    selectedThumbData = croppedImage.jpegData(compressionQuality: 0.80)
}

I think the problem is that I can't correctly set xOffset and yOffset. It's really tricky! Do you have any idea what should I change or replace to make it work as I want?

Thanks a lot, in advance!

Alexnnd
  • 429
  • 4
  • 13
  • Is your crop always in landscape mode? – Joakim Danielson May 16 '23 at 12:40
  • @JoakimDanielson Yes, regardless of the size, aspect ratio and orientation of the image, the crop zone must always be a 16:9 horizontal rectangle. – Alexnnd May 16 '23 at 12:48
  • Then you don’t have to care about min size and x offset in your code. The only tricky part is the y offset but that too isn’t so hard to figure out. – Joakim Danielson May 16 '23 at 12:51
  • @JoakimDanielson I'm on it for days now so it doesn't seem to be really easy to figure out. Can you please give me an idea? – Alexnnd May 16 '23 at 13:05
  • Thanks to not replace "Swift" by "iOS" in my question as I don't want to crop an image on my iPhone but on my Xcode project and also I would prefer to get an answer in "Swift" but not in "UIKit". – Alexnnd May 16 '23 at 15:28
  • THE ANWSER IS HERE: https://stackoverflow.com/a/49210788/18547664 – Alexnnd May 16 '23 at 15:50

0 Answers0