如何将两张图片合并成一张?

35

我想知道如何将2张图片保存为1张图片。

其中一张照片可以移动、旋转和缩放...

我正在尝试这样做,但它基本上会捕捉屏幕上的所有东西,包括我的按钮...

UIGraphicsBeginImageContext(self.view.bounds.size);
[self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *savedImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

请查看此链接:https://dev59.com/aVnUa4cB1Zd3GeqPYjoL - Leena
3
你提供的链接并不是很有用 :| - Vlad
请查看以下链接:https://dev59.com/DGox5IYBdhLWcg3wcT3r#9209044 - Srikar Appalaraju
8个回答

69

你可以创建图形上下文并在其中绘制两个图像。这样,你将得到一个合并了你的两个源图像的图像结果。

- (UIImage*)imageByCombiningImage:(UIImage*)firstImage withImage:(UIImage*)secondImage {
    UIImage *image = nil;

    CGSize newImageSize = CGSizeMake(MAX(firstImage.size.width, secondImage.size.width), MAX(firstImage.size.height, secondImage.size.height));
    if (UIGraphicsBeginImageContextWithOptions != NULL) {
        UIGraphicsBeginImageContextWithOptions(newImageSize, NO, [[UIScreen mainScreen] scale]);
    } else {
        UIGraphicsBeginImageContext(newImageSize); 
    }
    [firstImage drawAtPoint:CGPointMake(roundf((newImageSize.width-firstImage.size.width)/2), 
                                        roundf((newImageSize.height-firstImage.size.height)/2))]; 
    [secondImage drawAtPoint:CGPointMake(roundf((newImageSize.width-secondImage.size.width)/2), 
                                         roundf((newImageSize.height-secondImage.size.height)/2))]; 
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}

1
嗨,弗拉德,谢谢你的代码。它可以工作,但是它没有保存我编辑的任何移动或旋转。而且它按照图片的纵横比例进行保存。有什么建议吗? - Desmond
1
当两个图像具有相同的大小时,此函数会失败(然后MAX(first-width,second-width)的结果为0);此外,drawAtPoint函数似乎出现了故障。我不得不用以下代码替换它们:[firstImage drawAtPoint:CGPointMake(0,0)]; [secondImage drawAtPoint:CGPointMake(0, firstImage.size.height)];这仅在两个图像具有相同的宽度时有效! - Swissdude
你好!这段伟大的代码帮助了我很多。但是我不确定是否真的有必要使用roundf()函数。它可能会导致四舍五入误差。也许不是错误,但结果可能出乎意料。 - Alexey Voitenko
这里是同样逻辑的 Swift 版本代码片段 :) https://gist.github.com/A-Zak/3c38d3f83f911a25790f - Alex Zak
1
对我来说,图像大小增加了6到7倍。有没有办法在保持相同质量的情况下减小大小? - Zaraki
显示剩余4条评论

55

Swift 4.2

let topImage = UIImage(named: "image1.png")
let bottomImage = UIImage(named: "image2.png")

let size = CGSize(width: topImage!.size.width, height: topImage!.size.height + bottomImage!.size.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)

topImage!.draw(in: CGRect(x: 0, y: 0, width: size.width, height: topImage!.size.height))
bottomImage!.draw(in: CGRect(x: 0, y: topImage!.size.height, width: size.width, height: bottomImage!.size.height))

let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()

//set finalImage to IBOulet UIImageView
mergeImage.image = newImage

Objective-C

UIImage *image1 = [UIImage imageNamed:@"image1.png"];
UIImage *image2 = [UIImage imageNamed:@"image2.png"];

CGSize size = CGSizeMake(image1.size.width, image1.size.height + image2.size.height);

UIGraphicsBeginImageContext(size);

[image1 drawInRect:CGRectMake(0,0,size.width, image1.size.height)];
[image2 drawInRect:CGRectMake(0,image1.size.height,size.width, image2.size.height)];

UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

//set finalImage to IBOulet UIImageView
imageView.image = finalImage;

11
  1. 创建一个用于添加图片的子视图。
  2. 将所有图片都添加到该子视图中,而不是主视图中。
  3. 让按钮和其他元素保留在主视图中。
  4. 在位图上下文中只呈现带有图片的视图,而不是像您现在正在做的那样呈现主视图。

1
谢谢,我猜这是最好的方式 :) - Desmond

10

Swift 3

在此示例中,使用20%的边距缩进(frontImage)图像以使其位于另一张图像内部。

必须先绘制背景图像,然后按顺序绘制前景图像。

我将其用于在UIImageView中放置播放图标图片以覆盖视频帧图片,如下所示:

enter image description here

用法:

self.image = self.mergedImageWith(frontImage: UIImage.init(named: "play.png"), backgroundImage: UIImage.init(named: "backgroundImage.png")))

方法:

func mergedImageWith(frontImage:UIImage?, backgroundImage: UIImage?) -> UIImage{

    if (backgroundImage == nil) {
        return frontImage!
    }

    let size = self.frame.size
    UIGraphicsBeginImageContextWithOptions(size, false, 0.0)

    backgroundImage?.draw(in: CGRect.init(x: 0, y: 0, width: size.width, height: size.height))
    frontImage?.draw(in: CGRect.init(x: 0, y: 0, width: size.width, height: size.height).insetBy(dx: size.width * 0.2, dy: size.height * 0.2))

    let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()

    return newImage
}

9
您可以使用这种方法,非常灵活,您可以指定第二张图片的起始位置和整个图片的总大小。
-(UIImage *) addImageToImage:(UIImage *)img withImage2:(UIImage *)img2 andRect:(CGRect)cropRect withImageWidth:(int) width     
{

    CGSize size = CGSizeMake(width,40);
    UIGraphicsBeginImageContext(size);

    CGPoint pointImg1 = CGPointMake(0,0);
    [img drawAtPoint:pointImg1];

     CGPoint pointImg2 = cropRect.origin;
     [img2 drawAtPoint: pointImg2];

     UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();
     return result;
}

4
这是一种UIImage扩展的方法,可以将多个图像组合在一起:
class func combine(images: UIImage...) -> UIImage {
    var contextSize = CGSizeZero

    for image in images {
        contextSize.width = max(contextSize.width, image.size.width)
        contextSize.height = max(contextSize.height, image.size.height)
    }

    UIGraphicsBeginImageContextWithOptions(contextSize, false, UIScreen.mainScreen().scale)

    for image in images {
        let originX = (contextSize.width - image.size.width) / 2
        let originY = (contextSize.height - image.size.height) / 2

        image.drawInRect(CGRectMake(originX, originY, image.size.width, image.size.height))
    }

    let combinedImage = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

    return combinedImage
}

例子:

UIImage.combine(image1, image2)

2

Swift-3 (IOS10.3)

extension UIImage {
    func combineWith(image: UIImage) -> UIImage {
        let size = CGSize(width: self.size.width, height: self.size.height + image.size.height)
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)

        self.draw(in: CGRect(x:0 , y: 0, width: size.width, height: self.size.height))
        image.draw(in: CGRect(x: 0, y: self.size.height, width: size.width,  height: image.size.height))

        let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()

        return newImage
    }
}

使用方法

let image1 = UIImage(named: "image1.jpg")
let image2 = UIImage(named: "image2.jpg")

yourImageView.image = image1?.combineWith(image: image2)

0

基于Himanshu padia的回答

如果你想要在Objective-C中“动态”地将更多图片(具有相同的宽高比)组合成一个网格

我在偶数/奇数槽位上仅使用了两个示例。

等内联和轮廓边框的公式:

// psx = (x - (n+1)*bs / n)
// psy = (y - (m+1)*bs / m)

不同内联和轮廓边框的公式

// psx = (x - (n-1)*bs + obs / n)
// psy = (y - (m-1)*bs + obs / m)

说明:

  • psx,psy - 每个块的 X 和 Y 尺寸
  • x,y - 原始(块)图像尺寸
  • n,m - 网格中的块数
  • bs - 边框大小
  • obs - 轮廓边框大小

  • 为什么是 n+1?因为对于三个块,你需要 4 条边框 |*|*|*|

  • 为什么是 n-1?因为与上面相同,但不包括第一个和最后一个边框 !*|*|*!

代码:

UIImage *image1 = [UIImage imageNamed:@"14x9blue"];
UIImage *image2 = [UIImage imageNamed:@"14x9red"];

// grid parameters
int k =0;
int m=3,n = 3;
int i=0, j=0;

CGFloat borderSize = 20.0f;
//  equal border inline and outline
// the 1 is a multiplier for easier and more dynamic sizes
// 0*borderSize is inline border only, 1 is equal, 2 is double, etc.
CGFloat outlineBorder = 1*borderSize;

CGSize size = CGSizeMake(self.gridImageView.image.size.width, self.gridImageView.image.size.height);
CGRect gridImage = CGRectMake(0,0, size.width, size.height);


// piece size
// border inline and outline    
// psx = (x - (n-1)*bs + obs / n)
// psy = (y - (m-1)*bs + obs / m)
CGFloat pieceSizeX = (size.width - (n-1)*borderSize - 2*outlineBorder) / n;
CGFloat pieceSizeY = (size.height - (m-1)*borderSize - 2*outlineBorder) / m;




UIGraphicsBeginImageContext(size);
// semi transparent fill
[[UIColor colorWithDisplayP3Red:240 green:250 blue:0 alpha:0.5] setFill];
UIRectFill(CGRectMake(0,0, size.width, size.height));

UIImage *currentImage;
for(i=0; i<m; i++) {
    for (j=0; j<n; j++) {
        if (k++%2) {
            currentImage = image1;
        } else {
            currentImage = image2;
        }
        // 10-60 , 70-120, 130-180
        [currentImage drawInRect:CGRectMake(
                outlineBorder + (i)*borderSize + i*pieceSizeX,
                outlineBorder + (j)*borderSize + j*pieceSizeY,
                pieceSizeX,
                pieceSizeY
        )
        ];
    }
}

UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

//set finalImage to IBOulet UIImageView
self.gridImageView.image = finalImage;

Grid with equal borders


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接