正确使用UIRectClip将UIImage缩小到图标大小

时间:2009-09-10 15:26:51

标签: iphone uiimage icons scale

给定任何维度的 UIImage ,我希望生成一个方形“图标”大小的版本,px像素到一边,没有任何失真(拉伸)。但是,我遇到了一些障碍。不太确定问题出在哪里。这就是我到目前为止所做的事情。

首先,鉴于 UImage size,我确定了三件事:缩小图片时使用的ratio; a 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)绘制到rect中,设置剪切矩形,获取(可能是现在剪裁的)图像,使用它,最后清理我们的图像背景:

 UIGraphicsBeginImageContext(rect.size);
 [myImage drawInRect:rect]; 
 UIRectClip(clipRect);
 UIImage *icon = UIGraphicsGetImageFromCurrentImageContext();

 // Do something with the icon here ...

 UIGraphicsEndImageContext();

只有一个问题:剪辑永远不会发生!我最终得到了63px宽x50px高的图像。 :(

也许我在滥用/误解 UIRectClip ?我尝试了各种各样的东西:交换使用rectclipRect,在 drawInRect:之前移动 UIRectClip 。没有骰子。

我尝试在线搜索此方法的示例,但无济于事。为了记录, UIRectClip 定义为:

  

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

随身携带的东西让我们更接近:

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

现在我们没有失真,但剪裁的图像并没有像我预期的那样居中。尽管如此,至少图像是50x50,尽管变量名称现在由于所述改组而被犯规。 (我会尊重地将重命名作为读者的练习。)

3 个答案:

答案 0 :(得分: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 x 50图像的原点(在本例中)。

也许有一种更简单的方法。如果是这样,请称重!

答案 1 :(得分:1)

我想要实现类似的东西,但发现原始海报的答案并不是很有效。它扭曲了图像。这可能完全是因为他没有发布整个解决方案,并改变了一些初始化变量的方法:

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

我的解决方案错误(想要使用源图像中最大的可能方块)。此外,没有必要使用UIClipRect - 如果您将上下文设置为要提取的图像的大小,则无论如何都不会在该rect之外完成实际绘图。这只是缩放图像rect的大小和偏移其中一个原点坐标的问题。我在下面发布了我的解决方案:

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

答案 2 :(得分:0)

wheeliebin答案是正确的,但他忘记了在destY前面的减号

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