How to Crop a 4*3 Image in Photolibrary or Camera in Swift

How to crop a 4*3 image in photoLibrary or camera in swift

I did not know that links are not permitted as answer. Here I will try to answer the question.

Aim: Crop image with a predefined ratio.
Approach:

  • In the viewcontroller - we need to add a scrollview - so that we can
    put the image there and zoom or pan if required.
  • Set a constrain for the scrollview height and view height ratio(may
    be 0.8) - left 20% of the view to put the buttons.
  • set a constrain for the scrollview height and width ratio (in this
    case 4:3) Programmatically add Imageview (set size of the selected
    image's height and width )
  • Set scrollview minimum and maximum zoom scale to fit smaller and
    larger images in the scrollview properly.
  • while displaying the image we will make sure imageview either fits by
    height or width.

Now run the application see if we can view only the image in an 4:3 ratio scrollview.

For the save option just map the coordinates of the scrollview and get the image from the imageview (here we need to use the zoom scale)

Code:

var imgview: UIImageView!
var imagepicked:UIImage!
var minZoomScale:CGFloat!
let picker = UIImagePickerController()
@IBOutlet weak var scrollViewSquare: UIScrollView!

override func viewDidLoad() {
super.viewDidLoad()
picker.delegate = self
scrollViewSquare.delegate = self
}
func imagePickerController(
picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : AnyObject])
{
imagepicked = (info[UIImagePickerControllerOriginalImage] as? UIImage)!
ImageViewInit()
dismissViewControllerAnimated(false, completion: nil)
}

@IBAction func Pick(sender: AnyObject) {
picker.allowsEditing = false
picker.sourceType = .PhotoLibrary
presentViewController(picker, animated: true, completion: nil)
}
func ImageViewInit(){
imgview = UIImageView()
imgview.frame = CGRectMake(0, 0, imagepicked.size.width, imagepicked.size.height)
imgview.image = imagepicked
imgview.contentMode = .ScaleAspectFit
imgview.backgroundColor = UIColor.lightGrayColor()
scrollViewSquare.maximumZoomScale=4;
scrollViewSquare.minimumZoomScale=0.02;
scrollViewSquare.bounces=true;
scrollViewSquare.bouncesZoom=true;
scrollViewSquare.contentMode = .ScaleAspectFit
scrollViewSquare.contentSize = imagepicked.size
scrollViewSquare.autoresizingMask = UIViewAutoresizing.FlexibleWidth
scrollViewSquare.addSubview(imgview)
setZoomScale()
}
//fit imageview in the scrollview
func setZoomScale(){
let imageViewSize = imgview.bounds.size
let scrollViewSize = scrollViewSquare.bounds.size
let widthScale = scrollViewSize.width / imageViewSize.width
let heightScale = scrollViewSize.height / imageViewSize.height
minZoomScale = max(widthScale, heightScale)
scrollViewSquare.minimumZoomScale = minZoomScale
scrollViewSquare.zoomScale = minZoomScale
}

func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imgview
}
//mapping the image from the scrollview to imageview to get the desired ratio
@IBAction func Save(sender: AnyObject) {
let offset = scrollViewSquare.contentOffset
let visibleRect: CGRect = CGRectMake(offset.x, offset.y, offset.x+scrollViewSquare.frame.width, offset.y+scrollViewSquare.frame.height)
let visibleImgRect: CGRect = CGRectMake(offset.x/scrollViewSquare.zoomScale, offset.y/scrollViewSquare.zoomScale, (offset.x+scrollViewSquare.frame.width)/scrollViewSquare.zoomScale, (offset.y+scrollViewSquare.frame.height)/scrollViewSquare.zoomScale)
print("content offset now\(offset) and visible rect is \(visibleRect) - zoomlevel \(scrollViewSquare.zoomScale) now image \(imagepicked.size) and current visible area in image is \(visibleImgRect)")
}

Cropping an image with imagepickercontroller in swift

You can use default controls to achieve image cropping.

self.imgPicker.allowsEditing = true

Delegate Method

//MARK: image picker delegate method
//MARK:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

var image : UIImage!

if let img = info[UIImagePickerControllerEditedImage] as? UIImage
{
image = img

}
else if let img = info[UIImagePickerControllerOriginalImage] as? UIImage
{
image = img
}

picker.dismiss(animated: true,completion: nil)
}

UIImage: Resize, then Crop

I needed the same thing - in my case, to pick the dimension that fits once scaled, and then crop each end to fit the rest to the width. (I'm working in landscape, so might not have noticed any deficiencies in portrait mode.) Here's my code - it's part of a categeory on UIImage. Target size in my code is always set to the full screen size of the device.

@implementation UIImage (Extras)

#pragma mark -
#pragma mark Scale and crop image

- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize
{
UIImage *sourceImage = self;
UIImage *newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

if (CGSizeEqualToSize(imageSize, targetSize) == NO)
{
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;

if (widthFactor > heightFactor)
{
scaleFactor = widthFactor; // scale to fit height
}
else
{
scaleFactor = heightFactor; // scale to fit width
}

scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;

// center the image
if (widthFactor > heightFactor)
{
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
}
else
{
if (widthFactor < heightFactor)
{
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}
}

UIGraphicsBeginImageContext(targetSize); // this will crop

CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;

[sourceImage drawInRect:thumbnailRect];

newImage = UIGraphicsGetImageFromCurrentImageContext();

if(newImage == nil)
{
NSLog(@"could not scale image");
}

//pop the context to get back to the default
UIGraphicsEndImageContext();

return newImage;
}

How to remove cropping option when uploading an image in iOS/ swift

You can use default controls to disable image cropping.

self.imagePicker.allowsEditing = false

Cropping center square of UIImage

I think here would be the perfect solution!
It is NOT good idea to crop image basis on the toSize's size. It will look weird when the image resolution (size) is very large.
Following code will crop the image as per the toSize's ratio.

Improved from @BlackRider's answer.

- (UIImage *)imageByCroppingImage:(UIImage *)image toSize:(CGSize)size
{
double newCropWidth, newCropHeight;

//=== To crop more efficently =====//
if(image.size.width < image.size.height){
if (image.size.width < size.width) {
newCropWidth = size.width;
}
else {
newCropWidth = image.size.width;
}
newCropHeight = (newCropWidth * size.height)/size.width;
} else {
if (image.size.height < size.height) {
newCropHeight = size.height;
}
else {
newCropHeight = image.size.height;
}
newCropWidth = (newCropHeight * size.width)/size.height;
}
//==============================//

double x = image.size.width/2.0 - newCropWidth/2.0;
double y = image.size.height/2.0 - newCropHeight/2.0;

CGRect cropRect = CGRectMake(x, y, newCropWidth, newCropHeight);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);

UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);

return cropped;
}

Cropping image with Swift and put it on center position

To get a centered position for your crop, you can halve the difference of the height and width. Then you can assign the bounds for the new width and height after checking the orientation of the image (which part is longer)

func cropToBounds(image: UIImage, width: Double, height: Double) -> UIImage {

let contextImage: UIImage = UIImage(CGImage: image.CGImage)!

let contextSize: CGSize = contextImage.size

var posX: CGFloat = 0.0
var posY: CGFloat = 0.0
var cgwidth: CGFloat = CGFloat(width)
var cgheight: CGFloat = CGFloat(height)

// See what size is longer and create the center off of that
if contextSize.width > contextSize.height {
posX = ((contextSize.width - contextSize.height) / 2)
posY = 0
cgwidth = contextSize.height
cgheight = contextSize.height
} else {
posX = 0
posY = ((contextSize.height - contextSize.width) / 2)
cgwidth = contextSize.width
cgheight = contextSize.width
}

let rect: CGRect = CGRectMake(posX, posY, cgwidth, cgheight)

// Create bitmap image from context using the rect
let imageRef: CGImageRef = CGImageCreateWithImageInRect(contextImage.CGImage, rect)

// Create a new image based on the imageRef and rotate back to the original orientation
let image: UIImage = UIImage(CGImage: imageRef, scale: image.scale, orientation: image.imageOrientation)!

return image
}

I found most of this info over at this website in case you wanted to read further.

Updated for Swift 4

func cropToBounds(image: UIImage, width: Double, height: Double) -> UIImage {

let cgimage = image.cgImage!
let contextImage: UIImage = UIImage(cgImage: cgimage)
let contextSize: CGSize = contextImage.size
var posX: CGFloat = 0.0
var posY: CGFloat = 0.0
var cgwidth: CGFloat = CGFloat(width)
var cgheight: CGFloat = CGFloat(height)

// See what size is longer and create the center off of that
if contextSize.width > contextSize.height {
posX = ((contextSize.width - contextSize.height) / 2)
posY = 0
cgwidth = contextSize.height
cgheight = contextSize.height
} else {
posX = 0
posY = ((contextSize.height - contextSize.width) / 2)
cgwidth = contextSize.width
cgheight = contextSize.width
}

let rect: CGRect = CGRect(x: posX, y: posY, width: cgwidth, height: cgheight)

// Create bitmap image from context using the rect
let imageRef: CGImage = cgimage.cropping(to: rect)!

// Create a new image based on the imageRef and rotate back to the original orientation
let image: UIImage = UIImage(cgImage: imageRef, scale: image.scale, orientation: image.imageOrientation)

return image
}

How can I crop an image before loading it to the view controller

When you call the ImagePicker function, set allowsEditing as true:

self.imagePicker.allowsEditing = true
self.imagePicker.sourceType = .camera
self.present(self.imagePicker, animated: true, completion: nil)

Another option, if you want a bit more customization, you can use this library: https://github.com/TimOliver/TOCropViewController

And in didFinishPickingMediaWithInfo, you do something like this:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage{
dismiss(animated: true, completion: nil)
let cropVC = TOCropViewController(image: pickedImage)
cropVC.delegate = self
cropVC.aspectRatioPickerButtonHidden = true
cropVC.aspectRatioPreset = .presetSquare
cropVC.aspectRatioLockEnabled = true
cropVC.resetAspectRatioEnabled = false
self.present(cropVC, animated: true, completion: nil)
}
}


Related Topics



Leave a reply



Submit