umutg4d
umutg4d

Reputation: 239

Swift how to crop image with always 1:1 aspect ratio

I am using this library's cropping functions to crop image like Instagram does. (https://github.com/fahidattique55/FAImageCropper) And its cropping part of the code works like this.

private func captureVisibleRect() -> UIImage {                       
    var croprect = CGRect.zero
    let xOffset = (scrollView.imageToDisplay?.size.width)! / scrollView.contentSize.width;
    let yOffset = (scrollView.imageToDisplay?.size.height)! / scrollView.contentSize.height;

    croprect.origin.x = scrollView.contentOffset.x * xOffset;
    croprect.origin.y = scrollView.contentOffset.y * yOffset;

    let normalizedWidth = (scrollView?.frame.width)! / (scrollView?.contentSize.width)!
    let normalizedHeight = (scrollView?.frame.height)! / (scrollView?.contentSize.height)!

    croprect.size.width = scrollView.imageToDisplay!.size.width * normalizedWidth
    croprect.size.height = scrollView.imageToDisplay!.size.height * normalizedHeight

    let toCropImage = scrollView.imageView.image?.fixImageOrientation()
    let cr: CGImage? = toCropImage?.cgImage?.cropping(to: croprect)
    let cropped = UIImage(cgImage: cr!)

    return cropped  }

But the problem is for example i have a photo with (800(W)*600(H)) size, and i want to crop it with full width by using full zoom out.This function calculates croprect variable (800(W)*800(H)) correctly. But after this part of the code let cr: CGImage? = toCropImage?.cgImage?.cropping(to: croprect) the cr's resolution becomes (800(W)*600(H)). How can i transform this to square image by filling the empty parts of it with white color?

Upvotes: 1

Views: 3766

Answers (3)

Shoaib
Shoaib

Reputation: 1325

Simple extensions for Cropping images in different ways

I you want to crop from the center use cropAspectFill and if you want to keep full image and want to make it square then use cropAspectFit

Objective-C solution

    @implementation UIImage (crop)

- (UIImage *)cropAspectFill {

    CGFloat minSize = MIN(self.size.height, self.size.width);
    CGSize squareSize = CGSizeMake(minSize, minSize);

    // Get our offset to center the image inside our new square frame
    CGFloat dx = (minSize - self.size.width) / 2.0f;
    CGFloat dy = (minSize - self.size.height) / 2.0f;

    UIGraphicsBeginImageContext(squareSize);
    CGRect rect = CGRectMake(0, 0, minSize, minSize);

    // Adjust the rect to be centered in our new image
    rect = CGRectInset(rect, dx, dy);
    [self drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0];

    UIImage *squareImage =  UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return squareImage;
}

- (UIImage *)cropAspectFit {
    // Get a square that the image will fit into
    CGFloat maxSize = MIN(self.size.height, self.size.width);
    CGSize squareSize = CGSizeMake(maxSize, maxSize);

    // Get our offset to center the image inside our new square frame
    CGFloat dx = (maxSize - self.size.width) / 2.0f;
    CGFloat dy = (maxSize - self.size.height) / 2.0f;

    UIGraphicsBeginImageContext(squareSize);
    CGRect rect = CGRectMake(0, 0, maxSize, maxSize);

    // Adjust the rect to be centered in our new image
    rect = CGRectInset(rect, dx, dy);
    [self drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0];

    UIImage *squareImage =  UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return squareImage;
}

@end

Swift solution

extension UIImage {
func cropAspectFill() -> UIImage {
  let minSize = min(size.height, size.width)
  let squareSize = CGSize(width: minSize, height: minSize)

  // Get our offset to center the image inside our new square frame
  let dx = (minSize - size.width) / 2.0
  let dy = (minSize - size.height) / 2.0

  UIGraphicsBeginImageContext(squareSize)
  let rect = CGRect(x: 0, y: 0, width: minSize, height: minSize)

  // Adjust the rect to be centered in our new image
  let centeredRect = rect.insetBy(dx: dx, dy: dy)
  draw(in: centeredRect, blendMode: .normal, alpha: 1.0)

  let squareImage = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext()

  return squareImage!
}

func cropAspectFit() -> UIImage {
  // Get a square that the image will fit into
  let maxSize = min(size.height, size.width)
  let squareSize = CGSize(width: maxSize, height: maxSize)

  // Get our offset to center the image inside our new square frame
  let dx = (maxSize - size.width) / 2.0
  let dy = (maxSize - size.height) / 2.0

  UIGraphicsBeginImageContext(squareSize)
  let rect = CGRect(x: 0, y: 0, width: maxSize, height: maxSize)

  // Adjust the rect to be centered in our new image
  let centeredRect = rect.insetBy(dx: dx, dy: dy)
  draw(in: centeredRect, blendMode: .normal, alpha: 1.0)

  let squareImage = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext()

  return squareImage!
}
}

Upvotes: 0

umutg4d
umutg4d

Reputation: 239

You can square the image after this process by using the answer in this link. How to draw full UIImage inside a square with white color on the edge

This is the Swift 3 version of it.

private func squareImageFromImage(image: UIImage) -> UIImage{
    var maxSize = max(image.size.width,image.size.height)
    var squareSize = CGSize.init(width: maxSize, height: maxSize)

    var dx = (maxSize - image.size.width) / 2.0
    var dy = (maxSize - image.size.height) / 2.0
    UIGraphicsBeginImageContext(squareSize)
    var rect = CGRect.init(x: 0, y: 0, width: maxSize, height: maxSize)

    var context = UIGraphicsGetCurrentContext()
    context?.setFillColor(UIColor.white.cgColor)
    context?.fill(rect)

    rect = rect.insetBy(dx: dx, dy: dy)
    image.draw(in: rect, blendMode: CGBlendMode.normal, alpha: 1.0)
    var squareImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return squareImage!
}

Upvotes: 2

Anwuna
Anwuna

Reputation: 1113

I suggest you use UIGraphicsContext to draw a rectangle with the intended width and height, filling it with the desired color. Then draw the cropped image on it.

I haven't tested this but this should work for what you want.

I have omitted other parts of your code to focus on the essentials.

....
let context: CGContext? = UIGraphicsGetCurrentContext()
let rect = CGRect(x: 0, y: 0, width: width, height: height)
let color = UIColor.white
color.setFill()
context?.fill(rect)

let cr: CGImage? = toCropImage?.cgImage?.cropping(to: croprect)
let cropped = UIImage(cgImage: cr!)

context?.draw(cropped, in: rect)
let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!

Replace width and height with the desired width and height.

Upvotes: 1

Related Questions