Search code examples
iosobjective-csdkuiimageuigraphicscontext

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

Solution

  • 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.