沿任一轴翻转UIImage

4

我正在尝试创建一个方法,可以沿着X轴、Y轴或同时沿着两个轴翻转UIImage。我已经接近成功,但我的变换知识不够好以致于无法完全实现。这是我目前的代码:

- (UIImage *)flippedImageByAxis:(MVImageFlip)axis{
     UIGraphicsBeginImageContext(self.size);
     CGContextRef context = UIGraphicsGetCurrentContext();
     CGAffineTransform verticalFlip = CGAffineTransformMake(1, 0, 0, -1, 0, self.size.height);
     CGAffineTransform horizFlip = CGAffineTransformMake(-1.0, 0.0, 0.0, 1.0, self.size.width, 0.0);

     if(axis == MVImageFlipXAxis || axis == MVImageFlipXAxisAndYAxis)
         CGContextConcatCTM(context, horizFlip);
     if(axis == MVImageFlipYAxis || axis == MVImageFlipXAxisAndYAxis)
         CGContextConcatCTM(context, verticalFlip);

     CGContextDrawImage(context, CGRectMake(0.0, 0.0, self.size.width, self.size.height), [self CGImage]);

     UIImage *flipedImage = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();

     return flipedImage;
 }

这个操作可以翻转图像,但并不完全正确。Y轴翻转的图像根本没有被翻转,X轴翻转的图像看起来像XY图像应该看起来的样子,而XY图像则像Y轴图像应该看起来的样子。将这些变换组合起来并使它们正常工作让我感到头疼。

MVImageFlip枚举只是代码中看到的三种情况,没有什么特别之处。

5个回答

25

我最终终于弄清楚了。这是适用于任何其他需要的人的代码。

- (UIImage *)flippedImageByAxis:(MVImageFlip)axis{
    UIGraphicsBeginImageContext(self.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    if(axis == MVImageFlipXAxis){
        // Do nothing, X is flipped normally in a Core Graphics Context
    } else if(axis == MVImageFlipYAxis){
        // fix X axis
        CGContextTranslateCTM(context, 0, self.size.height);
        CGContextScaleCTM(context, 1.0f, -1.0f);

        // then flip Y axis
        CGContextTranslateCTM(context, self.size.width, 0);
        CGContextScaleCTM(context, -1.0f, 1.0f);
    } else if(axis == MVImageFlipXAxisAndYAxis){
        // just flip Y
        CGContextTranslateCTM(context, self.size.width, 0);
        CGContextScaleCTM(context, -1.0f, 1.0f);
    }

    CGContextDrawImage(context, CGRectMake(0.0, 0.0, self.size.width, self.size.height), [self CGImage]);

    UIImage *flipedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return flipedImage;
}

我更喜欢在这种情况下使用图像缩放:UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale); - Jakub Truhlář

9

请尝试以下方法:

UIImage* myimage = [UIImage imageNamed: @"myimage.png"];
myimage = [UIImage imageWithCGImage: myimage.CGImage scale: 1.0f orientation: UIImageOrientationUpMirrored];

4
我之前找到了这段代码并尝试过,但它没有起作用,生成的UIImages与输入的完全相同。我会再试一次以确保。 - Cory Imdieke
1
刚刚又试了一遍,仍然没有任何反应。非常奇怪。 - Cory Imdieke
6
正确的参数是 UIImageOrientationDownMirroredUIImageOrientationDown,可以将图片翻转到头部。文档链接:这里 - Engin Kurutepe

7

如果你只是想显示图片而不保存它,那么你可能不需要创建第二个CGContext。更有效的方法是直接使用UIImage中已经加载好的CGImage,并像下面这样改变方向:

- (UIImage *)flippedImageByFlippingAlongXAxis:(BOOL)flipOnX andAlongYAxis:(BOOL)flipOnY
{
    UIImageOrientation currentOrientation = self.imageOrientation;
    UIImageOrientation newOrientation = currentOrientation;

    if (flipOnX == YES) {
        switch (newOrientation) {
            case UIImageOrientationUp:
                newOrientation = UIImageOrientationUpMirrored;
                break;
            case UIImageOrientationDown:
                newOrientation = UIImageOrientationMirrored;
                break;
            case UIImageOrientationUpMirrored:
                newOrientation = UIImageOrientationUp;
                break;
            case UIImageOrientationDownMirrored:
                newOrientation = UIImageOrientationDown;
                break;
            case UIImageOrientationLeft:
                newOrientation = UIImageOrientationLeftMirrored;
                break;
            case UIImageOrientationRight:
                newOrientation = UIImageOrientationRightMirrored;
                break;
            case UIImageOrientationLeftMirrored:
                newOrientation = UIImageOrientationLeft;
                break;
            case UIImageOrientationRightMirrored:
                newOrientation = UIImageOrientationRight;
                break;
        }
    }

    if (flipOnY == YES) {
        switch (newOrientation) {
            case UIImageOrientationUp:
                newOrientation = UIImageOrientationDownMirrored;
                break;
            case UIImageOrientationDown:
                newOrientation = UIImageOrientationUpMirrored;
                break;
            case UIImageOrientationUpMirrored:
                newOrientation = UIImageOrientationDown;
                break;
            case UIImageOrientationDownMirrored:
                newOrientation = UIImageOrientationUp;
                break;
            case UIImageOrientationLeft:
                newOrientation = UIImageOrientationRightMirrored;
                break;
            case UIImageOrientationRight:
                newOrientation = UIImageOrientationLeftMirrored;
                break;
            case UIImageOrientationLeftMirrored:
                newOrientation = UIImageOrientationRight;
                break;
            case UIImageOrientationRightMirrored:
                newOrientation = UIImageOrientationLeft;
                break;
        }
    }

    return [UIImage imageWithCGImage:self.CGImage scale:self.scale orientation:newOrientation];
}

当你开始一个新的CGContext并使用CGContextDrawImage进行翻转时,你会分配另一个内存块来保存以不同顺序的相同字节。通过改变UIImage的方向,您可以避免另一个分配。相同的图像数据被使用,只是以不同的方向绘制。


这篇文章有点老,但我想发表一下评论。在我的特定问题中,我确实需要保存图像。无论如何,这是一个好建议,如果图像只用于显示,则更有效率。 - Cory Imdieke
1
我喜欢这个答案,也喜欢重复使用CGContext,因为我只显示图片。但是现在它是不正确的。然而,在Swift中将.Up更改为.Down.LeftMirrored更改为.RightMirrored实际上是进行了180度旋转,因此每个开关中的4个情况都没有反射。要在上面的示例中修复它,您只需确保对于每种情况,始终添加或删除“Mirrored”。我会添加另一个Swift答案以完整性。 - fresidue
修正了答案。 - Borzh

2
这只是原来由@ ultramiraculous提供的答案的稍微修正并“更新为Swift”版本,以防对某人有所帮助。
垂直翻转(相对于x轴的反射):
func flipV(im:UIImage)->UIImage {
    var newOrient:UIImageOrientation
    switch im.imageOrientation {
    case .Up:
        newOrient = .DownMirrored
    case .UpMirrored:
        newOrient = .Down
    case .Down:
        newOrient = .UpMirrored
    case .DownMirrored:
        newOrient = .Up
    case .Left:
        newOrient = .LeftMirrored
    case .LeftMirrored:
        newOrient = .Left
    case .Right:
        newOrient = .RightMirrored
    case .RightMirrored:
        newOrient = .Right
    }
    return UIImage(CGImage: im.CGImage, scale: im.scale, orientation: newOrient)
}

水平翻转(沿y轴对称)

func flipH(im:UIImage)->UIImage {
    var newOrient:UIImageOrientation
    switch im.imageOrientation {
    case .Up:
        newOrient = .UpMirrored
    case .UpMirrored:
        newOrient = .Up
    case .Down:
        newOrient = .DownMirrored
    case .DownMirrored:
        newOrient = .Down
    case .Left:
        newOrient = .RightMirrored
    case .LeftMirrored:
        newOrient = .Right
    case .Right:
        newOrient = .LeftMirrored
    case .RightMirrored:
        newOrient = .Left
    }
    return UIImage(CGImage: im.CGImage, scale: im.scale, orientation: newOrient)
}

0

Swift 3 版本:

func flipV(im:UIImage)->UIImage {
        var newOrient:UIImageOrientation
        switch im.imageOrientation {
        case .up:
            newOrient = .downMirrored
        case .upMirrored:
            newOrient = .down
        case .down:
            newOrient = .upMirrored
        case .downMirrored:
            newOrient = .up
        case .left:
            newOrient = .leftMirrored
        case .leftMirrored:
            newOrient = .left
        case .right:
            newOrient = .rightMirrored
        case .rightMirrored:
            newOrient = .right
        }
        return UIImage(cgImage: im.cgImage!, scale: im.scale, orientation: newOrient)
    }

    func flipH(im:UIImage)->UIImage {
        var newOrient:UIImageOrientation
        switch im.imageOrientation {
        case .up:
            newOrient = .upMirrored
        case .upMirrored:
            newOrient = .up
        case .down:
            newOrient = .downMirrored
        case .downMirrored:
            newOrient = .down
        case .left:
            newOrient = .rightMirrored
        case .leftMirrored:
            newOrient = .right
        case .right:
            newOrient = .leftMirrored
        case .rightMirrored:
            newOrient = .left
        }
        return UIImage(cgImage: im.cgImage!, scale: im.scale, orientation: newOrient)
    }

2
请不要提供仅包含代码的答案。您应该详细说明您的方法。这有助于其他用户更好地理解您的解决方案。 - LarsBauer

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