gpt4 book ai didi

objective-c - 按比例缩放和旋转 NSImage 的 drawInRect

转载 作者:行者123 更新时间:2023-12-03 16:54:08 25 4
gpt4 key购买 nike

我试图绘制一个按比例缩放并旋转 90 度的 NSImage,但不断得到剪切的结果图像。

在 NSView 子类中,这是我当前所做的:

- (void) drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];

NSImage* image = /* get image */;

CGRect drawRect = dirtyRect;
CGRect imageRect = [self proportionallyScale:image.size toSize:drawRect.size];

NSAffineTransform* rotation = [[NSAffineTransform alloc] init];
[rotation translateXBy:NSWidth(drawRect) / 2 yBy:NSHeight(drawRect) / 2];
[rotation rotateByDegrees:90];
[rotation translateXBy:-NSWidth(drawRect) / 2 yBy:-NSHeight(drawRect) / 2];

NSGraphicsContext* context = [NSGraphicsContext currentContext];
[context saveGraphicsState];
[rotation concat];
[image drawInRect:imageRect fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
[context restoreGraphicsState];
}

以及缩放逻辑:

- (CGRect) proportionallyScale:(CGSize)fromSize toSize:(CGSize)toSize
{
CGPoint origin = CGPointZero;
CGFloat width = fromSize.width, height = fromSize.height;
CGFloat targetWidth = toSize.width, targetHeight = toSize.height;

float widthFactor = targetWidth / width;
float heightFactor = targetHeight / height;

CGFloat scaleFactor = std::min(widthFactor, heightFactor);

CGFloat scaledWidth = width * scaleFactor;
CGFloat scaledHeight = height * scaleFactor;

if (widthFactor < heightFactor)
origin.y = (targetHeight - scaledHeight) / 2.0;
else if (widthFactor > heightFactor)
origin.x = (targetWidth - scaledWidth) / 2.0;
return {origin, {scaledWidth, scaledHeight}};
}

这是未应用旋转的结果(图像不是正方形,渲染红色背景以显示 View 所在的位置):

No rotation applied

当我通过启用[rotation concat]来应用变换时:

Current code with 90 deg rotation applied

问题是图像的缩放及其偏移量应该相对于旋转的视口(viewport)大小而不是输入 View 边界来计算。然而我似乎无法想出正确计算这个的逻辑。

任何人都可以帮助正确计算缩放和旋转图像的正确图像绘制矩形的逻辑吗?或者有更好的方法来解决整个问题吗?

最佳答案

简短版本

添加:

imageRect.origin.x += NSWidth(drawRect) / 2 - NSHeight(drawRect) / 2;
imageRect.origin.y += NSHeight(drawRect) / 2 - NSWidth(drawRect) / 2;

drawRect中调用proportionallyScale之后

长版

我分两步完成:限制和缩放图像,然后在视口(viewport)中重新定位它。如果您想获得所有奇特的效果,您可以将它们组合起来。我认为这应该适用于各种 View 尺寸。

这是我们最初的观点:

********************
* *
* View * 6
* *
* *
X*******************
20

左下角的原点被标记为X

假设图像大小为 6 x 8(旋转之前)。

第一部分很简单,确定旋转时我们应该绘制多大的图像。只需将翻转尺寸传递给 proportionallyScale:

CGRect imageRect = [self
proportionallyScale:image.size
toSize:CGSizeMake(
drawRect.size.height, // 6
drawRect.size.width) // 20
];

这会产生一个矩形:

imageRect = { origin=(x=0, y=6) size=(width=6, height=8) };

但这目前没有多大意义:

  6
$$$$$$
$ $
$ $
$ IM $ 8
$ $
$ $
$ $
X$$$$$**************
* *
* View * 6
* *
* *
X*******************
20

然后将 View 绕中心顺时针旋转 90 度:

                        8
X++++X$$$$$$$$ -
+ + $ |
Rot'd View >-- + $ IM $ |
+ + $ 6 | 7
+ $ $ |
+ +$$$$$$$$ |
*******+****+******* -
* VP + + * |
* + + * | 6
* + + * |
* + + * |
X******+****+******* -
+ + |
+ + |
+ + |
+ + | 7
+ + |
++++++ -

|------|----|------|
7 6 7

VP 是原始 View 的位置。我们需要将原点从旋转空间变换到原始视口(viewport)空间。

这个变换可以计算为:

// note that drawRect hasn't been flipped here
CGFloat transX = NSWidth(drawRect) / 2 - NSHeight(drawRect) / 2 == 7;
CGFloat transY = NSHeight(drawRect) / 2 - NSWidth(drawRect) / 2 == -7

因此我们将变换应用于当前图像:

imageRect.origin.x += transX;
imageRect.origin.y += transY;

此转换产生:

               X++++X
+ +
+ +
+ +
+ +
+ +
******$+$$$$+$******
* VP $+ +$ *
* $+ +$ *
* $+ +$ *
* $+ +$ *
X*****$+$$$$+$******
+ +
+ +
+ +
+ +
+ +
++++++

现在一切都很好地定位和缩放:

           6     8      6
|-----|------|-----|

******$$$$$$$$****** -
* $ $ * |
* $ $ * | 6
* $ $ * |
* $ $ * |
X*****$$$$$$$$****** -

至少在下一个黑暗邪恶力量到来之前......

关于objective-c - 按比例缩放和旋转 NSImage 的 drawInRect,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27760601/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com