制作 UIImage 的方形裁剪导致图像拉伸

Posted

技术标签:

【中文标题】制作 UIImage 的方形裁剪导致图像拉伸【英文标题】:Making square crop of UIImage causing image to stretch 【发布时间】:2014-05-02 23:27:55 【问题描述】:

当尝试对 UIImage 进行中心裁剪时,我得到以下结果(左侧是640*1136 处的原始图像,右侧是在320*320 处适合正方形UIImageView 的裁剪图像):

转为:

我对比率元素进行了相当多的修改,以便它可以正确检测要修剪的数量:使用图像的较短边,基于short_side/width_of_desired_rect 构建比率,但它似乎不起作用在这种情况下。感谢您的帮助!

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

    //for retina consideration
    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;

【问题讨论】:

仅供参考 - ios 4.0 中添加了 UIScreenscale 属性。没有必要再检查它了。 你没有裁剪。您正在将整个图像重新绘制到一个较小的区域中。搜索“ios裁剪图片”,你会找到很多解决问题的方法。 谢谢@rmaddy - 我想我正在裁剪和重绘图像(压扁的图像有 8 个垂直平方数,而原始图像超过 11 个)。 你不想画到clipRect。您希望以原始纵横比绘制图像,以便仅在 clipRect 中呈现您想要保留的部分。 【参考方案1】:

试试这个:

- (UIImage *)squareImageFromImage:(UIImage *)image scaledToSize:(CGFloat)newSize 
    CGAffineTransform scaleTransform;
    CGPoint origin;

    if (image.size.width > image.size.height) 
        CGFloat scaleRatio = newSize / image.size.height;
        scaleTransform = CGAffineTransformMakeScale(scaleRatio, scaleRatio);

        origin = CGPointMake(-(image.size.width - image.size.height) / 2.0f, 0);
     else 
        CGFloat scaleRatio = newSize / image.size.width;
        scaleTransform = CGAffineTransformMakeScale(scaleRatio, scaleRatio);

        origin = CGPointMake(0, -(image.size.height - image.size.width) / 2.0f);
    

    CGSize size = CGSizeMake(newSize, newSize);
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) 
        UIGraphicsBeginImageContextWithOptions(size, YES, 0);
     else 
        UIGraphicsBeginImageContext(size);
    

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextConcatCTM(context, scaleTransform);

    [image drawAtPoint:origin];

    image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return image;

【讨论】:

感谢您回答@fumoboy007 - 不幸的是它没有工作:/ 图像炸得很大并且没有正确裁剪。我还删除了BOOL isLandscape,因为它没有在其余代码中使用。 嗯……这很奇怪。我可以看一些截图吗? 啊忘了缩放...等一下。 这很好用,无论是前置摄像头还是后置摄像头。谢谢!我只是添加了一些更改,因为 newSizeCGSize 而不是 CGFloat 不客气。 =) 对于信箱,是的,几乎可以翻转缩放和裁剪逻辑,并绘制一个黑色矩形(或任何颜色)。【参考方案2】:

使用此代码调整图像大小

// Returns image resized to the desired CGSize
- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize 
    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;

编辑:你基本上也在这里重绘。如果您一遍又一遍地重复使用相同的图像,最好调用一次并将结果保存为文件。在以后的调用中加载它而不是原始的。

编辑 2:好的,您要做的是在将图像拟合成正方形的同时保持纵横比。上面的代码基本上通过调整图像大小将图像放入正方形,但它不保持纵横比。保持纵横比的一种方法是找到缩小图像两个维度中较大者的因子,然后将另一个维度缩小相同的因子。如果您遇到问题,请告诉我。

【讨论】:

感谢 user2891327。虽然这在使用后置摄像头时效果很好,但在使用前置摄像头时,图像仍然会被挤压。奇怪的是,另一组代码似乎也是这种情况 我添加了一些截图以防万一。这是相机拍摄的(注意,它的纵横比为 9:16)而不调整为正方形:i.imgur.com/88SaGO6.png,这是在调整为正方形之后:i.imgur.com/fL8TMWr.png【参考方案3】:

swift3版本fumoboy007的代码..

     func squareImage(img: UIImage, scaledToSize newSize: CGFloat) -> UIImage 
    var scaleTransform: CGAffineTransform
    var origin: CGPoint
    var image = img
    if image.size.width > image.size.height 
        let scaleRatio: CGFloat = newSize / image.size.height
        scaleTransform = CGAffineTransform(scaleX: scaleRatio, y: scaleRatio)
        origin = CGPoint(x: -(image.size.width - image.size.height) / 2.0, y: 0)
    
    else 
        let scaleRatio: CGFloat = newSize / image.size.width
        scaleTransform = CGAffineTransform(scaleX: scaleRatio, y: scaleRatio)
        origin = CGPoint(x: 0, y: -(image.size.height - image.size.width) / 2.0)
    
    let size = CGSize(width: newSize, height: newSize)
    if image.size.width > image.size.height 
        UIGraphicsBeginImageContextWithOptions(size, true, 0)
    
    else 
        UIGraphicsBeginImageContext(size)
    

    let context: CGContext? = UIGraphicsGetCurrentContext()
    context?.concatenate(scaleTransform)
    image.draw(at: origin)
    image = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return image

【讨论】:

以上是关于制作 UIImage 的方形裁剪导致图像拉伸的主要内容,如果未能解决你的问题,请参考以下文章

在裁剪之前调整 UIImage 或 CIImage 的大小会拉伸图像吗?

图像变得拉伸,同时制作椭圆形的uiimage

UIImage裁剪透明像素

裁剪的 UIImage 方向/拉伸

将方形 UIImage 裁剪为圆角矩形

将 UIImage 转换为 CGImage 会导致图像旋转