我有一个占用窗口全部范围的NSImageView。图像视图没有边框,其设置显示在左下角。所以这意味着视图的原点与实际图像的原点相匹配,无论窗口的大小如何调整。
此外,图像比我在屏幕上完全适合的尺寸大得多。所以我也将imageview设置为按比例缩小图像的大小。但是,我似乎无法在任何地方找到这种比例因子。
我的最终目标是将鼠标按下事件映射到实际图像坐标。要做到这一点,我想我还需要一条信息......显示的NSImage实际上有多大。
如果我查看[imageView bounds]
,我会得到图像视图的边界矩形,通常会比图像大。
答案 0 :(得分:3)
我认为这可以满足您的需求:
NSRect imageRect = [imageView.cell drawingRectForBounds: imageView.bounds];
返回视图中图像原点的偏移量,以及它的大小。
为了您最终重新设置鼠标坐标的目标,您的自定义视图类中的此类内容应该可以正常工作...
- (void)mouseUp:(NSEvent *)event
{
NSPoint eventLocation = [event locationInWindow];
NSPoint location = [self convertPoint: eventLocation fromView: nil];
NSRect drawingRect = [self.cell drawingRectForBounds:self.bounds];
location.x -= drawingRect.origin.x;
location.y -= drawingRect.origin.y;
NSSize frameSize = drawingRect.size;
float frameAspect = frameSize.width/frameSize.height;
NSSize imageSize = self.image.size;
float imageAspect = imageSize.width/imageSize.height;
float scaleFactor = 1.0f;
if(imageAspect > frameAspect) {
///in this case image.width == frame.width
scaleFactor = imageSize.width / frameSize.width;
float imageHeightinFrame = imageSize.height / scaleFactor;
float imageOffsetInFrame = (frameSize.height - imageHeightinFrame)/2;
location.y -= imageOffsetInFrame;
} else {
///in this case image.height == frame.height
scaleFactor = imageSize.height / frameSize.height;
float imageWidthinFrame = imageSize.width / scaleFactor;
float imageOffsetInFrame = (frameSize.width - imageWidthinFrame)/2;
location.x -= imageOffsetInFrame;
}
location.x *= scaleFactor;
location.y *= scaleFactor;
//do something with you newly calculated mouse location
}
答案 1 :(得分:0)
正如我在上面的评论中指出的,这是我采取的方法:
// the view that mouseUp: is part of doesnt draw anything. I'm layering it
// in the window hierarchy to intercept mouse events. I suppose I could have
// subclassed NSImageView instead, but I went this route. isDragging is
// an ivar...its cleared in mouseDown: and set in mouseDragged:
// this view has no idea what the original unscaled image size is, so
// rescaling is done by caller
- (void)mouseUp:(NSEvent *)theEvent
{
if (!isDragging)
{
NSPoint rawPoint = [theEvent locationInWindow];
NSImageView *view = self.subviews.lastObject;
point = [self convertPoint:rawPoint fromView:view];
point.x /= view.bounds.size.width;
point.y /= view.bounds.size.height;
[owner mouseClick:point];
}
}
在我的NSWindowController中,我是鼠标视图的窗口委托,我有:
static int resizeMode=-1;
- (void)windowDidEndLiveResize:(NSNotification *)notification
{
if ([notification object]==frameWindow)
self.resizeFrameSelection=0;
resizeMode = -1;
}
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
{
if (sender==frameWindow)
{
float imageAspectRatio = (float)movie.movieSize.width / (float)movie.movieSize.height;
float newH = frameSize.height;
float newW = frameSize.width;
float currH = sender.frame.size.height;
float currW = sender.frame.size.width;
float deltaH = abs(newH-currH);
float deltaW = abs(newW-currW);
// lock onto one dimension to key off of, per drag.
if ( resizeMode==1 || (resizeMode==-1 && deltaW<deltaH ))
{
// adjust width to match aspect ratio
frameSize.width = frameSize.height * imageAspectRatio;
resizeMode=1;
}
else
{
// adjust height to match aspect ratio
frameSize.height = frameSize.width / imageAspectRatio;
resizeMode=2;
}
}
return frameSize;
}
答案 2 :(得分:0)
由于我还没有找到任何解决方案来获取NSImageView中的真实图像帧,我手动完成了图像计算,尊重其所有属性(缩放,对齐和边框)。这可能不是最有效的代码,并且可能与真实图像有0.5-1像素的微小偏差,但它与原始图像非常接近(我知道这个问题很老但是解决方案可能会帮助其他人):
@implementation NSImageView (ImageFrame)
// -------------------------------------------------------------------------
// -imageFrame
// -------------------------------------------------------------------------
- (NSRect)imageFrame
{
// Find the content frame of the image without any borders first
NSRect contentFrame = self.bounds;
NSSize imageSize = self.image.size;
NSImageFrameStyle imageFrameStyle = self.imageFrameStyle;
if (imageFrameStyle == NSImageFrameButton ||
imageFrameStyle == NSImageFrameGroove)
{
contentFrame = NSInsetRect(self.bounds, 2, 2);
}
else if (imageFrameStyle == NSImageFramePhoto)
{
contentFrame = NSMakeRect(contentFrame.origin.x + 1,
contentFrame.origin.y + 2,
contentFrame.size.width - 3,
contentFrame.size.height - 3);
}
else if (imageFrameStyle == NSImageFrameGrayBezel)
{
contentFrame = NSInsetRect(self.bounds, 8, 8);
}
// Now find the right image size for the current imageScaling
NSImageScaling imageScaling = self.imageScaling;
NSSize drawingSize = imageSize;
// Proportionally scaling
if (imageScaling == NSImageScaleProportionallyDown ||
imageScaling == NSImageScaleProportionallyUpOrDown)
{
NSSize targetScaleSize = contentFrame.size;
if (imageScaling == NSImageScaleProportionallyDown)
{
if (targetScaleSize.width > imageSize.width) targetScaleSize.width = imageSize.width;
if (targetScaleSize.height > imageSize.height) targetScaleSize.height = imageSize.height;
}
NSSize scaledSize = [self sizeByScalingProportionallyToSize:targetScaleSize fromSize:imageSize];
drawingSize = NSMakeSize(scaledSize.width, scaledSize.height);
}
// Axes independent scaling
else if (imageScaling == NSImageScaleAxesIndependently)
drawingSize = contentFrame.size;
// Now get the image position inside the content frame (center is default) from the current imageAlignment
NSImageAlignment imageAlignment = self.imageAlignment;
NSPoint drawingPosition = NSMakePoint(contentFrame.origin.x + contentFrame.size.width / 2.0 - drawingSize.width / 2.0,
contentFrame.origin.y + contentFrame.size.height / 2.0 - drawingSize.height / 2.0);
// NSImageAlignTop / NSImageAlignTopLeft / NSImageAlignTopRight
if (imageAlignment == NSImageAlignTop ||
imageAlignment == NSImageAlignTopLeft ||
imageAlignment == NSImageAlignTopRight)
{
drawingPosition.y = contentFrame.origin.y+contentFrame.size.height - drawingSize.height;
if (imageAlignment == NSImageAlignTopLeft)
drawingPosition.x = contentFrame.origin.x;
else if (imageAlignment == NSImageAlignTopRight)
drawingPosition.x = contentFrame.origin.x + contentFrame.size.width - drawingSize.width;
}
// NSImageAlignBottom / NSImageAlignBottomLeft / NSImageAlignBottomRight
else if (imageAlignment == NSImageAlignBottom ||
imageAlignment == NSImageAlignBottomLeft ||
imageAlignment == NSImageAlignBottomRight)
{
drawingPosition.y = contentFrame.origin.y;
if (imageAlignment == NSImageAlignBottomLeft)
drawingPosition.x = contentFrame.origin.x;
else if (imageAlignment == NSImageAlignBottomRight)
drawingPosition.x = contentFrame.origin.x + contentFrame.size.width - drawingSize.width;
}
// NSImageAlignLeft / NSImageAlignRight
else if (imageAlignment == NSImageAlignLeft)
drawingPosition.x = contentFrame.origin.x;
// NSImageAlignRight
else if (imageAlignment == NSImageAlignRight)
drawingPosition.x = contentFrame.origin.x + contentFrame.size.width - drawingSize.width;
return NSMakeRect(round(drawingPosition.x),
round(drawingPosition.y),
ceil(drawingSize.width),
ceil(drawingSize.height));
}
// -------------------------------------------------------------------------
// -sizeByScalingProportionallyToSize:fromSize:
// -------------------------------------------------------------------------
- (NSSize)sizeByScalingProportionallyToSize:(NSSize)newSize fromSize:(NSSize)oldSize
{
CGFloat widthHeightDivision = oldSize.width / oldSize.height;
CGFloat heightWidthDivision = oldSize.height / oldSize.width;
NSSize scaledSize = NSZeroSize;
if (oldSize.width > oldSize.height)
{
if ((widthHeightDivision * newSize.height) >= newSize.width)
{
scaledSize = NSMakeSize(newSize.width, heightWidthDivision * newSize.width);
} else {
scaledSize = NSMakeSize(widthHeightDivision * newSize.height, newSize.height);
}
} else {
if ((heightWidthDivision * newSize.width) >= newSize.height)
{
scaledSize = NSMakeSize(widthHeightDivision * newSize.height, newSize.height);
} else {
scaledSize = NSMakeSize(newSize.width, heightWidthDivision * newSize.width);
}
}
return scaledSize;
}
@end
答案 3 :(得分:0)
Swift 5 @Toby解决方案的实现
extension NSImageView {
/** Returns an `NSRect` of the drawn image in the view. */
func imageRect() -> NSRect {
// Find the content frame of the image without any borders first
var contentFrame = self.bounds
guard let imageSize = image?.size else { return .zero }
let imageFrameStyle = self.imageFrameStyle
if imageFrameStyle == .button || imageFrameStyle == .groove {
contentFrame = NSInsetRect(self.bounds, 2, 2)
} else if imageFrameStyle == .photo {
contentFrame = NSRect(x: contentFrame.origin.x + 1, y: contentFrame.origin.x + 2, width: contentFrame.size.width - 3, height: contentFrame.size.height - 3)
} else if imageFrameStyle == .grayBezel {
contentFrame = NSInsetRect(self.bounds, 8, 8)
}
// Now find the right image size for the current imageScaling
let imageScaling = self.imageScaling
var drawingSize = imageSize
// Proportionally scaling
if imageScaling == .scaleProportionallyDown || imageScaling == .scaleProportionallyUpOrDown {
var targetScaleSize = contentFrame.size
if imageScaling == .scaleProportionallyDown {
if targetScaleSize.width > imageSize.width { targetScaleSize.width = imageSize.width }
if targetScaleSize.height > imageSize.height { targetScaleSize.height = imageSize.height }
}
let scaledSize = self.sizeByScalingProportianlly(toSize: targetScaleSize, fromSize: imageSize)
drawingSize = NSSize(width: scaledSize.width, height: scaledSize.height)
}
// Axes independent scaling
else if imageScaling == .scaleAxesIndependently {
drawingSize = contentFrame.size
}
// Now get the image position inside the content frame (center is default) from the current imageAlignment
let imageAlignment = self.imageAlignment
var drawingPosition = NSPoint(x: contentFrame.origin.x + contentFrame.size.width / 2 - drawingSize.width / 2,
y: contentFrame.origin.y + contentFrame.size.height / 2 - drawingSize.height / 2)
// Top Alignments
if imageAlignment == .alignTop || imageAlignment == .alignTopLeft || imageAlignment == .alignTopRight {
drawingPosition.y = contentFrame.origin.y + contentFrame.size.height - drawingSize.height
if imageAlignment == .alignTopLeft {
drawingPosition.x = contentFrame.origin.x
} else if imageAlignment == .alignTopRight {
drawingPosition.x = contentFrame.origin.x + contentFrame.size.width - drawingSize.width
}
}
// Bottom Alignments
else if imageAlignment == .alignBottom || imageAlignment == .alignBottomLeft || imageAlignment == .alignBottomRight {
drawingPosition.y = contentFrame.origin.y
if imageAlignment == .alignBottomLeft {
drawingPosition.x = contentFrame.origin.x
} else if imageAlignment == .alignBottomRight {
drawingPosition.x = contentFrame.origin.x + contentFrame.size.width - drawingSize.width
}
}
// Left Alignment
else if imageAlignment == .alignLeft {
drawingPosition.x = contentFrame.origin.x
}
// Right Alginment
else if imageAlignment == .alignRight {
drawingPosition.x = contentFrame.origin.x + contentFrame.size.width - drawingSize.width
}
return NSRect(x: round(drawingPosition.x), y: round(drawingPosition.y), width: ceil(drawingSize.width), height: ceil(drawingSize.height))
}
func sizeByScalingProportianlly(toSize newSize: NSSize, fromSize oldSize: NSSize) -> NSSize {
let widthHeightDivision = oldSize.width / oldSize.height
let heightWidthDivision = oldSize.height / oldSize.width
var scaledSize = NSSize.zero
if oldSize.width > oldSize.height {
if (widthHeightDivision * newSize.height) >= newSize.width {
scaledSize = NSSize(width: newSize.width, height: heightWidthDivision * newSize.width)
} else {
scaledSize = NSSize(width: widthHeightDivision * newSize.height, height: newSize.height)
}
} else {
if (heightWidthDivision * newSize.width) >= newSize.height {
scaledSize = NSSize(width: widthHeightDivision * newSize.height, height: newSize.height)
} else {
scaledSize = NSSize(width: newSize.width, height: heightWidthDivision * newSize.width)
}
}
return scaledSize
}
}