给定任何维度的 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 ?我尝试了各种各样的东西:交换使用rect
和clipRect
,在 drawInRect:之前移动 UIRectClip 。没有骰子。
我尝试在线搜索此方法的示例,但无济于事。为了记录, UIRectClip 定义为:
修改当前剪切路径 与指定的相交 矩形。
随身携带的东西让我们更接近:
UIGraphicsBeginImageContext(clipRect.size);
UIRectClip(rect);
[myImage drawInRect:rect];
现在我们没有失真,但剪裁的图像并没有像我预期的那样居中。尽管如此,至少图像是50x50,尽管变量名称现在由于所述改组而被犯规。 (我会尊重地将重命名作为读者的练习。)
答案 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);