2012-07-29 16 views
7

Tengo un NSImageView que ocupa toda la extensión de una ventana. No hay borde en la vista de la imagen, y está configurado para mostrarse en la esquina inferior izquierda. Por lo tanto, esto significa que el origen de la vista coincide con el origen de la imagen real, sin importar cómo se cambie el tamaño de la ventana.Obtener los límites de un NSImage dentro de un NSImageView

Además, la imagen es mucho más grande de lo que razonablemente puedo ajustar a escala completa en la pantalla. Así que también tengo la vista de la imagen configurada para reducir proporcionalmente el tamaño de la imagen. Sin embargo, parece que no puedo encontrar este factor de escala en ninguna parte.

Mi objetivo final es asignar un evento de mouse hacia abajo en las coordenadas de la imagen real. Para hacer esto, creo que necesito una información más ... cuán grande es en realidad el NSImage que se muestra.

Si miro el [imageView bounds], aparece el rectángulo delimitador de la vista de la imagen, que generalmente será más grande que la imagen.

+0

Lo he intentado. Los marcos, los límites, etc. son todos relativos a los objetos de tipo NSView/NSWindow. Así que pude obtener el marco delimitador de la vista o la ventana en sí ... el problema es que NSImageView no utiliza todos sus límites. Parte de la vista está en blanco. Y lo que necesito es la cantidad por la cual el NSImageView redujo su imagen, o el rectángulo delimitador de donde realmente se dibujó ImageView (en comparación con lo que posee) – wrjohns

+0

Por ahora, voy con una solución alternativa, donde No se permite el cambio de tamaño de la ventana y se eliminan todos los otros elementos de la interfaz de usuario de la ventana (como la barra de título), de modo que conozco los límites de SuperView = NSImageView bounds = el tamaño de la imagen real. – wrjohns

+0

NSImages no tiene marcos. ** Tienen ** tamaños, pero el tamaño es de la imagen a escala completa, no del tamaño en el que realmente están dibujados. – wrjohns

Respuesta

2

creo que esto le da lo que necesita:

NSRect imageRect = [imageView.cell drawingRectForBounds: imageView.bounds]; 

que devuelve el desplazamiento del origen de la imagen dentro de la vista, y su tamaño.

Y para terminas objetivo de reasignación de las coordenadas del ratón, algo como esto en la clase de vista personalizado deberían trabajar ...

- (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

Lo siento ... la primera línea terminó no funcionaba. I NSLog'ed el rect computado, y como cambié el tamaño de la ventana de modo que la relación de aspecto cambió (pero la celda de imagen se establece para dibujar proporcionalmente), los límites de la celda de imagen coincidían con los límites de la ventana, no la imagen mostrada. Estoy empezando a pensar que no hay una llamada API para esto. Lo que podría hacer es calcular la relación de aspecto de la imagen original sin escalar ... y usar eso para calcular la extensión de la imagen en la ventana redimensionada – wrjohns

+0

Dada la descripción que tiene de cómo se han configurado las cosas que podrían ser correctas.El resto del código anterior calcula el desplazamiento en la imagen misma. ¿Has probado el resto del código? Estoy haciendo algo muy similar a ti, excepto que mi vista y los límites de la ventana no coinciden, ya que tengo un borde. Es posible que no necesite el * scaleFactor final porque está allí porque quiero las coordenadas en el espacio de la imagen (es decir ... relativo al tamaño real de la imagen). – combinatorial

+0

Probé el resto del código. Pero con drawingRect desactivado, la coordenada calculada final también estaba desactivada. Decidí un enfoque de dos frentes para lo que deseo: implementar algunos métodos de NSWindowDelegate y forzar cualquier cambio de tamaño manual para conservar la relación de aspecto, y luego en mi método mouseUp: puedo asumir que size = tamaño de ventana – wrjohns

0

Como indiqué en un comentario anterior, aquí está el enfoque Tomé:

// 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]; 

    } 
} 

Y en mi NSWindowController, que es la ventana de mi delegado para la vista de ratón, que tengo:

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

Como todavía no he encontrado ninguna solución para obtener el marco de imagen real dentro de NSImageView, hice el cálculo de imagen manualmente, respetando todas sus propiedades (escala, alineación y borde). Puede que este no sea el código más eficiente y puede haber desviaciones menores de 0,5-1 píxeles de la imagen real, pero está muy cerca de la imagen original (sé que esta pregunta es bastante antigua pero la solución podría ayudar a otros):

@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 
Cuestiones relacionadas