xcode 垂直缝合/合成多张图像并保存为一张图像(iOS,objective-c)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11752885/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 01:05:39  来源:igfitidea点击:

Stitch/Composite multiple images vertically and save as one image (iOS, objective-c)

objective-ciosxcodeimage

提问by Cameron E

I need help writing an objective-c function that will take in an array of UIImages/PNGs, and return/save one tall image of all the images stitched together in order vertically. I am new to this so please go slow and take it easy :)

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

My ideas so far: Draw a UIView, then addSubviews to each one's parent (of the images) and then ???

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

采纳答案by Gordon Dove

The normal way is to create a bitmap image context, draw your images in at the required position, and then get the image from the image context.

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

You can do this with UIKit, which is somewhat easier, but isn't thread safe, so will need to run in the main thread and will block the UI.

您可以使用 UIKit 来完成此操作,这稍微容易一些,但不是线程安全的,因此需要在主线程中运行并会阻塞 UI。

There is loads of example code around for this, but if you want to understand it properly, you should look at UIGraphicsContextBeginImageContext, UIGraphicsGetCurrentContext, UIGraphicsGetImageFromCurrentImageContext and UIImageDrawInRect. Don't forget UIGraphicsPopCurrentContext.

周围有大量示例代码,但如果你想正确理解它,你应该查看 UIGraphicsContextBeginImageContext、UIGraphicsGetCurrentContext、UIGraphicsGetImageFromCurrentImageContext 和 UIImageDrawInRect。不要忘记 UIGraphicsPopCurrentContext。

You can also do this with Core Graphics, which is AFAIK, safe to use on background threads ( I've not had a crash from it yet). Efficiency is about the same, as UIKit just uses CG under the hood. Key words for this are CGBitmapContextCreate, CGContextDrawImage, CGBitmapContextCreateImage, CGContextTranslateCTM, CGContextScaleCTM and CGContextRelease ( no ARC for Core Graphics). The scaling and translating is because CG has the origin in the bottom right hand corner and Y inscreases upwards.

您也可以使用 AFAIK 的 Core Graphics 执行此操作,可以安全地在后台线程上使用(我还没有发生崩溃)。效率大致相同,因为 UIKit 只是在幕后使用 CG。关键字是 CGBitmapContextCreate、CGContextDrawImage、CGBitmapContextCreateImage、CGContextTranslateCTM、CGContextScaleCTM 和 CGContextRelease(核心图形没有 ARC)。缩放和平移是因为 CG 的原点在右下角,而 Y 向上增加。

There is also a third way, which is to use CG for the context, but save yourself all the co-ordinate pain by using a CALayer, set your CGImage ( UIImage.CGImage) as the contents and then render the layer to the context. This is still thread safe and lets the layer take care of all the transformations. Keywords for this is - renderInContext:

还有第三种方法,即使用 CG 作为上下文,但通过使用 CALayer,将您的 CGImage ( UIImage.CGImage) 设置为内容,然后将图层渲染到上下文,从而为您省去所有坐标的痛苦。这仍然是线程安全的,并让层负责所有的转换。关键字是 - renderInContext:

回答by clearlight

Below are Swift 3 and Swift 2 examples that stitch images together vertically or horizontally. They use the dimensions of the largest image in the array provided by the caller to determine the common size used for each individual frame each individual image is stitched into.

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

Note: The Swift 3 example preserves each image's aspect ratio, while the Swift 2 example does not. See note inline below regarding that.

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

UPDATE: Added Swift 3 example

更新:添加了 Swift 3 示例

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
}

Note: The original Swift 2 example below does notpreserve the aspect ratio (e.g. in the Swift 2 example all images are expanded to fit in the bounding box that represents the extrema of the widths and heights of the images, thus Any non-square image can be stretched disproportionately in one of its dimensions). If you're using Swift 2 and want to preserve the aspect ratio please use the AVMakeRect()modification from the Swift 3 example. Since I no longer have access to a Swift 2 playground and can't test it to ensure no errors I'm not updating the Swift 2 example here for that.

注意:下面的原始 Swift 2 示例保留纵横比(例如,在 Swift 2 示例中,所有图像都被扩展以适合表示图像宽度和高度极值的边界框,因此任何非方形图像可以在其维度之一不成比例地拉伸)。如果您使用的是 Swift 2 并希望保留纵横比,请使用AVMakeRect()Swift 3 示例中的修改。由于我不再可以访问 Swift 2 playground 并且无法对其进行测试以确保没有错误,因此我不会在此处更新 Swift 2 示例。

Swift 2: (Doesn't preserve aspect ratio. Fixed in Swift 3 example above)

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
}

回答by What what

I know I'm a bit late here but hopefully this can help someone out. If you're trying to create one large image out of an array you can use this method

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

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

回答by Tori Rogozhyna

Swift 4

斯威夫特 4

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

        let maxWidth = self.compactMap { 
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;   
.size.width }.max() let maxHeight = self.compactMap {
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!
}
.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) } } } }

回答by darkmystel

Try this piece of code,I tried stitching two images together n displayed them in an ImageView

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

##代码##

join is the name of the imageview and you get to see the images as a single image.

join 是图像视图的名称,您可以将图像视为单个图像。

回答by C6Silver

The solutions above were helpful but had a serious flaw for me. The problem is that if the images are of different sizes, the resulting stitched image would have potentially large spaces between the parts. The solution I came up with combines all images right below each other so that it looks like more like a single image no matter the individual image sizes.

上面的解决方案很有帮助,但对我来说有一个严重的缺陷。问题在于,如果图像的大小不同,则生成的拼接图像可能会在各部分之间存在较大的空间。我想出的解决方案将所有图像组合在一起,使其看起来更像是单个图像,无论单个图像大小如何。

For Swift 3.x

对于 Swift 3.x

##代码##