Merging two UIImage into 1 to be savedtolibrary - ios

I would like to know how can I merge 2 uiimage into 1? I would like to save the end product to the library. For saving images I'm using a UI button. Here's snippet of how I save a UIImageview.image.
-(IBAction)getPhoto:(id)sender {
UIImage* imageToSave = imageOverlay.image;
UIImageWriteToSavedPhotosAlbum(imageToSave, nil, nil, nil);
}
I've looked online and read about UIGraphicsBeginImageContext. Found an example but I couldn't understand how to actually apply it to mine. Here's the one I've got so far.
- (UIImage*)addImage:(UIImage *)image secondImage:(UIImage *)image2
{
UIGraphicsBeginImageContext(image.size);
[image drawInRect:CGRectMake(0,0,image.size.width,image.size.height)];
[image2 drawInRect:CGRectMake(10,10,image2.size.width,image2.size.height) blendMode:kCGBlendModeNormal alpha:1.0];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Right now I have 2 UIImageviews which is imageOverlay.image and imageView.image. If I use the method above how to assign the return value to UIImageWriteToSavedPhotoAlbum? Hope someone can point me to the right direction.
Thanks very much.

Seems like you don't have the header for the method in your header file, in the .h file of the class/view controller from which you're running the IBAction, add the first line of your method, -(UIImage*) addImage:... And end it with a ; before the #end. That should work, though you'd have to implement it in the .m file of the same .h file somewhere.

Try this:
-(IBAction)getPhoto:(id)sender {
UIImage* imageToSave = [self addImage:imageOverlay.image secondImage:imageView.image];
UIImageWriteToSavedPhotosAlbum(imageToSave, nil, nil, nil);
}

create a NSLog, and pass them through it like this, image1 and image2 are your images:
NSLog (#"testing images aren't nil. Details for image1: %# image2: %#",image1,image2);
I'm a newbie too, and I don't really know a more sophisticated way to see if the image is nil, but I saw that by passing a nil image to the statement above, you'd only get nil instead of the values of those two images. If you get lots of information, even though they're alot of codes and you may not understand them either, as I usually don't, at least you can test whether they are nil or not.

Related

difference between UIImageView.image = ... and UIimageView.layer.content =

Two ways of set UIImage to A UIImageView:
First:
self.imageview.image = [UIImage imageNamed:#"clothing.png"];
Second:
self.imageview.layer.contents = (__bridge id _Nullable)([[UIImage imageNamed:#"clothing.png"] CGImage]);
what is the difference between the two ways?
which one is better?
In fact.What I want to do is displaying part of one PNG in UIImageView.
There are two ways:
First:
UIImage *image = [UIImage imageNamed:#"clothing.png"];
CGImageRef imageRef = CGImageCreateWithImageInRect(image, rect);
self.imageview.image = [UIImage imageWithCGImage:imageRef];
Second:
self.imageview2.layer.contents = (__bridge id _Nullable)([[UIImage imageNamed:#"clothing.png"] CGImage]);//way2
self.imageview2.layer.contentsRect = rect;
Which one is better? Why? Thanks!
First:
self.imageview.image = [UIImage imageNamed:#"clothing.png"];
By using this you can directly assign your image to any UIImageView While in
Second:
self.imageview.layer.contents = (__bridge id _Nullable)([[UIImage imageNamed:#"clothing.png"] CGImage]);
You can not assign image directly to layer. so you need to put a CGImage into a layer.
So First is best forever. Thank you.
First option is better, Bridge concept is used before introduction of ARC
Of course the better way is the first one :
self.imageview.image = [UIImage imageNamed:#"clothing.png"];
Indeed, this is the way an UIImageView is built for.
For clarification, every view (UIView, UIImageView, etc) has a .layer property to add visual content on it. Here you're adding an image in it. You could have achieved the same result with a single UIView. But, in performances terms and clarity, you should (have to) use .image property.
Edit :
Even with your new edit, first option is still the better one.
You can do that but it's your responsibility to modify the image to make the image.CGImage draw correctly respect to imageOrientation, contentMode and so on. If you set the image with imageView.image = image;, it's apple's responsibility to do that.
I give you an example that causes the problem:
as image.CGImage doesn't contain image orientation, so if you set it directly and if the source image is not UIImageOrientationUp, the image will be rotated, unless you "fix the orientation" of the source image like this. (You can get a image that is not UIImageOrientationUp, just take a photo with your iPhone)
- (UIImage *)fixOrientation {
if (self.imageOrientation == UIImageOrientationUp) return self;
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
[self drawInRect:(CGRect){0, 0, self.size}];
UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return normalizedImage;
}
Here are two screen shot, the first is set image.CGImage directly to layer.contents, the second is set image to imageView.image.
So always use imageView.image unless you know what you're doing.

How to add several UIImages to one base UIImage in iOS

I know there has to be a way to take one base image (in my case a transparent 4096x4096 base layer) and adding several dozen (up to 100) very small (100x100) images to it in different locations. BUT I cannot figure out how to do it: Assume for the following that imageArray has many elements, each containing a NSDictionary with the following structure:
#{
#"imagename":imagename,
#"x":xYDict[#"x"],
#"y":xYDict[#"y"]
}
Now, here is the code (that is not working. all I have is a transparent screen...and the performance is STILL horrible...about 1-2 seconds per "image" in the loop...and massive memory use.
NSString *PNGHeatMapPath = [[myGizmoClass dataDir] stringByAppendingPathComponent:#"HeatMap.png"];
#autoreleasepool
{
CGSize theFinalImageSize = CGSizeMake(4096, 4096);
NSLog(#"populateHeatMapJSON: creating blank image");
UIGraphicsBeginImageContextWithOptions(theFinalImageSize, NO, 0.0);
UIImage *theFinalImage = UIGraphicsGetImageFromCurrentImageContext();
for (NSDictionary *theDict in imageArray)
{
NSLog(#"populateHeatMapJSON: adding: %#",theDict[#"imagename"]);
UIImage *image = [UIImage imageNamed:theDict[#"imagename"]];
[image drawInRect:CGRectMake([theDict[#"x"] doubleValue],[theDict[#"y"] doubleValue],image.size.width,image.size.height)];
}
UIGraphicsEndImageContext();
NSData *imageData = UIImagePNGRepresentation(theFinalImage);
theFinalImage = nil;
[imageData writeToFile:PNGHeatMapPath atomically:YES];
NSLog(#"populateHeatMapJSON: PNGHeatMapPath = %#",PNGHeatMapPath);
}
I KNOW I am misunderstanding UIGraphics contexts...can someone help me out? I am trying to superimpose a bunch of UIImages on the blank transparent canvas at certain x,y locations, get the final image and save it.
PS: This is also .. if the simulator is anything to go by ... leaking like heck. It goes up to 2 or 3 gig...
Thanks in advance.
EDIT:
I did find this and tried it but it requires me to rewrite the entire image, copy that image to a new one and add to that new one. Was hoping for a "base image", "add this image", "add that image", "add the other image" and get the new base image without all the copying:
Is this as good as it gets?
+(UIImage*) drawImage:(UIImage*) fgImage
inImage:(UIImage*) bgImage
atPoint:(CGPoint) point
{
UIGraphicsBeginImageContextWithOptions(bgImage.size, FALSE, 0.0);
[bgImage drawInRect:CGRectMake( 0, 0, bgImage.size.width, bgImage.size.height)];
[fgImage drawInRect:CGRectMake( point.x, point.y, fgImage.size.width, fgImage.size.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
You are getting the image UIGraphicsGetImageFromCurrentImageContext() before you have actually drawn anything. Move this call to after your loop and before the UIGraphicsEndImageContext()
Your drawing actually occurs on the line
[image drawInRect:CGRectMake([theDict[#"x"] doubleValue],[theDict[#"y"] doubleValue],image.size.width,image.size.height)];
the function UIGraphicsGetImageFromCurrentImageContext() gives you the image of the current contents of the context so you need to ensure that you have done all your drawing before you grab the image.

How do I programmatically combine multiple UIImages into one long UIImage?

I'm using the code from here How can I programmatically put together some UIImages to have one big UIImage? to combine multiple screenshots into one large vertical image. However, I'm having trouble calling this function to combine multiple images together using:
imageContainer = [UIImage imageByCombiningImage:imageContainer withImage:viewImage];
How do I call this UIImage+combine category to merge the library of images together?
Here's my Code:
- (void) printScreen {
// this is a method that starts the screenshot taking process
// this line is necessary to capture the completion of the scrollView animation
_webView.scrollView.delegate = self;
// save the first image
UIGraphicsBeginImageContextWithOptions(_webView.bounds.size, NO, 0);
[_webView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(viewImage, nil, nil, nil);
// scroll to the next section
[_webView.scrollView scrollRectToVisible:CGRectMake(0, _webView.frame.size.height, _webView.frame.size.width, _webView.frame.size.height) animated:YES];
}
- (void )scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
// at this point the _webView scrolled to the next section
// I save the offset to make the code a little easier to read
CGFloat offset = _webView.scrollView.contentOffset.y;
UIGraphicsBeginImageContextWithOptions(_webView.bounds.size, NO, 0);
// note that the below line will not work if you replace _webView.layer with _webView.scrollView.layer
[_webView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image1 = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(image1, nil, nil, nil);
// if we are not done yet, scroll to next section
if (offset < _webView.scrollView.contentSize.height) {
[_webView.scrollView scrollRectToVisible:CGRectMake(0, _webView.frame.size.height+offset, _webView.frame.size.width, _webView.frame.size.height) animated:YES];
}
UIImage *image = [UIImage imageByCombiningImage:image1 withImage:image2];
[[self theNewImageView] setImage:image];
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
NSLog(#"%# printScreen Image", image);
NSLog(#"%# printScreen Image2", image2);
}
Edit:
At this point I've tried alot of different things. Im new to objective C development so I've been digging deep into the Apple developer docs and other good places for info like stack and lynda.
Im seeing two different codes from the logs: printScreen Image2, printScreen Image, but i just cant get the function to call the new category.
I'm able to write all the images in separate pieces to the photo album and I can merge image1 or image2 into one image but not the both images or all images.
I figured it out! Right in front of my face the entire time. I needed to add the call to the category within the scrollViewDidEndScrollingAnimation then save to the UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);. I probably tried a couple different version of this solution but I renamed some variables early on to align with my project which screwed everything up.

Change Back And Forth UIImages

Hi I’m trying to get an image to change on a method call and if the method is recalled the original image comes back
-(void)change
{
if ((player.image = [UIImage imageNamed:#"first.png"]))
{
player.image = [UIImage imageNamed:#"second.png"]));
}
else
{
player.image = [UIImage imageNamed:#"first.png"]));
}
}
This works change the "first.png" image to "second.png" but when called again it doesn’t.
Where am I going wrong?
As pointed out by Michael Dautermann, the way you're comparing two UIImages is wrong. Can't you simply keep an NSString property that tells you the image you're showing?
-(void)change
{
if ([self.displayedImageTitle isEqualToString:#"first.png"]){
player.image = [UIImage imageNamed:#"second.png"]));
self.displayedImageTitle = #"second.png";
}
else{
player.image = [UIImage imageNamed:#"first.png"]));
self.displayedImageTitle = #"first.png";
}
}
In your code above, you're making an invalid assumption that "[UIImage imageNamed: #"first.png"]" will always be the same UIImage object when you do a comparison. That isn't true. Every time you call the "imageNamed" API, you may be creating a brand new UIImage object.
Now, since UIImage object doesn't know anything about file names or image titles, you need to keep track of which image is being displayed and then toggle on that.
I'd suggest creating a subclassed UIImage object that has a filename or title property (that you would also need to set), or have your two UIImages as properties or ivars loaded into memory (that is, if these aren't giant memory hogging images) and then do your toggling.

UIImage becomes NSNumber

I am trying to save UIImage to app delegate. When I load that UIViewController for the first time, it returns UIImage(see first screen shot).
Help me ! Stuck here for almost 2 days.
But when I redirect back to that controller, UIImage becomes NSNumber. (see second screen shot)
Before I leave the controller I set the image to app delegate as follows
UIGraphicsBeginImageContextWithOptions(self.imageView.frame.size,YES, 0.0);
[self.imageView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
del.getImage = resultingImage;
This problem is most easily solved using the debugger. First, as the comments said, change the property name to say myImage. Then, in your UIViewController class, provide you own setter:
- (void)setMyImage:(UIImage *)myImage
{
NSLog(#"Image class: %#", NSStringFromClass([myImage class]));
if([myImage isKindOfClass:[NSNumber class]]) {
NSLog(#"YIKES: a number!");
}
_myImage = myImage; // assumes ARC
}
Put a breakpoint on the second NSLog, or both. When you hit the second breakpoint, look at the call stack and you will find out who is setting it.

Resources