UIImage种植中心广场

所以这是我迄今为止所做的。 我正在使用从相机捕获的UIImage,并可以在横向上裁剪中心广场。 出于某种原因,这不会像预期的那样转换成肖像模式。 我会发布我的代码和日志只是为了参考。

码:

CGRect squareRect = CGRectMake(offsetX, offsetY, newWidth, newHeight); CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], squareRect); image = [UIImage imageWithCGImage:imageRef scale:1 orientation:image.imageOrientation]; 

肖像结果(不是正方形):

 original image size: {1536, 2048}, with orientation: 3 squareRect: {{0, 256}, {1536, 1536}} new image size: {1280, 1536}, with orientation: 3 <--- not expected 

景观结果(平方):

 original image size: {2048, 1536}, with orientation: 1 squareRect: {{256, 0}, {1536, 1536}} new image size: {1536, 1536}, with orientation: 1 

这是CGImageCreateWithImageInRect()中的错误还是我在这里丢失的东西?

我想这里是完美的解决scheme!
toSize尺寸上裁剪图像不是个好主意。 当图像分辨率(尺寸)非常大时,它会显得很奇怪。
以下代码会根据toSize比例裁剪图像。
来自@BlackRider的答案得到了改进。

 - (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; } 

这适用于不同的方向。 纵向和横向都能正确工作。

 - (UIImage *)imageByCroppingImage:(UIImage *)image toSize:(CGSize)size { // not equivalent to image.size (which depends on the imageOrientation)! double refWidth = CGImageGetWidth(image.CGImage); double refHeight = CGImageGetHeight(image.CGImage); double x = (refWidth - size.width) / 2.0; double y = (refHeight - size.height) / 2.0; CGRect cropRect = CGRectMake(x, y, size.height, size.width); CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect); UIImage *cropped = [UIImage imageWithCGImage:imageRef scale:0.0 orientation:self.imageOrientation]; CGImageRelease(imageRef); return cropped; } 

基于Elmundo检查的答案和Imbrue的快速版本,这里是自动计算图像中心大小(考虑方向)的相同解决scheme,并考虑到错误:

 func cropImageToSquare(image: UIImage) -> UIImage? { var imageHeight = image.size.height var imageWidth = image.size.width if imageHeight > imageWidth { imageHeight = imageWidth } else { imageWidth = imageHeight } let size = CGSize(width: imageWidth, height: imageHeight) let refWidth : CGFloat = CGFloat(CGImageGetWidth(image.CGImage)) let refHeight : CGFloat = CGFloat(CGImageGetHeight(image.CGImage)) let x = (refWidth - size.width) / 2 let y = (refHeight - size.height) / 2 let cropRect = CGRectMake(x, y, size.height, size.width) if let imageRef = CGImageCreateWithImageInRect(image.CGImage, cropRect) { return UIImage(CGImage: imageRef, scale: 0, orientation: image.imageOrientation) } return nil } 

Swift 3版本

 func cropImageToSquare(image: UIImage) -> UIImage? { var imageHeight = image.size.height var imageWidth = image.size.width if imageHeight > imageWidth { imageHeight = imageWidth } else { imageWidth = imageHeight } let size = CGSize(width: imageWidth, height: imageHeight) let refWidth : CGFloat = CGFloat(image.cgImage!.width) let refHeight : CGFloat = CGFloat(image.cgImage!.height) let x = (refWidth - size.width) / 2 let y = (refHeight - size.height) / 2 let cropRect = CGRect(x: x, y: y, width: size.height, height: size.width) if let imageRef = image.cgImage!.cropping(to: cropRect) { return UIImage(cgImage: imageRef, scale: 0, orientation: image.imageOrientation) } return nil } 

尝试这样的事情:

 - (UIImage *)imageByCroppingImage:(UIImage *)image toSize:(CGSize)size { double x = (image.size.width - size.width) / 2.0; double y = (image.size.height - size.height) / 2.0; CGRect cropRect = CGRectMake(x, y, size.height, size.width); CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect); UIImage *cropped = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); return cropped; } 

正如你所看到的,我没有在调用UIImage imageWithCGImage:指定方向。 我不知道这是你的代码中的问题。

有一个检查解决scheme的快速版本:

 private func imageByCroppingImage(image : UIImage, size : CGSize) -> UIImage{ var refWidth : CGFloat = CGFloat(CGImageGetWidth(image.CGImage)) var refHeight : CGFloat = CGFloat(CGImageGetHeight(image.CGImage)) var x = (refWidth - size.width) / 2 var y = (refHeight - size.height) / 2 let cropRect = CGRectMake(x, y, size.height, size.width) let imageRef = CGImageCreateWithImageInRect(image.CGImage, cropRect) let cropped : UIImage = UIImage(CGImage: imageRef, scale: 0, orientation: image.imageOrientation)! return cropped } 

从@ Elmundo的回答改进

 +(UIImage *)getCenterMaxSquareImageByCroppingImage:(UIImage *)image withOrientation:(UIImageOrientation)imageOrientation { CGSize centerSquareSize; double oriImgWid = CGImageGetWidth(image.CGImage); double oriImgHgt = CGImageGetHeight(image.CGImage); NSLog(@"oriImgWid==[%.1f], oriImgHgt==[%.1f]", oriImgWid, oriImgHgt); if(oriImgHgt <= oriImgWid) { centerSquareSize.width = oriImgHgt; centerSquareSize.height = oriImgHgt; }else { centerSquareSize.width = oriImgWid; centerSquareSize.height = oriImgWid; } NSLog(@"squareWid==[%.1f], squareHgt==[%.1f]", centerSquareSize.width, centerSquareSize.height); double x = (oriImgWid - centerSquareSize.width) / 2.0; double y = (oriImgHgt - centerSquareSize.height) / 2.0; NSLog(@"x==[%.1f], x==[%.1f]", x, y); CGRect cropRect = CGRectMake(x, y, centerSquareSize.height, centerSquareSize.width); CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect); UIImage *cropped = [UIImage imageWithCGImage:imageRef scale:0.0 orientation:imageOrientation]; CGImageRelease(imageRef); return cropped; } 

Swift 3

  let refWidth : CGFloat = CGFloat(image.cgImage!.width) let refHeight : CGFloat = CGFloat(image.cgImage!.height) let x = (refWidth - size.width) / 2 let y = (refHeight - size.height) / 2 let cropRect = CGRect(x: x, y: y, width: size.width, height: size.height) let imageRef = image.cgImage!.cropping(to: cropRect) let cropped : UIImage = UIImage(cgImage: imageRef!, scale: 0, orientation: image.imageOrientation) return cropped 

Swift 2使用UIImage Extension

 extension UIImage { func imageByCroppingImage(size : CGSize) -> UIImage { let refWidth : CGFloat = CGFloat(CGImageGetWidth(self.CGImage)) let refHeight : CGFloat = CGFloat(CGImageGetHeight(self.CGImage)) let x = (refWidth - size.width) / 2 let y = (refHeight - size.height) / 2 let cropRect = CGRectMake(x, y, size.width, size.height) let imageRef = CGImageCreateWithImageInRect(self.CGImage, cropRect) let cropped : UIImage = UIImage(CGImage: imageRef!, scale: 0, orientation: self.imageOrientation) return cropped } } 

这是一个古老的问题,但是没有一个答案是正确的(即使是被接受的答案)。 重要的是要理解的是, UIImageOrientationimage.imageOrientation )实际上是正确的,但它的UP的定义和UP的定义是不同的。 对我们而言, UP是设备的顶部(电源button所在的位置)。 对于UIImageOrientationUP是音量控制button的对面 。 因此,如果设备拍摄音量控制下的图片,这是UIImageOrientationUp 。 如果以纵向模式拍摄照片(使用“主屏幕”button),则为UIImageOrientationLeft

所以你可以计算中心的肖像,然后你可以应用以下转换的图像,使作物在正确的地方。

 - (UIImage *)cropImage:(UIImage*)image toRect:(CGRect)rect { CGFloat (^rad)(CGFloat) = ^CGFloat(CGFloat deg) { return deg / 180.0f * (CGFloat) M_PI; }; // determine the orientation of the image and apply a transformation to the crop rectangle to shift it to the correct position CGAffineTransform rectTransform; switch (image.imageOrientation) { case UIImageOrientationLeft: rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -image.size.height); break; case UIImageOrientationRight: rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -image.size.width, 0); break; case UIImageOrientationDown: rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -image.size.width, -image.size.height); break; default: rectTransform = CGAffineTransformIdentity; }; // adjust the transformation scale based on the image scale rectTransform = CGAffineTransformScale(rectTransform, image.scale, image.scale); // apply the transformation to the rect to create a new, shifted rect CGRect transformedCropSquare = CGRectApplyAffineTransform(rect, rectTransform); // use the rect to crop the image CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, transformedCropSquare); // create a new UIImage and set the scale and orientation appropriately UIImage *result = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation]; // memory cleanup CGImageRelease(imageRef); return result; } 

这段代码移动裁剪的方块,使其处于正确的相对位置。

这是基于@ Alonzo的Swift 3上面的答案,代码被简化和简化,使其更易于理解和简洁。 如果图像已经是正方形的话,它也会放弃。

 extension UIImage { func square() -> UIImage? { if size.width == size.height { return self } let cropWidth = min(size.width, size.height) let cropRect = CGRect( x: (size.width - cropWidth) / 2/0, y: (size.height - cropWidth) / 2.0, width: cropWidth, height: cropWidth ) guard let imageRef = cgImage?.cropping(to: cropRect) else { return nil } return UIImage(cgImage: imageRef, scale: 0, orientation: imageOrientation) } } 

基于Swift 2扩展的解决scheme。 从@Geoffrey和@Nirav Dangi即兴创作。 请注意,当它们小于给定的宽度或高度时,我们将newCropWidth和newCropHeight设置为图像的宽度或高度。

 extension UIImage { func imageByCroppingImage(size: CGSize) -> UIImage { let newCropWidth, newCropHeight : CGFloat; if(self.size.width < self.size.height) { if (self.size.width < size.width) { newCropWidth = self.size.width; } else { newCropWidth = size.width; } newCropHeight = (newCropWidth * size.height)/size.width; } else { if (self.size.height < size.height) { newCropHeight = self.size.height; } else { newCropHeight = size.height; } newCropWidth = (newCropHeight * size.width)/size.height; } let x = self.size.width / 2 - newCropWidth / 2; let y = self.size.height / 2 - newCropHeight / 2; let cropRect = CGRectMake(x, y, newCropWidth, newCropHeight); let imageRef = CGImageCreateWithImageInRect(self.CGImage, cropRect); let croppedImage : UIImage = UIImage(CGImage: imageRef!, scale: 0, orientation: self.imageOrientation); return croppedImage; } } 

那么从UIImageView获取帮助呢?

 + (UIImage *)laodSquareImage:(UIImage *)image withDiameter:(CGFloat)diameter { CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter); UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame]; imageView.contentMode = UIViewContentModeScaleAspectFill; imageView.clipsToBounds = YES; imageView.image = image; CALayer *layer = imageView.layer; layer.masksToBounds = YES; UIGraphicsBeginImageContextWithOptions(imageView.bounds.size,NO, [UIScreen mainScreen].scale); CGContextRef context = UIGraphicsGetCurrentContext(); [layer renderInContext:context]; UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return roundedImage; } 

你也可以通过添加一个链接来创build图像圈。

 layer.cornerRadius =MAX( imageView.frame.size.height,imageView.frame.size.width)/2; 

已经有很多解决scheme,但我想发布我的:扩展UIImage {

 var cgImageWidth: Int { return cgImage?.width ?? 0 } var cgImageheight: Int { return cgImage?.height ?? 0 } var blance: CGFloat { return min(size.width, size.height)} var blanceSize: CGSize { return CGSize(width: blance, height: blance) } var blanceRect: CGRect { return CGRect(origin: .zero, size: blanceSize) } var roundedImage: UIImage? { UIGraphicsBeginImageContextWithOptions(blanceSize, false, scale) defer { UIGraphicsEndImageContext() } guard let cgImage = cgImage?.cropping(to: CGRect(origin: CGPoint(x: max(0, CGFloat(cgImageWidth) - blance)/2.0, y: max(0, CGFloat(cgImageheight) - blance)/2.0), size: blanceSize)) else { return nil } UIBezierPath(ovalIn: blanceRect).addClip() UIImage(cgImage: cgImage, scale: 1.0, orientation: self.imageOrientation).draw(in: blanceRect) return UIGraphicsGetImageFromCurrentImageContext() } 

}

我正在处理以下

 extension UIImage { var cgImageWidth: Int { return cgImage?.width ?? 0 } var cgImageheight: Int { return cgImage?.height ?? 0 } var blance: CGFloat { return min(size.width, size.height)} var blanceSize: CGSize { return CGSize(width: blance, height: blance) } var blanceRect: CGRect { return CGRect(origin: .zero, size: blanceSize) } var roundedImage: UIImage? { UIGraphicsBeginImageContextWithOptions(blanceSize, false, scale) defer { UIGraphicsEndImageContext() } guard let cgImage = cgImage?.cropping(to: CGRect(origin: CGPoint(x: max(0, CGFloat(cgImageWidth) - blance)/2.0, y: max(0, CGFloat(cgImageheight) - blance)/2.0), size: blanceSize)) else { return nil } UIBezierPath(ovalIn: blanceRect).addClip() UIImage(cgImage: cgImage, scale: 1.0, orientation: self.imageOrientation).draw(in: blanceRect) return UIGraphicsGetImageFromCurrentImageContext() } 

}

我能够用这样的东西来实现它:

  UIImage *thisImage = [[UIImage alloc] initWithContentsOfFile:imagePath]; double x = (thisImage.size.width )/2.0; double y = (thisImage.size.height)/2.0; mediaImage = [self imageByCropping:thisImage toRect:CGRectMake(x, y, 60, 60)]; [thisImage release];