2012-07-29 12 views
7

Mam NSImageView, który zajmuje cały zakres okna. Nie ma obramowania widoku obrazu, a jego zestaw wyświetla się w lewym dolnym rogu. Oznacza to, że początek widoku jest zgodny z początkiem rzeczywistego obrazu, bez względu na to, jak zmienia się rozmiar okna.Uzyskiwanie ograniczeń NSImage w ramach NSImageView

Ponadto obraz jest znacznie większy niż to, co mogę rozsądnie zmieścić w pełnej skali na ekranie. Dlatego też mam ustawiony widok obrazu, aby proporcjonalnie zmniejszyć rozmiar obrazu. Jednak nie mogę znaleźć tego współczynnika skali w dowolnym miejscu.

Moim ostatecznym celem jest odwzorowanie zdarzenia w dół myszy na rzeczywiste współrzędne obrazu. Aby to zrobić, potrzebuję jeszcze jednej informacji ... jak duży jest wyświetlany NSImage.

Jeśli spojrzę na [imageView bounds], otrzymam prostokąt obwiedniowy widoku obrazu, który z reguły będzie większy niż obraz.

+0

Próbowałem tego. Ramki i obwiednie i tak dalej odnoszą się do obiektów typu NSView/NSWindow. Tak więc mogłem uzyskać ramkę ograniczającą samego widoku lub okna ... problem polega na tym, że NSImageView nie rysuje na wszystkich swoich granicach. Część widoku jest pusta. I potrzebuję albo ilości, o którą NSImageView przeskalował swój obraz, albo prostokąta, w którym faktycznie wciągnął ImageView (w przeciwieństwie do tego, co posiada) – wrjohns

+0

Na razie idę z obejściem, gdzie msgstr. uniemożliwia zmianę rozmiaru okna i usunięcie wszystkich innych elementów interfejsu użytkownika z okna (np. paska tytułu), dzięki czemu znam granice widoku = granice NSImageView = rozmiar rzeczywistego obrazu. – wrjohns

+0

NSImages nie ma ramek. One ** do ** mają rozmiary, ale rozmiar jest obrazu w pełnej skali, a nie rozmiaru, w którym są faktycznie rysowane. – wrjohns

Odpowiedz

2

Myślę, że to daje ci to, czego potrzebujesz:

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

która zwraca przesunięcie pochodzenia obrazu w widoku, a jego wielkość.

I skończyć cel remapping współrzędne myszy, coś takiego na swojej niestandardowej klasy widoku powinny pracować ...

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

Niestety ... pierwsza linia zakończyła się niepowodzeniem. Zanalizowałem wyliczony rect, a gdy zmieniłem rozmiar okna tak, że proporcje zmieniły się (ale obraz jest ustawiony tak, by rysować proporcjonalnie), granice imagecell pasowały do ​​granic okna, a nie do wyświetlanego obrazu. Zaczynam myśleć, że nie ma na to API. Co mogę zrobić, to obliczyć współczynnik proporcji oryginalnego, nieskalowanego obrazu ... i użyć go do obliczenia zasięgu obrazu w oknie o zmienionym rozmiarze – wrjohns

+0

Biorąc pod uwagę twój opis konfiguracji rzeczy, które mogą być poprawne.Reszta powyższego kodu oblicza przesunięcie w samym obrazie. Czy próbowałeś pozostałej części kodu? Robię dla ciebie bardzo podobną rzecz, z tym wyjątkiem, że mój widok i granice okien nie pasują do mojej granicy. Możesz nie potrzebować ostatecznego * = scaleFactor, ponieważ jest tam, ponieważ chcę współrzędne w przestrzeni obrazu (tj. .. w stosunku do rzeczywistego rozmiaru obrazu). – combinatorial

+0

Spróbowałem resztę kodu. Ale przy wyłączonym rysunkuRequest obliczona współrzędna również była wyłączona. Zdecydowałem się na 2 podejście do tego, co chcę: zaimplementować kilka metod z NSWindowDelegate i wymusić ręczne zmiany rozmiaru, aby zachować proporcje, a następnie w mojej metodzie mouseUp: mogę założyć, że rozmiar obrazu = rozmiar okna – wrjohns

0

Jak wskazano w powyższym komentarzu, oto podejście wziąłem:

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

    } 
} 

I w moim NSWindowController, który jest moje okno delegat na widok myszy, mam:

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

Ponieważ nie znalazłem żadnego rozwiązania, aby uzyskać realną ramkę obrazu wewnątrz NSImageView, zrobiłem obliczenia obrazu ręcznie, z poszanowaniem wszystkich jego właściwości (skalowanie, wyrównanie i obramowanie). Może to nie być najskuteczniejszy kod i mogą występować niewielkie odchylenia o 0,5-1 piksela od rzeczywistego obrazu, ale zbliża się on do oryginalnego obrazu (wiem, że to pytanie jest dość stare, ale rozwiązanie może pomóc innym):

@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