PDA

View Full Version : Combine(merge) two images




Trisect Develop
Jun 28, 2013, 02:34 AM
I'm working on a Mac program that should combine two images and display them in an ImageView.

The first image is dragged into XCode and the other one is loaded from disk.

How do I combine(merge) those two images and put them into my ImageView?



xArtx
Jun 28, 2013, 03:44 AM
I'm working on a Mac program that should combine two images and display them in an ImageView.

The first image is dragged into XCode and the other one is loaded from disk.

How do I combine(merge) those two images and put them into my ImageView?

Could you not give the second image some transparency and print it over the first one?

Trisect Develop
Jun 28, 2013, 03:52 AM
I'm fairly new to Mac programming have done a lot of iOS programming.

But I don't think an ImageView can cotain two images!

I need to combine them somehow.

robbieduncan
Jun 28, 2013, 03:53 AM
Do you actually need the images combined in memory/on disk or do you just want to display the result? If the latter just use 2 image views with one slightly transparent.

Otherwise:

1) Load each image into an NSImage object
2) Lock focus using lockFocus (https://developer.apple.com/library/mac/documentation/cocoa/reference/ApplicationKit/Classes/NSImage_Class/Reference/Reference.html#//apple_ref/occ/instm/NSImage/lockFocus) on the bottom "layer"
3) Draw the top "layer" using drawInRect:fromRect:operation:fraction: (https://developer.apple.com/library/mac/documentation/cocoa/reference/ApplicationKit/Classes/NSImage_Class/Reference/Reference.html#//apple_ref/occ/instm/NSImage/drawInRect:fromRect:operation:fraction:) setting the operation and fraction to do what you want.

Trisect Develop
Jun 28, 2013, 04:07 AM
I want to take one image and put another on on top of the first one and display it in an ImageView. Later I wan't the save the merged image form the ImageView.

I have eight ImageViews and for each of the I have a button. When a button is clicked I choose an image from disk and combine it with an image already dragged into Xcode.

Right now I have some code that actually merge two images and it works fine for the first ImageView but when I do the same for the second ImageView the first one changes to the exact same as the second one. If I then loads a new image into the first one the second changes automatically.

So I'm thinking theres something wrong with my code and thats why I'm asking for an example on how to do it.

Here the code from my m file.

The load button ( it the same code for the second button)

NSOpenPanel* panel = [NSOpenPanel openPanel];

[panel setCanChooseFiles:YES];
[panel setCanChooseDirectories:NO];

[panel beginWithCompletionHandler:^(NSInteger result){
if (result == NSFileHandlingPanelOKButton) {
NSURL *theDoc = [[panel URLs] objectAtIndex:0];

NSString *fileNameAndPath = [[theDoc path] stringByStandardizingPath];

//** VŠlg device
switch ([[rbSelectDevice selectedCell] tag]) {
case 1: //** iPhone 5
screenShot1 = [self mergeImages:iPhone5 withImage:[[NSImage alloc]initWithContentsOfFile:fileNameAndPath]];
break;
}

[ivScreenshot1 setImage:screenShot1];

}

}];


The merge method

//** Merge two images together
-(NSImage *)mergeImages:(NSImage *)theTarget withImage:(NSImage *)theSource{

//Get the source image from file
NSImage *source = theSource; //[[NSImage alloc]initWithContentsOfFile:@"/Users/JensThomsen/Library/Developer/Xcode/DerivedData/Smartphone_App_Store_Icons_and_Images_Tool-bsnfzaaviuzrqdcpuknipijqslci/Build/Products/Debug/icon512.png"];

//Init target image
NSImage *target = theTarget; //[[NSImage alloc]initWithContentsOfFile:@"/Users/JensThomsen/Library/Developer/Xcode/DerivedData/Smartphone_App_Store_Icons_and_Images_Tool-bsnfzaaviuzrqdcpuknipijqslci/Build/Products/Debug/tempImage.png"];

//start drawing on target
[target lockFocus];
//draw the portion of the source image on target image
[source drawInRect:NSMakeRect(84,270,770,1365) fromRect:NSZeroRect operation: NSCompositeCopy fraction:1.0];
//end drawing
[target unlockFocus];

//create a NSBitmapImageRep
NSBitmapImageRep *bmpImageRep = [[NSBitmapImageRep alloc]initWithData:[target TIFFRepresentation]];
//add the NSBitmapImage to the representation list of the target
[target addRepresentation:bmpImageRep];


return target;
}

robbieduncan
Jun 28, 2013, 04:16 AM
Sounds like you are using the same NSImage instance for all the views then. But we don't have the code for that bit. Also you're merge code has hard-coded both images so it will always return the exact same thing...

Trisect Develop
Jun 28, 2013, 04:23 AM
Maybe you are right but I cannot figure out where the problem is.


I declare this variables in the top.

NSImage *iPhone5;

NSImage *screenShot1;
NSImage *screenShot2;


I set the iPhone5 image in the initWithNibName method

iPhone5 = [NSImage imageNamed:@"IPhone_5.png"];


Does this clear things so that you maybe can see what I'm doing wrong?

robbieduncan
Jun 28, 2013, 04:42 AM
Maybe you are right but I cannot figure out where the problem is.


I declare this variables in the top.

NSImage *iPhone5;

NSImage *screenShot1;
NSImage *screenShot2;


I set the iPhone5 image in the initWithNibName method

iPhone5 = [NSImage imageNamed:@"IPhone_5.png"];


Does this clear things so that you maybe can see what I'm doing wrong?
It matters not what variable names you declare. It matters what's loaded to them. I see I miss read your code: the fixed paths are commented out. But we still can't see all of the code: only the code for one case. If all cases use
"iphone5" as their target then they are sharing a single instance so all will always be the same image.

Trisect Develop
Jun 28, 2013, 04:51 AM
Ahh, so if I use

NSImage *iPhone5_1;
NSImage *iPhone5_2;
NSImage *iPhone5_3;

It will be better?

robbieduncan
Jun 28, 2013, 05:00 AM
Ahh, so if I use

NSImage *iPhone5_1;
NSImage *iPhone5_2;
NSImage *iPhone5_3;

It will be better?

Assuming each of those points to a different instance, not the same then yes. I.e. don't do this:


NSImage *temp = [NSImage imageNamed:@"IPhone_5.png"];
NSImage *iPhone5_1 = temp;
NSImage *iPhone5_2 = temp;
...


as the variable names completely and utterly don't matter: they would all point at the same instance.

Also check that imageNamed is not caching the result and returning the same instance: I'd use alloc/init to ensure a new, clean instance each time.

Trisect Develop
Jun 28, 2013, 05:34 AM
Okay I tried this

iPhone5_1 = [[NSImage alloc] init];
iPhone5_2 = [[NSImage alloc] init];
iPhone5_1 = [NSImage imageNamed:@"IPhone_5.png"];
iPhone5_2 = [NSImage imageNamed:@"IPhone_5.png"];


But I get the same result

robbieduncan
Jun 28, 2013, 05:48 AM
Okay I tried this

iPhone5_1 = [[NSImage alloc] init];
iPhone5_2 = [[NSImage alloc] init];
iPhone5_1 = [NSImage imageNamed:@"IPhone_5.png"];
iPhone5_2 = [NSImage imageNamed:@"IPhone_5.png"];


But I get the same result

I think you fundamentally don't understand objects, pointers and what this code does. The first two lines of code are completely and utterly pointless as they allocate new objects and point the variables at them to immediately afterwards have those pointers moved to other objects. You then use the method I warned you not to use as it would cache the object so it is most likely that _1 and _2 are now pointing at the same instance. When I suggested using alloc/init that was commonly used shorthand to indicate this style of code but not necessarily a plain init: in this case I expected you to use one of initWithContentsOfFile or initWithContentsOfURL.

But I would suggest you need to take step back and consider learning some basic debugging techniques like using NSLog...

Trisect Develop
Jun 28, 2013, 06:02 AM
Thanks!
This did it.

NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"IPhone_5.png"];
iPhone5_1 = [[NSImage alloc] initWithContentsOfFile:filePath];
iPhone5_2 = [[NSImage alloc] initWithContentsOfFile:filePath];


And YES I'm new to Mac programming. Never had this problems when programming for iOS.

robbieduncan
Jun 28, 2013, 06:26 AM
Never had this problems when programming for iOS.

Bear in mind imageNamed works the same way there too in case you want to do similar on iOS...

xArtx
Jun 30, 2013, 11:39 PM
If your CPU has the time, why not load both images into bitmap contexts,
set the transparency of one of the images there,
overlay one atop the other, and then load the final image into the view?