2012-07-29 18 views
7

ウィンドウの全範囲を占めるNSImageViewがあります。画像ビューには境界線がなく、左下に表示するように設定されています。つまり、ウィンドウのサイズがどのように変更されても、ビューの原点は実際のイメージの原点と一致します。NSImageView内のNSImageの境界を取得する

また、画像は、フルスケールで合理的に画面に収まるものよりもはるかに大きくなります。画像のサイズを比例的に縮小するように画像ビューを設定しました。しかし、私はどこにでもこのスケールファクターを見つけることができません。

私の究極の目標は、マウスのダウンイベントを実際の画像座標にマッピングすることです。これを行うには、もう1つの情報が必要だと思います...表示されたNSImageの実際の大きさはどれくらいですか?

私が[imageView bounds]を見ると、画像ビューの外接矩形が得られます。これは一般に画像よりも大きくなります。

+0

私はそれを試みました。フレームと境界などはすべてNSView/NSWindowタイプのオブジェクトに関連しています。だから私は、ビューまたはウィンドウ自体の境界フレームを取得することができます...問題は、NSImageViewがその境界のすべてを描画しないということです。ビューの一部が空白です。そして、私が必要とするのは、NSImageViewがイメージを縮小した量、またはImageViewが実際に描画された境界の矩形です(それが所有するものとは対照的に) – wrjohns

+0

今のところ、私は回避策を取りますウィンドウのサイズを変更できないようにして、タイトルバーのようなウィンドウから他のすべてのUI要素を取り除いて、スーパービューの境界= NSImageView境界=実際のイメージのサイズを知るようにします。 – wrjohns

+0

NSImagesにフレームがありません。彼らは**サイズ**を持っていますが、サイズは実際に描画されるサイズではなく、フルスケールのイメージです。 – wrjohns

答えて

2

は、私は、これはあなたが必要なものを与えることを考える:

ビュー内の画像の原点のオフセットを返し、それは大きさだ
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  
} 
+0

申し訳ありません...最初の行は機能しなくなりました。私はNSLogで計算された矩形を返し、アスペクト比が変更されるようにウィンドウのサイズを変更すると(ただし、イメージセルは比例して描画されるように設定されています)、イメージセルの境界は表示されたイメージではなくウィンドウの境界に一致します。私はこのためのAPI呼び出しがないと思っています。私ができることは、元の拡大されていない画像の縦横比を計算し、それを使ってサイズ変更されたウィンドウ内の画像の範囲を計算することです。 – wrjohns

+0

正しいものがどのように設定されているか説明します。上のコードの残りの部分は、画像自体へのオフセットを計算します。あなたはコードの残りの部分を試しましたか?私は境界線を持っているので私のビューとウィンドウの境界が一致しない以外はあなたに非常に似たようなことをしています。画像空間に座標を必要とするため(つまり、画像の実際のサイズに相対的に)、最終的な* = scaleFactorは必要ないかもしれません。 – combinatorial

+0

私は残りのコードを試しました。しかし、drawingRectをオフにすると、最終的な計算座標もオフになりました。 NSWindowDelegateからいくつかのメソッドを実装し、アスペクト比を保持するために手動でサイズ変更を強制してから、mouseUp:メソッドで画像サイズ=ウィンドウサイズを仮定することができます。 – wrjohns

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