Merging a previosly rotated by gesture UIImageView

2019-02-05 16:17发布

问题:

I'm getting crazy while trying to merge two UIImageView.

The situation:

  • a background UIImageView (userPhotoImageView)
  • an overlayed UIImageView (productPhotoImageView) that can be streched, pinched and rotated

I call my function on the UIImages but I can take coords and new stretched size from the UIImageView containing them (they are synthesized in my class)

    - (UIImage *)mergeImage:(UIImage *)bottomImg withImage:(UIImage *)topImg;

Maybe simplest way would be rendering the layer of the top UIImageView in a the new CGContextRef like this:

    [bottomImg drawInRect:CGRectMake(0, 0, bottomImg.size.width, bottomImg.size.height)];
    [productPhotoImageView.layer renderInContext:ctx];

But in this way I loose the rotation effect previosly applied by gestures.

A second way would be trying to apply AffineTransformation to UIImage to reproduce GestureEffects and then draw it in the context like this:

    UIImage * scaledTopImg = [topImg imageByScalingProportionallyToSize:productPhotoView.frame.size];
    UIImage * rotatedScaledTopImg = [scaledTopImg imageRotatedByDegrees:ANGLE];    
    [rotatedScaledTopImg drawAtPoint:CGPointMake(productPhotoView.frame.origin.x, productPhotoView.frame.origin.y)];

The problem of this second approach is that I'm not able to exactly get the final rotation degrees (the ANGLE parameter that should be filled in the code above) amount since the user started to interact, this because the RotationGesture is reset to 0 after applying so the next callback is a delta from the current rotation.

For sure the most easy way would be the first one, freezing the two UIImageViews as they are displayed in that very moment but actually I still didn't find anyway to do it.

回答1:

Ok basically there is another workaround for all this crazy merging stuff, but it's definitively not an elegant solution. For avoid handling any kind of AffineTransformation just capture the ImageScreen and then crop it.

CGImageRef screenImage = UIGetScreenImage();
CGRect fullRect = [[UIScreen mainScreen] applicationFrame];
CGImageRef saveCGImage = CGImageCreateWithImageInRect(screenImage, fullRect);
CGRect cropRect = CGRectMake(x,y,width,height);
CGImageRef saveCGImage = CGImageCreateWithImageInRect(screenImage, cropRect);

Told you it wasnt elegant, but for someone it could be useful.



回答2:

Great that was helpful and so too much workaroundy ;)

so since i see it's pretty hard to find around some code examples to merge pics after a manipulation here goes mine, hope it can be helpful:

- (UIImage *)mergeImage:(UIImage *)bottomImg withImage:(UIImage *)topImg {

    UIImage * scaledTopImg = [topImg imageByScalingProportionallyToSize:productPhotoView.frame.size];

    UIGraphicsBeginImageContext(scaledTopImg.size);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(ctx, scaledTopImg.size.width * 0.5f, scaledTopImg.size.height  * 0.5f);    
    CGFloat angle = atan2(productPhotoView.transform.b, productPhotoView.transform.a);    
    CGContextRotateCTM(ctx, angle);    
    [scaledTopImg drawInRect:CGRectMake(- scaledTopImg.size.width * 0.5f, -(scaledTopImg.size.height  * 0.5f), scaledTopImg.size.width, scaledTopImg.size.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIGraphicsBeginImageContext(bottomImg.size);
    [bottomImg drawInRect:CGRectMake(0, 0, bottomImg.size.width, bottomImg.size.height)];    
    [newImage drawInRect:CGRectMake(productPhotoView.frame.origin.x, productPhotoView.frame.origin.y, newImage.size.width, newImage.size.height)];
    UIImage *newImage2 = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();    

    return newImage2;
}

Since I got a background image it was easier first create a context just to apply tranformation to the overlayview, than save it and write on top of the bottom layer.

Take care of the CTM translation before rotating the overlayview or it will rotate around an axis placed at {0,0} while I want to rotate my image around its center.

Regards



回答3:

I have the same problem.

I only have problem with rotation.

I use gesture recognizers for move, scale and rotation.

At the beginning when I save the image tha scale was right, the position was right but never apply rotation to the saved image.

Now it works

if you want to know the rotation angle I get it with:

CGFloat angle = atan2(overlay.transform.b, overlay.transform.a);

And rotation with:

CGContextRotateCTM(context, angle);

If you have a different approach please let me know.