垂直缝合/合成多个图像并另存为一个图像(iOS,objective-c)
我需要帮助编写一个objective-c函数,该函数将接收一组UIImages/PNG,并返回/保存所有垂直缝合在一起的图像的一个高图像。我是新手,所以请慢慢来,放松点:) 到目前为止,我的想法是: 绘制UIView,然后将子视图添加到每个视图的父视图(图像的父视图)垂直缝合/合成多个图像并另存为一个图像(iOS,objective-c),objective-c,ios,xcode,image,Objective C,Ios,Xcode,Image,我需要帮助编写一个objective-c函数,该函数将接收一组UIImages/PNG,并返回/保存所有垂直缝合在一起的图像的一个高图像。我是新手,所以请慢慢来,放松点:) 到目前为止,我的想法是: 绘制UIView,然后将子视图添加到每个视图的父视图(图像的父视图) 然后???通常的方法是创建位图图像上下文,在所需位置绘制图像,然后从图像上下文中获取图像 您可以使用UIKit来实现这一点,它稍微简单一些,但不是线程安全的,因此需要在主线程中运行,并将阻止UI 这方面有很多示例代码,但是如果您想
然后???通常的方法是创建位图图像上下文,在所需位置绘制图像,然后从图像上下文中获取图像 您可以使用UIKit来实现这一点,它稍微简单一些,但不是线程安全的,因此需要在主线程中运行,并将阻止UI 这方面有很多示例代码,但是如果您想正确理解它,应该查看UIGraphicsContextBeginImageContext、UIGraphicsGetCurrentContext、UIGraphicsGetImageFromCurrentImageContext和UIImageDrawInRect。不要忘记UIGraphicsPopCurrentContext 您也可以使用核心图形来实现这一点,它是安全的,可以安全地在后台线程上使用(我还没有因为它而崩溃)。效率差不多,因为UIKit只是在引擎盖下使用CG。 这方面的关键词是CGBitmapContextCreate、CGContextDrawImage、CGBitmapContextCreateImage、CGContextTranslateCTM、CGContextScaleCTM和CGContextRelease(核心图形无弧)。缩放和平移是因为CG的原点在右下角,Y向上递增
还有第三种方法,即使用CG作为上下文,但通过使用CALayer,将您的CGImage(UIImage.CGImage)设置为内容,然后将层渲染到上下文中,从而省去了所有协调方面的麻烦。这仍然是线程安全的,并且让层负责所有的转换。这篇文章的关键词是-renderInContext:试试这段代码,我试着将两幅图像拼接在一起,然后在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的名称,您可以将图像作为单个图像查看。我知道我来晚了一点,但希望这可以帮助其他人。如果要从阵列中创建一个大图像,可以使用此方法
- (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;
}
下面是Swift 3和Swift 2将图像垂直或水平缝合在一起的示例。它们使用调用者提供的数组中最大图像的尺寸来确定每个图像缝合到的每个帧的通用大小 注意: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
要保留纵横比,请使用AVMakeRect()
来自Swift 3示例的修改。因为我不再有访问权限
到Swift 2游乐场,无法测试以确保没有错误,我没有
在此更新Swift 2示例
Swift 2:(不保留纵横比。在上面的Swift 3示例中已修复)
上面的解决方案很有帮助,但对我来说有一个严重的缺陷。问题是,如果图像的大小不同,则生成的缝合图像在零件之间可能有较大的空间。我提出的解决方案将所有图像合并在一起,使其看起来更像单个图像,而不管单个图像大小如何 适用于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!
}
斯威夫特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)
}
}
}
}
谢谢你,伙计,我现在就开始调查这件事。公平地说,你的评论也不公平,我只是想帮你。@happiehappiedone!当在Swift操场上用不全是正方形的图像进行测试时,我注意到在Swift 2示例中,图像被水平或垂直拉伸,没有保留纵横比。我已经在新增的Swift 3示例中解决了这个问题。谢谢你能让我的答案成为这个问题的公认答案吗,这样人们就更容易快速找到最佳答案(例如,真正解决问题并提供工作示例的答案)?这似乎是一个奇怪或贪婪的请求,但事实并非如此。“公认答案”的目标是尽可能直接地引导人们找到最实际可行的解决方案,这就是为什么随着解决方案的增加,你可以改变它。很好的答案!我喜欢这是一个扩展,谢谢你发布这个。谢谢Tori!此解决方案不仅有效,而且效果良好。从UIGraphicsGetImageFromCurrentImageContext切换到UIGraphicsImageRenderer后,我能够在将10多幅全屏图像拼接成一幅长图像时保持图像质量。这应该是公认的答案!
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)
}
}
}
}