以任意角度旋转NSImage并支持Retina显示

时间:2014-08-13 10:03:22

标签: macos cocoa retina-display nsimage

我需要将NSImage旋转任意角度。对于我的应用程序的iOS版本,我从互联网上找到的几个来源一起攻击了以下解决方案:

@implementation UIImage (ut_rotate)

- (instancetype)imageRotatedByDegrees:(CGFloat)degrees{
    CGFloat scale   = [UIScreen mainScreen].scale; // support retina displays
    float newSide   = self.size.width; // square img
    CGSize size     =  CGSizeMake(newSide, newSide);
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGAffineTransform transform = CGAffineTransformIdentity;
    transform = CGAffineTransformTranslate(transform, newSide/2.0f, newSide/2.0f);
    transform = CGAffineTransformRotate(transform, _heading * M_PI/180.0);
    transform = CGAffineTransformScale(transform, 1.0, -1.0);
    CGContextConcatCTM(context, transform);
    CGContextDrawImage(context, CGRectMake(-newSide/2.0f, -newSide/2.0f, newSide, newSide), _image.CGImage);

    return [UIImage imageWithCGImage: CGBitmapContextCreateImage(context) scale:scale orientation:UIImageOrientationUp];
}
@end

请注意,此黑客支持视网膜显示。

对于Cocoa,我在其中一个互联网上找到了规范解决方案:

@implementation NSImage (ut_rotate)

- (NSImage*)imageRotatedByDegrees:(CGFloat)degrees {
    // Calculate the bounds for the rotated image
    // We do this by affine-transforming the bounds rectangle
    NSRect imageBounds = {NSZeroPoint, [self size]};
    NSBezierPath* boundsPath = [NSBezierPath bezierPathWithRect:imageBounds];
    NSAffineTransform* transform = [NSAffineTransform transform];
    [transform rotateByDegrees:-1.0 * degrees];// we want clockwise angles
    [boundsPath transformUsingAffineTransform:transform];
    NSRect rotatedBounds = {NSZeroPoint, [boundsPath bounds].size};
    NSImage* rotatedImage = [[NSImage alloc] initWithSize:rotatedBounds.size] ;

    // Center the image within the rotated bounds
    imageBounds.origin.x = NSMidX(rotatedBounds) - (NSWidth(imageBounds) / 2);
    imageBounds.origin.y = NSMidY(rotatedBounds) - (NSHeight(imageBounds) / 2);

    // Start a new transform, to transform the image
    transform = [NSAffineTransform transform];

    // Move coordinate system to the center
    // (since we want to rotate around the center)
    [transform translateXBy:+(NSWidth(rotatedBounds) / 2)
                        yBy:+(NSHeight(rotatedBounds) / 2)];
    // Do the rotation
    [transform rotateByDegrees:-1.0 * degrees];
    // Move coordinate system back to normal (bottom, left)
    [transform translateXBy:-(NSWidth(rotatedBounds) / 2)
                        yBy:-(NSHeight(rotatedBounds) / 2)];

    // Draw the original image, rotated, into the new image
    // Note: This "drawing" is done off-screen.
    [rotatedImage lockFocus];
    [transform concat];
    [self drawInRect:imageBounds fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0] ;
    [rotatedImage unlockFocus];

    return rotatedImage;

}
@end

问题是:a)结果在非视网膜显示器上看起来模糊b)不支持视网膜。

我发现在lockFocusunlockFocus之间使用block-based drawing methods代替代码,但却不理解。

我正在寻找能够产生更清晰图像并支持视网膜的解决方案。根据我的需要,OS X 10.9及更高版本只支持平方源图像。

2 个答案:

答案 0 :(得分:0)

这是完全未经测试但可能有效:

@implementation NSImage (ut_rotate)

- (NSImage*)imageRotatedByDegrees:(CGFloat)degrees {
    // Calculate the bounds for the rotated image
    // We do this by affine-transforming the bounds rectangle
    NSRect imageBounds = {NSZeroPoint, [self size]};
    NSBezierPath* boundsPath = [NSBezierPath bezierPathWithRect:imageBounds];
    NSAffineTransform* transform = [NSAffineTransform transform];
    [transform rotateByDegrees:-1.0 * degrees];// we want clockwise angles
    [boundsPath transformUsingAffineTransform:transform];
    NSRect rotatedBounds = {NSZeroPoint, [boundsPath bounds].size};

    // Center the image within the rotated bounds
    imageBounds.origin.x = NSMidX(rotatedBounds) - (NSWidth(imageBounds) / 2);
    imageBounds.origin.y = NSMidY(rotatedBounds) - (NSHeight(imageBounds) / 2);

    NSImage* rotatedImage = [NSImage imageWithSize:rotatedBounds.size flipped:NO drawingHandler:^BOOL (NSRect dstRect){
        // Start a new transform, to transform the image
        NSAffineTransform* transform = [NSAffineTransform transform];

        // Move coordinate system to the center
        // (since we want to rotate around the center)
        [transform translateXBy:+(NSWidth(rotatedBounds) / 2)
                            yBy:+(NSHeight(rotatedBounds) / 2)];
        // Do the rotation
        [transform rotateByDegrees:-1.0 * degrees];
        // Move coordinate system back to normal (bottom, left)
        [transform translateXBy:-(NSWidth(rotatedBounds) / 2)
                            yBy:-(NSHeight(rotatedBounds) / 2)];

        // Draw the original image, rotated, into the new image
        [transform concat];
        [self drawInRect:imageBounds fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
        return YES;
    }];

    return rotatedImage;

}
@end

答案 1 :(得分:0)

我对NSImage的扩展,适用于所有学位

getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);