I'm trying to draw a NSImage proportionally scaled and rotated 90 degrees but keep getting a clipped resulting image.
In the NSView subclass, Here's what I currently do:
- (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];
}
And the scaling logic:
- (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}};
}
Here's the result with no rotation applied (the image is not square, the red background is rendered to show where the view is):
And when I apply the transform by enabling [rotation concat]
:
The problem being that the scaling of the image and its offset should be computed relative to the rotated viewport size and not the input view bounds. However I can't seem to come up with the logic that computes this correctly.
Can anyone please help with the logic that properly computes the correct image drawing rect for the scaled and rotated image? Or is there a better approach to the whole problem?