我的最终目标是用 NSImage 填充任意大小的矩形。我想要:
- 填充整个矩形
- 保留图像的纵横比
- 在保持 1) 和 2) 的同时尽可能多地显示图像
- 当无法显示所有图像时,向中心裁剪。
这证明了我正在尝试做的事情。顶部的船的原始图像被绘制成下面各种大小的矩形。
好的,到目前为止一切顺利。我向 NSImage 添加了一个类别来执行此操作。
@implementation NSImage (Fill)
/**
* Crops source to best fit the destination
*
* destRect is the rect in which we want to draw the image
* sourceRect is the rect of the image
*/
-(NSRect)scaleAspectFillRect:(NSRect)destRect fromRect:(NSRect)sourceRect
{
NSSize sourceSize = sourceRect.size;
NSSize destSize = destRect.size;
CGFloat sourceAspect = sourceSize.width / sourceSize.height;
CGFloat destAspect = destSize.width / destSize.height;
NSRect cropRect = NSZeroRect;
if (sourceAspect > destAspect) { // source is proportionally wider than dest
cropRect.size.height = sourceSize.height;
cropRect.size.width = cropRect.size.height * destAspect;
cropRect.origin.x = (sourceSize.width - cropRect.size.width) / 2;
} else { // dest is proportionally wider than source (or they are equal)
cropRect.size.width = sourceSize.width;
cropRect.size.height = cropRect.size.width / destAspect;
cropRect.origin.y = (sourceSize.height - cropRect.size.height) / 2;
}
return cropRect;
}
- (void)drawScaledAspectFilledInRect:(NSRect)rect
{
NSRect imageRect = NSMakeRect(0, 0, [self size].width, [self size].height);
NSRect sourceRect = [self scaleAspectFillRect:rect fromRect:imageRect];
[[NSGraphicsContext currentContext]
setImageInterpolation:NSImageInterpolationHigh];
[self drawInRect:rect
fromRect:sourceRect
operation:NSCompositeSourceOver
fraction:1.0 respectFlipped:YES hints:nil];
}
@end
当我想将图像绘制到某个矩形中时,我调用:
[myImage drawScaledAspectFilledInRect:onScreenRect];
工作得很好,除了一个问题。在某些尺寸下,图像看起来很模糊:
我的第一个想法是我需要在整数像素上绘制,所以我在绘制之前使用了 NSIntegralRect()。没运气。
当我想到它时,我认为这可能是插值的结果。要从较大的图像绘制到较小的绘制矩形 NSImage 必须进行插值。模糊的图像可能只是值映射得不是很好的情况,我们最终会得到一些无法避免的不良伪影。
所以,问题是这样的:我如何选择一个避免这些伪影的最佳矩形?我可以在绘制之前调整绘制矩形或裁剪矩形以避免这种情况,但我不知道如何或何时调整它们。