我需要帮助编写一个 Objective-C 函数,该函数将接受 UIImages/PNG 数组,并返回/保存按垂直顺序缝合在一起的所有图像的一个高图像。我是新手,所以请慢慢来,放轻松:)
到目前为止我的想法: 绘制一个 UIView,然后将子视图添加到每个视图的父视图(图像的) 然后???
下面是 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 示例并没有保留 长宽比(例如,在 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
}
您可以使用 UIKit 来完成此操作,这更容易一些,但不是线程安全的,因此需要在主线程中运行并会阻塞 UI。
为此有大量示例代码,但如果您想正确理解它,您应该查看 UIGraphicsContextBeginImageContext、UIGraphicsGetCurrentContext、UIGraphicsGetImageFromCurrentImageContext 和 UIImageDrawInRect。不要忘记 UIGraphicsPopCurrentContext。
您也可以使用 Core Graphics 来完成此操作,据我所知,可以安全地在后台线程上使用(我还没有遇到过崩溃)。效率大致相同,因为 UIKit 只是在底层使用 CG。 其关键字是 CGBitmapContextCreate、CGContextDrawImage、CGBitmapContextCreateImage、CGContextTranslateCTM、CGContextScaleCTM 和 CGContextRelease(核心图形没有 ARC)。缩放和平移是因为 CG 原点在右下角,Y 向上增加。
还有第三种方法,即使用 CG 作为上下文,但使用 CALayer 可以省去所有坐标麻烦,将 CGImage ( UIImage.CGImage) 设置为内容,然后将图层渲染到上下文。这仍然是线程安全的,并让该层处理所有转换。关键字是 - renderInContext:
- (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;
}
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)
}
}
}
}
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 是图像视图的名称,您可以将图像视为单个图像。
对于 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!
}
适用于 Swift 5+
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).index(of: 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.draw(in: rect)
}
stitchedImages = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
}
return stitchedImages
}
使用
var selectedImages: [UIImage] = []
let images = stitchImages(images: selectedImages, isVertical: true)
imageView.image = images