UIRectClip的正确使用方法,将UIImage缩小至图标大小

7
给定任意尺寸的UIImage图像,我希望生成一个正方形的“图标”大小版本,每边大小为px像素,无任何扭曲(拉伸)。然而,我遇到了一个小问题。不太确定问题出在哪里。这是我到目前为止所做的事情。
首先,给定一个UIImage size,我确定三件事:缩小图像时使用的比例;一个delta(我们希望的图标尺寸与最长边之间的差异),以及一个offset(用于在剪切图像时计算起始坐标):
 if (size.width > size.height) {
   ratio = px / size.width;
   delta = (ratio*size.width - ratio*size.height);
   offset = CGPointMake(delta/2, 0);
 } else {
   ratio = px / size.height;
   delta = (ratio*size.height - ratio*size.width);
   offset = CGPointMake(0, delta/2);
 }

现在,假设您有一张640像素宽、480像素高的图片,我们想从中获取一个50像素x 50像素的图标。由于宽度大于高度,因此我们的计算如下:

ratio = 50px / 640px = 0.078125
delta = (ratio * 640px) - (ratio * 480px) = 50px - 37.5px = 12.5px
offset = {x=6.25, y=0}

接下来,我创建了一个CGRect rect,它的大小足够大,可以被裁剪到我们想要的图标大小而不会失真,另外还有一个clipRect用于裁剪:

CGRect rect = CGRectMake(0.0, 0.0, (ratio * size.width) + delta,
                                   (ratio * size.height) + delta);
CGRect clipRect = CGRectMake(offset.x, offset.y, px, px);

将上述数值代入,我们得到:

rect = origin {x=0.0, y=0.0}, size {width=62.5, height=50.0}
clipRect = origin {x=6.25, y=0}, size {width=50.0, height=50.0}

现在我们有一个宽62.5像素,高50像素的矩形来使用,并且有一个裁剪矩形抓取中间的50x50部分。
接下来是最后一步!接下来,我们设置图像上下文,将UIImage(这里称为myImage)绘制到矩形中,设置裁剪矩形,获取(可能已被裁剪的)图像,使用它,最后清理我们的图像上下文。
 UIGraphicsBeginImageContext(rect.size);
 [myImage drawInRect:rect]; 
 UIRectClip(clipRect);
 UIImage *icon = UIGraphicsGetImageFromCurrentImageContext();

 // Do something with the icon here ...

 UIGraphicsEndImageContext();

只有一个问题:裁剪从未发生过!最终我得到的是一张63像素宽,50像素高的图片。:(

也许我误用/误解了 UIRectClip ?我尝试调整各种事物:交换 rectclipRect 的使用,将 UIRectClip 移动到 drawInRect: 之前。但都没有成功。

我还尝试在网上搜索这个方法的示例,但没有找到。对于记录,UIRectClip 的定义如下:

通过与指定矩形相交来修改当前剪切路径。

调整一些东西可以让我们更接近目标:

UIGraphicsBeginImageContext(clipRect.size);
UIRectClip(rect);
[myImage drawInRect:rect];

现在我们没有失真了,但是剪切的图像并没有如我所预期的那样居中于原始图像。不过,至少这个图像是50x50的,尽管由于上述混乱导致变量名现在被弄乱了。(我会尊重地让读者自己来重命名。)

3个回答

7

哎呀!我有点混淆了。这个方法是可行的:

CGRect clipRect = CGRectMake(-offset.x, -offset.y,
                             (ratio * size.width) + delta,
                             (ratio * size.height) + delta);
UIGraphicsBeginImageContext(CGSizeMake(px, px));
UIRectClip(clipRect);
[myImage drawInRect:clipRect];
UIImage *icon = UIGraphicsGetImageFromCurrentImageContext();

// Do something with the icon here ...

UIGraphicsEndImageContext();

不再需要使用rect。诀窍似乎是在剪辑矩形中使用负偏移量,从而将我们想要抓取50×50图像的原点对齐(在本示例中)。
也许有更简单的方法。如果有,请发表您的看法!

1

我想实现类似的事情,但发现原帖中的答案并没有完全起作用。它扭曲了图像。这可能仅仅是因为他没有发布整个解决方案,并更改了一些变量初始化的方式:

 (if (size.width > size.height) 
       ratio = px / size.width;

我的解决方案有问题(我想使用源图像中最大可能的正方形)。而且没有必要使用UIClipRect——如果您将上下文设置为要提取的图像大小,则任何实际绘制都不会在该矩形之外进行。只需缩放图像矩形的大小并偏移一个原点坐标即可。下面是我的解决方案:

+(UIImage *)makeIconImage:(UIImage *)image
{
    CGFloat destSize = 400.0;
    CGRect rect = CGRectMake(0, 0, destSize, destSize);

    UIGraphicsBeginImageContext(rect.size);

    if(image.size.width != image.size.height)
    {
        CGFloat ratio;
        CGRect destRect;

        if (image.size.width > image.size.height)
        {
            ratio = destSize / image.size.height;

            CGFloat destWidth = image.size.width * ratio;
            CGFloat destX = (destWidth - destSize) / 2.0;

            destRect = CGRectMake(-destX, 0, destWidth, destSize);

        }
        else
        {
            ratio = destSize / image.size.width;

            CGFloat destHeight = image.size.height * ratio;
            CGFloat destY = (destHeight - destSize) / 2.0;

            destRect = CGRectMake(0, destY, destSize, destHeight);
        }
        [image drawInRect:destRect];
    }
    else
    {
        [image drawInRect:rect];
    }
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return scaledImage;
}

谢谢你分享这个!我已经有一段时间没有看过我最终得到的东西了。我绝对不想或打算使用我的方法产生任何扭曲。你的“最大可能正方形”听起来很合理,我很高兴听到UIRectClip不是必需的。(其他读者,请发表意见并看看这对你们是否可行!) - Joe D'Andrea
谢谢,特别是针对这句话“而且不必使用UIClipRect——如果您将上下文设置为要提取的图像大小,则在该矩形之外不会进行任何实际绘制”。 - xaphod

0

wheeliebin的答案是正确的,但他忘记在destY前面加上一个减号

destRect = CGRectMake(0, -destY, destSize, destHeight);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接