SolidSnake4444
SolidSnake4444

Reputation: 3587

How does one overlay one image onto another to create a new image to save (watermark)?

Basically I want to take an image that the user chooses from their photo library and then apply a watermark, a triangle in the lower right that has the app name on it. I have the second image already made with a transparent layer in photoshop.

I tried a function, which I can't remember the exact name, but it involved CGIImages and masks. This combines the two images, but as a mask, which made the image darker where the transparent layer was and the images were not merged per se, just masked.

How would I get the watermark image to merge with another image, to make a UIImage, without displaying the images on the screen?

Upvotes: 27

Views: 32281

Answers (6)

LGLB
LGLB

Reputation: 1

Disclaimer: Two months new to programming/Swift/Xcode, so please forgive me for any errors.

Like others here, I needed to apply some watermarks as well, and in a multi-platform app. Most examples depended on "AppKit" components, which I'm learning are exclusive to macOS (again, I'm new); or they depended on "UIKit" components, which are apparently exclusive to iOS. Plus, the most helpful/capable suggestions for me that I found here used "UIGraphicsBeginImageContext". When I caved-in (iOS only) to use the examples, they worked great, but that one, particular UI method is marked as 'deprecated' (at least by late 2024), so I felt I had to look further.

My endeavors led me down to the core, the 'Core' that is. All the lower-level graphics I had to do forced me into Core Imaging and Core Graphics frameworks anyway, where everything is touchy, optional, somewhat tricky, and can differ to UI orientations, but I got it to all work great, and decided I should try to share, hoping it might help someone else. There are small preliminary steps to convert other images back down to CI/CG, which seems to be their basis anyway, but it's not hard to do and feels native to UIImage and NSImage.

You'd need to add the 'import CoreImage.CIFilterBuiltins' to your standard imports, if you hadn't already by that point. Also, in the example, I have 2 pre-made overlays with transparent alpha channels stored prior ("theWatermarkCIImage" and "theClippingRectCIImage") that are the same size [easiest] as the expected underlaid (background) image is, and the func lets the input boolean choose which to apply (this choice-function is custom for my uses, but you could just pass in an overlay/watermark image instead of the boolean as the second input, and edit the code with "let dummer.inputImage = myWatermarkImage"). And also, there is an 'if false {}' block which I switched on and off while developing for immediately testing the results. May be helpful for you too, so left it in here:

import CoreImage.CIFilterBuiltins


func applyOverlayToCIImage(_ theUnderlaidImage: CIImage, _ useWatermark: Bool) -> CGImage {

    let dum = CIContext()
    let dummer = CIFilter.sourceOverCompositing()
    dummer.inputImage = (useWatermark ? theWatermarkCIImage : theClippingRectCIImage)
    dummer.backgroundImage = theUnderlaidImage

    let dummest = dummer.outputImage!
    let duh = dum.createCGImage(dummest, from: dummest.extent)

    if false {
        let dumURL = URL(filePath: "/Users/someUserName/Desktop/someUniqueFileName.jpg")
        do {try dum.writeJPEGRepresentation(of: dummest, to: dumURL, colorSpace: CGColorSpaceCreateDeviceRGB()) }
        catch { print("Could not write JPEG to file to: \(dumURL)\nBecause Error: \(error)") } }

    return duh!
}

Hope it helps.

Upvotes: 0

Sachin Rasane
Sachin Rasane

Reputation: 1559

SWIFT 4

let backgroundImage = imageData!
let watermarkImage = #imageLiteral(resourceName: "jodi_url_icon")

UIGraphicsBeginImageContextWithOptions(backgroundImage.size, false, 0.0)
backgroundImage.draw(in: CGRect(x: 0.0, y: 0.0, width: backgroundImage.size.width, height: backgroundImage.size.height))
watermarkImage.draw(in: CGRect(x: 10, y: 10, width: watermarkImage.size.width, height: backgroundImage.size.height - 40))

let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.imgaeView.image = result

Use result to UIImageView, tested.

Upvotes: 2

CodeMonkey
CodeMonkey

Reputation: 635

The solution provided by omz also works in Swift, like so:

let backgroundImage = UIImage(named: "image.png")!
let watermarkImage = UIImage(named: "watermark.png")!

UIGraphicsBeginImageContextWithOptions(backgroundImage.size, false, 0.0)
backgroundImage.draw(in: CGRect(x: 0.0, y: 0.0, width: backgroundImage.size.width, height: backgroundImage.size.height))
watermarkImage.draw(in: CGRect(x: backgroundImage.size.width - watermarkImage.size.width, y: backgroundImage.size.height - watermarkImage.size.height, width: watermarkImage.size.width, height: watermarkImage.size.height))
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

Upvotes: 13

Ali A. Jalil
Ali A. Jalil

Reputation: 921

SWIFT 5 Function:

func addWaterMark(image: UIImage) -> UIImage {
        let backgroundImage = image//UIImage(named: "image.png")
        let watermarkImage = UIImage(named: "waterMark.png")

        UIGraphicsBeginImageContextWithOptions(backgroundImage.size, false, 0.0)
        backgroundImage.draw(in: CGRect(x: 0.0, y: 0.0, width: backgroundImage.size.width, height: backgroundImage.size.height))
        watermarkImage!.draw(in: CGRect(x: backgroundImage.size.width - watermarkImage!.size.width, y: backgroundImage.size.height - watermarkImage!.size.height, width: watermarkImage!.size.width, height: watermarkImage!.size.height))
        let result = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return result!
    }

Upvotes: 1

omz
omz

Reputation: 53561

It's pretty easy:

UIImage *backgroundImage = [UIImage imageNamed:@"image.png"];
UIImage *watermarkImage = [UIImage imageNamed:@"watermark.png"];

UIGraphicsBeginImageContext(backgroundImage.size);
[backgroundImage drawInRect:CGRectMake(0, 0, backgroundImage.size.width, backgroundImage.size.height)];
[watermarkImage drawInRect:CGRectMake(backgroundImage.size.width - watermarkImage.size.width, backgroundImage.size.height - watermarkImage.size.height, watermarkImage.size.width, watermarkImage.size.height)];
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

If you want the background and watermark to be of the same size then use this code

...
[backgroundImage drawInRect:CGRectMake(0, 0, backgroundImage.size.width, backgroundImage.size.height)];
[watermarkImage drawInRect:CGRectMake(0, 0, backgroundImage.size.width, backgroundImage.size.height)];
...

Upvotes: 83

Parvez Belim
Parvez Belim

Reputation: 1013

You can use this method, which is very dynamic and you can specify the starting position of the second image and total size of the image.

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

}

Upvotes: 1

Related Questions