垂直拼接/合成多个图像并保存为一个图像(iOS,objective-c)

时间:2012-08-01 05:13:53

标签: objective-c ios xcode image

我需要帮助编写一个Objective-c函数,该函数将接收一组UIImages / PNG,并返回/保存所有拼接在一起的图像的高图像。我是新手,所以请慢点放松一下:)

到目前为止我的想法: 画一个UIView,然后将子视图添加到每个人的父(图像中) 然后???

6 个答案:

答案 0 :(得分:20)

以下是将图像垂直或水平拼接在一起的Swift 3和Swift 2示例。它们使用调用者提供的数组中最大图像的尺寸来确定每个单独图像被拼接到的每个单独帧的常用尺寸。

注意:Swift 3示例保留了每个图像的宽高比,而Swift 2示例则没有。请参阅下面的内容注释。

更新:添加了Swift 3示例

斯威夫特3:

import UIKit
import AVFoundation

func stitchImages(images: [UIImage], isVertical: Bool) -> UIImage {
    var stitchedImages : UIImage!
    if images.count > 0 {
        var maxWidth = CGFloat(0), maxHeight = CGFloat(0)
        for image in images {
            if image.size.width > maxWidth {
                maxWidth = image.size.width
            }
            if image.size.height > maxHeight {
                maxHeight = image.size.height
            }
        }
        var totalSize : CGSize
        let maxSize = CGSize(width: maxWidth, height: maxHeight)
        if isVertical {
            totalSize = CGSize(width: maxSize.width, height: maxSize.height * (CGFloat)(images.count))
        } else {
            totalSize = CGSize(width: maxSize.width  * (CGFloat)(images.count), height:  maxSize.height)
        }
        UIGraphicsBeginImageContext(totalSize)
        for image in images {
            let offset = (CGFloat)(images.index(of: image)!)
            let rect =  AVMakeRect(aspectRatio: image.size, insideRect: isVertical ?
                            CGRect(x: 0, y: maxSize.height * offset, width: maxSize.width, height: maxSize.height) :
                            CGRect(x: maxSize.width * offset, y: 0, width: maxSize.width, height: maxSize.height))
            image.draw(in: rect)
        }
        stitchedImages = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    }
    return stitchedImages
}
  

注意:下面的原始Swift 2示例 not 保留   宽高比(例如,在Swift 2示例中,所有图像都扩展为   适合代表宽度和极值的边界框   图像的高度,因此可以拉伸任何非方形图像   不成比例地处于其中一个方面)。如果您使用的是Swift 2   并希望保留宽高比,请使用AVMakeRect()   从Swift 3示例中修改。因为我不再有访问权限   到Swift 2游乐场,无法测试它以确保没有错误我不是   为此更新Swift 2示例。

Swift 2 :(不保留宽高比。在上面的Swift 3示例中修复

import UIKit
import AVFoundation

func stitchImages(images: [UIImage], isVertical: Bool) -> UIImage {
    var stitchedImages : UIImage!
    if images.count > 0 {
        var maxWidth = CGFloat(0), maxHeight = CGFloat(0)
        for image in images {
            if image.size.width > maxWidth {
                maxWidth = image.size.width
            }
            if image.size.height > maxHeight {
                maxHeight = image.size.height
            }
        }
        var totalSize : CGSize, maxSize = CGSizeMake(maxWidth, maxHeight)
        if isVertical {
            totalSize = CGSizeMake(maxSize.width, maxSize.height * (CGFloat)(images.count))
        } else {
            totalSize = CGSizeMake(maxSize.width  * (CGFloat)(images.count), maxSize.height)
        }
        UIGraphicsBeginImageContext(totalSize)
        for image in images {
            var rect : CGRect, offset = (CGFloat)((images as NSArray).indexOfObject(image))
            if isVertical {
                rect = CGRectMake(0, maxSize.height * offset, maxSize.width, maxSize.height)
            } else {
                rect = CGRectMake(maxSize.width * offset, 0 , maxSize.width, maxSize.height)
            }
            image.drawInRect(rect)
        }
        stitchedImages = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
    }
    return stitchedImages
}

答案 1 :(得分:9)

通常的方法是创建位图图像上下文,在所需位置绘制图像,然后从图像上下文中获取图像。

您可以使用UIKit执行此操作,这有点容易,但不是线程安全的,因此需要在主线程中运行并阻止UI。

这里有很多示例代码,但是如果你想正确理解它,你应该看看UIGraphicsContextBeginImageContext,UIGraphicsGetCurrentContext,UIGraphicsGetImageFromCurrentImageContext和UIImageDrawInRect。不要忘记UIGraphicsPopCurrentContext。

你也可以使用Core Graphics,这是AFAIK,可以安全地在后台线程上使用(我还没有崩溃)。效率大致相同,因为UIKit只是在引擎盖下使用CG。 关键词是CGBitmapContextCreate,CGContextDrawImage,CGBitmapContextCreateImage,CGContextTranslateCTM,CGContextScaleCTM和CGContextRelease(核心图形没有ARC)。缩放和翻译是因为CG的右下角有原点而Y向上增加。

还有第三种方法,即使用CG作为上下文,但是通过使用CALayer保存自己所有的坐标疼痛,将CGImage(UIImage.CGImage)设置为内容,然后将图层渲染到上下文。这仍然是线程安全的,让图层处理所有的转换。关键字是 - renderInContext:

答案 2 :(得分:6)

我知道我在这里有点晚了,但希望这可以帮助别人。如果您尝试从阵列中创建一个大图像,则可以使用此方法

- (UIImage *)mergeImagesFromArray: (NSArray *)imageArray {

    if ([imageArray count] == 0) return nil;

    UIImage *exampleImage = [imageArray firstObject];
    CGSize imageSize = exampleImage.size;
    CGSize finalSize = CGSizeMake(imageSize.width, imageSize.height * [imageArray count]);

    UIGraphicsBeginImageContext(finalSize);

    for (UIImage *image in imageArray) {
        [image drawInRect: CGRectMake(0, imageSize.height * [imageArray indexOfObject: image],
                                      imageSize.width, imageSize.height)];
    }

    UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return finalImage;
}

答案 3 :(得分:2)

尝试这段代码,我尝试将两个图像拼接在一起,然后在ImageView中显示它们

UIImage *bottomImage = [UIImage imageNamed:@"bottom.png"]; //first image
UIImage *image       = [UIImage imageNamed:@"top.png"]; //foreground image

CGSize newSize = CGSizeMake(209, 260); //size of image view
UIGraphicsBeginImageContext( newSize );

// drawing 1st image
[bottomImage drawInRect:CGRectMake(0,0,newSize.width/2,newSize.height/2)];

// drawing the 2nd image after the 1st
[image drawInRect:CGRectMake(0,newSize.height/2,newSize.width/2,newSize.height/2)] ;

UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

join.image = newImage;   

join是imageview的名称,您可以将图像看作单个图像。

答案 4 :(得分:2)

上述解决方案很有帮助但对我来说存在严重缺陷。问题在于,如果图像具有不同的尺寸,则所得到的拼接图像将在部件之间具有潜在的大空间。我想出的解决方案将所有图像组合在一起,使其看起来更像是单个图像,无论单个图像大小如何。

适用于Swift 3.x

static func combineImages(images:[UIImage]) -> UIImage
{
    var maxHeight:CGFloat = 0.0
    var maxWidth:CGFloat = 0.0

    for image in images
    {
        maxHeight += image.size.height
        if image.size.width > maxWidth
        {
            maxWidth = image.size.width
        }
    }

    let finalSize = CGSize(width: maxWidth, height: maxHeight)

    UIGraphicsBeginImageContext(finalSize)

    var runningHeight: CGFloat = 0.0

    for image in images
    {
        image.draw(in: CGRect(x: 0.0, y: runningHeight, width: image.size.width, height: image.size.height))
        runningHeight += image.size.height
    }

    let finalImage = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

    return finalImage!
}

答案 5 :(得分:1)

雨燕4

extension Array where Element: UIImage {
    func stitchImages(isVertical: Bool) -> UIImage {

        let maxWidth = self.compactMap { $0.size.width }.max()
        let maxHeight = self.compactMap { $0.size.height }.max()

        let maxSize = CGSize(width: maxWidth ?? 0, height: maxHeight ?? 0)
        let totalSize = isVertical ?
            CGSize(width: maxSize.width, height: maxSize.height * (CGFloat)(self.count))
            : CGSize(width: maxSize.width  * (CGFloat)(self.count), height:  maxSize.height)
        let renderer = UIGraphicsImageRenderer(size: totalSize)

        return renderer.image { (context) in
            for (index, image) in self.enumerated() {
                let rect = AVMakeRect(aspectRatio: image.size, insideRect: isVertical ?
                    CGRect(x: 0, y: maxSize.height * CGFloat(index), width: maxSize.width, height: maxSize.height) :
                    CGRect(x: maxSize.width * CGFloat(index), y: 0, width: maxSize.width, height: maxSize.height))
                image.draw(in: rect)
            }
        }
    }
}