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

我需要帮助写一个objective-c函数,将采取一系列UIImages / PNGs,并返回/保存所有图像垂直顺序拼接在一起的高图像。 我是新来的,所以请慢下来,放轻松:)

我的想法到目前为止:绘制一个UIView,然后addSubviews每个人的父母(的图像),然后?

正常的方法是创build一个位图图像上下文,在所需的位置绘制图像,然后从图像上下文获取图像。

你可以使用UIKit来做到这一点,这是比较容易,但不是线程安全的,所以将需要在主线程中运行,并将阻止用户界面。

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

你也可以使用核心graphics,这是AFAIK,安全地使用后台线程(我还没有从它的崩溃)做到这一点。 效率大致相同,因为UIKit只是使用CG引擎。 关键词是CGBitmapContextCreate,CGContextDrawImage,CGBitmapContextCreateImage,CGContextTranslateCTM,CGContextScaleCTM和CGContextRelease(没有ARC for Core Graphics)。 缩放和翻译是因为CG的起点在右下angular,Y向上。

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

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

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

更新:增加了Swift 3的例子

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 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例子并不保留宽高比(例如,在Swift 2例子中,所有图像都被展开以适合表示图像宽度和高度极值的边界框,因此任何非方形图像可以在其一个维度上不成比例地拉长)。 如果您使用的是Swift 2,并且想要保留宽高比,请使用Swift 3示例中的AVMakeRect()修改。 由于我不再能够访问Swift 2游乐场,并且无法testing它以确保没有错误,所以我没有更新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 } 

我知道我在这里有点晚了,但希望这可以帮助别人。 如果你想从数组中创build一个大的图像,你可以使用这个方法

 - (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; } 

试试这段代码,我试图拼接两个图像在一起显示在一个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; 

连接是imageview的名称,你可以看到图像作为一个单一的图像。

上面的解决scheme是有帮助的,但对我来说有一个严重的缺陷。 问题是,如果图像尺寸不同,则生成的拼接图像在零件之间可能具有较大的空间。 我想出的解决scheme将所有图像合并到一起,使得它看起来更像是单个图像,而不pipe单个图像大小。

对于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! }