我有一些代码来调整图像的大小,这样我就可以得到图像中心的缩放块-我用这个来获取一个UIImage,并返回一个小的,正方形的图像表示,类似于在照片应用程序的相册视图中看到的。(我知道我可以使用UIImageView和调整裁剪模式来实现相同的结果,但这些图像有时显示在UIWebViews中)。
我已经开始注意到这段代码中的一些崩溃,我有点难住了。我有两种不同的理论,不知道哪一种是正确的。
理论1)我通过绘制到目标尺寸的屏幕外图像上下文来实现裁剪。因为我想要图像的中心部分,所以我将传递给drawwinrect的CGRect参数设置为比图像上下文的边界更大的值。我希望这是符合规定的,但我是不是在试图掩盖其他我不应该触及的记忆?
理论2)我在后台线程中做所有这些。我知道UIKit的某些部分被限制在主线程中。我假设/希望绘制到屏幕外的视图不是其中之一。我错了吗?
(哦,我真怀念NSImage的drawwinrect:fromRect:operation:fraction:方法。)
在Swift中裁剪UIImage的最佳解决方案,在精度方面,像素缩放…:
private func squareCropImageToSideLength(let sourceImage: UIImage,
let sideLength: CGFloat) -> UIImage {
// input size comes from image
let inputSize: CGSize = sourceImage.size
// round up side length to avoid fractional output size
let sideLength: CGFloat = ceil(sideLength)
// output size has sideLength for both dimensions
let outputSize: CGSize = CGSizeMake(sideLength, sideLength)
// calculate scale so that smaller dimension fits sideLength
let scale: CGFloat = max(sideLength / inputSize.width,
sideLength / inputSize.height)
// scaling the image with this scale results in this output size
let scaledInputSize: CGSize = CGSizeMake(inputSize.width * scale,
inputSize.height * scale)
// determine point in center of "canvas"
let center: CGPoint = CGPointMake(outputSize.width/2.0,
outputSize.height/2.0)
// calculate drawing rect relative to output Size
let outputRect: CGRect = CGRectMake(center.x - scaledInputSize.width/2.0,
center.y - scaledInputSize.height/2.0,
scaledInputSize.width,
scaledInputSize.height)
// begin a new bitmap context, scale 0 takes display scale
UIGraphicsBeginImageContextWithOptions(outputSize, true, 0)
// optional: set the interpolation quality.
// For this you need to grab the underlying CGContext
let ctx: CGContextRef = UIGraphicsGetCurrentContext()
CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh)
// draw the source image into the calculated rect
sourceImage.drawInRect(outputRect)
// create new image from bitmap context
let outImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
// clean up
UIGraphicsEndImageContext()
// pass back new image
return outImage
}
调用此函数的指令:
let image: UIImage = UIImage(named: "Image.jpg")!
let squareImage: UIImage = self.squareCropImageToSideLength(image, sideLength: 320)
self.myUIImageView.image = squareImage
注意:最初的源代码灵感是用Objective-C写的,可以在Cocoanetics博客上找到。
这里没有一个答案能够100%正确地处理所有的缩放和旋转问题。以下是迄今为止所有内容的综合,最新的iOS7/8。它是作为一个方法被包含在UIImage的一个类别中。
- (UIImage *)croppedImageInRect:(CGRect)rect
{
double (^rad)(double) = ^(double deg) {
return deg / 180.0 * M_PI;
};
CGAffineTransform rectTransform;
switch (self.imageOrientation) {
case UIImageOrientationLeft:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -self.size.height);
break;
case UIImageOrientationRight:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -self.size.width, 0);
break;
case UIImageOrientationDown:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -self.size.width, -self.size.height);
break;
default:
rectTransform = CGAffineTransformIdentity;
};
rectTransform = CGAffineTransformScale(rectTransform, self.scale, self.scale);
CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], CGRectApplyAffineTransform(rect, rectTransform));
UIImage *result = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
CGImageRelease(imageRef);
return result;
}
(UIImage *)squareImageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
double ratio;
double delta;
CGPoint offset;
//make a new square size, that is the resized imaged width
CGSize sz = CGSizeMake(newSize.width, newSize.width);
//figure out if the picture is landscape or portrait, then
//calculate scale factor and offset
if (image.size.width > image.size.height) {
ratio = newSize.width / image.size.width;
delta = (ratio*image.size.width - ratio*image.size.height);
offset = CGPointMake(delta/2, 0);
} else {
ratio = newSize.width / image.size.height;
delta = (ratio*image.size.height - ratio*image.size.width);
offset = CGPointMake(0, delta/2);
}
//make the final clipping rect based on the calculated values
CGRect clipRect = CGRectMake(-offset.x, -offset.y,
(ratio * image.size.width) + delta,
(ratio * image.size.height) + delta);
//start a new context, with scale factor 0.0 so retina displays get
//high quality image
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(sz, YES, 0.0);
} else {
UIGraphicsBeginImageContext(sz);
}
UIRectClip(clipRect);
[image drawInRect:clipRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
我不满意的其他解决方案,因为他们要么画了几次(使用更多的权力比必要的)或有问题的方向。下面是我从UIImage *图像中使用的缩放正方形croppedImage。
CGFloat minimumSide = fminf(image.size.width, image.size.height);
CGFloat finalSquareSize = 600.;
//create new drawing context for right size
CGRect rect = CGRectMake(0, 0, finalSquareSize, finalSquareSize);
CGFloat scalingRatio = 640.0/minimumSide;
UIGraphicsBeginImageContext(rect.size);
//draw
[image drawInRect:CGRectMake((minimumSide - photo.size.width)*scalingRatio/2., (minimumSide - photo.size.height)*scalingRatio/2., photo.size.width*scalingRatio, photo.size.height*scalingRatio)];
UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
注意:所有这些答案都假设一个cgimage支持的图像对象。
的形象。CGImage可以返回nil,如果UIImage是由CIImage支持的,如果你用CIFilter创建了这个图像。
在这种情况下,您可能必须在新的上下文中绘制图像,并返回该图像(缓慢)。
UIImage* crop(UIImage *image, rect) {
UIGraphicsBeginImageContextWithOptions(rect.size, false, [image scale]);
[image drawAtPoint:CGPointMake(-rect.origin.x, -rect.origin.y)];
cropped_image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return cropped_image;
}