在两个轴上翻转NSImage

8

我正在尝试翻转使用NSImageBitmapRep表示的NSImage。经过一些搜索( Flipping Quicktime preview & captureMirroring CIImage/NSImage),我尝试了两种方法,一种是通过CIImage进行并应用缩放变换,使用两个因子的值为-1。

首先是使用CIImage的imageByApplyingTransform:

    NSBitmapImageRep *imgRep = ...
    CGImageRef cgi = [imgRep CGImage];
    CIImage *cii = [CIImage imageWithCGImage:cgi];
    CGAffineTransform at = CGAffineTransformTranslate(CGAffineTransformMakeScale(-1, -1), 0, 0);
    NSCIImageRep *ciiRep = [NSCIImageRep imageRepWithCIImage:[cii imageByApplyingTransform:at]];

    NSImage *img = [[[NSImage alloc] init] autorelease];
    [img addRepresentation:ciiRep];
    [self.ivImage setImage:img];

然后使用CIAffineTransform滤镜:

    NSBitmapImageRep *imgRep = ...
    CGImageRef cgi = [imgRep CGImage];
    CIImage *cii = [CIImage imageWithCGImage:cgi];
    CIFilter *f = [CIFilter filterWithName:@"CIAffineTransform"];
    NSAffineTransform *t = [NSAffineTransform transform];
    [t scaleXBy:1.0 yBy:1.0];
    //[t translateXBy:width yBy:0];
    [f setValue:t forKey:@"inputTransform"];
    [f setValue:cii forKey:@"inputImage"];
    CIImage *cii2 = [f valueForKey:@"outputImage"];
    NSCIImageRep *ciiRep = [NSCIImageRep imageRepWithCIImage:cii2];

    NSImage *img = [[[NSImage alloc] init] autorelease];
    [img addRepresentation:ciiRep];
    [self.ivImage setImage:img];

两种方法都会生成空白图像。我也尝试过翻译图像,以防它因为-1缩放而在屏幕外,但没有成功。如果我使用正值进行缩放,我可以看到变换被正确应用。self.ivImage是一个NSImageView。我想要一个实际上被翻转的NSImage,所以对NSImageView应用变换不是一个选项。这是32位的,Xcode 4.3.2在Lion上。
4个回答

10

你应该使用一个大小来初始化你的NSImage

展示你的翻译尝试,因为这是正确的方式。通常情况下,先翻译再缩放是最容易的。你的代码片段似乎有些历史遗迹式的翻译尝试,但不正确。一个案例中你将其翻译为0,0,而在另一个案例中你将其翻译为宽度,0。此外,在第二个代码片段中,你正在通过1,1(正数)进行缩放,所以没有翻转。

另外,可能更简单的方法是在适当大小的新图像上锁定焦点,设置变换,然后绘制图像。避免了所有那些与CIImage相关的麻烦。

NSBitmapImageRep *imgRep = ...
NSImage* img = [[[NSImage alloc] initWithSize:NSMakeSize(imgRep.pixelsWide, imgRep.pixelsHigh)] autorelease];
[img lockFocus];
NSAffineTransform* t = [NSAffineTransform transform];
[t translateXBy:imgRep.pixelsWide yBy:imgRep.pixelsHigh];
[t scaleXBy:-1 yBy:-1];
[t concat];
[imgRep drawInRect:NSMakeRect(0, 0, imgRep.pixelsWide, imgRep.pixelsHigh)];
[img unlockFocus];

1
谢谢,它直接就能运行了! :) 而且没有经过 CIImage 的绕路,更加简洁!我的翻译和正向缩放的尝试是为了测试是否应用了变换。 - msohn

8

无论如何,我认为一个好主意是发布完整的函数。这是基于Ken帖子的解决方案。

- (NSImage *)flipImage:(NSImage *)image
{
    NSImage *existingImage = image;
    NSSize existingSize = [existingImage size];
    NSSize newSize = NSMakeSize(existingSize.width, existingSize.height);
    NSImage *flipedImage = [[[NSImage alloc] initWithSize:newSize] autorelease];

    [flipedImage lockFocus];
    [[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];

    NSAffineTransform *t = [NSAffineTransform transform];
    [t translateXBy:existingSize.width yBy:existingSize.height];
    [t scaleXBy:-1 yBy:-1];
    [t concat];

    [existingImage drawAtPoint:NSZeroPoint fromRect:NSMakeRect(0, 0, newSize.width, newSize.height) operation:NSCompositeSourceOver fraction:1.0];

    [flipedImage unlockFocus];

    return flipedImage;
}

7

基于 Alejandro Lugeno 的解决方案的 Swift 扩展:

extension NSImage {
    func flipped(flipHorizontally: Bool = false, flipVertically: Bool = false) -> NSImage {
        let flippedImage = NSImage(size: size)

        flippedImage.lockFocus()

        NSGraphicsContext.current?.imageInterpolation = .high

        let transform = NSAffineTransform()
        transform.translateX(by: flipHorizontally ? size.width : 0, yBy: flipVertically ? size.height : 0)
        transform.scaleX(by: flipHorizontally ? -1 : 1, yBy: flipVertically ? -1 : 1)
        transform.concat()

        draw(at: .zero, from: NSRect(origin: .zero, size: size), operation: .sourceOver, fraction: 1)

        flippedImage.unlockFocus()

        return flippedImage
    }
}

size 定义在哪里?你没有传递它。 - Houman
1
@Houman NSImage有一个size属性:https://developer.apple.com/documentation/appkit/nsimage/1519987-size 由于该函数在NSImage扩展中,因此不必传递它。 - Tamás Sengel
1
简单来说:这里的 sizeself.size 的缩写。 - Tamás Sengel

4

垂直翻转

- (NSImage *)flipImageVertically:(NSImage *)inputImage {

    NSImage *tmpImage;
    NSAffineTransform *transform = [NSAffineTransform transform];

    NSSize dimensions = [inputImage size];
    NSAffineTransformStruct flip = {1.0, 0.0, 0.0, -1.0, 0.0,
        dimensions.height};
    tmpImage = [[NSImage alloc] initWithSize:dimensions];
    [tmpImage lockFocus];
    [transform setTransformStruct:flip];
    [transform concat];
    [inputImage drawAtPoint:NSMakePoint(0,0)
                         fromRect:NSMakeRect(0,0, dimensions.width, dimensions.height)
                        operation:NSCompositeCopy fraction:1.0];
    [tmpImage unlockFocus];


    return [tmpImage autorelease];

}

水平翻转

+ (NSImage *)flipImageHorizontally:(NSImage *)inputImage {

    NSImage *tmpImage;
    NSAffineTransform *transform = [NSAffineTransform transform];

    NSSize dimensions = [inputImage size];
    NSAffineTransformStruct flip = {-1.0, 0.0, 0.0, 1.0,
        dimensions.width, 0.0 };
    tmpImage = [[NSImage alloc] initWithSize:dimensions];
    [tmpImage lockFocus];
    [transform setTransformStruct:flip];
    [transform concat];
    [inputImage drawAtPoint:NSMakePoint(0,0)
                         fromRect:NSMakeRect(0,0, dimensions.width, dimensions.height)
                        operation:NSCompositeCopy fraction:1.0];
    [tmpImage unlockFocus];

    return [tmpImage autorelease];

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接