CGImageCreateWithImageInRect not Cropping Correctl

2020-03-24 09:26发布

I'm having a hell of a time using CGImageCreateWithImageInRect to crop a photo. My app has the user move / enlarge an image till it fills a 316 x 316 view, then I want it to crop off any area outside the box and save the image as a UIImage. I determine the crop origin by taking the absolute value of the x and y imageview origin as that brings me back to 0,0 of the view / box that contains the imageview. Below is the code:

    CGRect croppedRect = CGRectMake(fabs(widthDistanceToOrigin), fabs(HeightDistanceToOrigin), 316, 316);
    CGImageRef croppedImageRef = CGImageCreateWithImageInRect(image.CGImage, croppedRect); 
    UIImage *croppedImage = [UIImage imageWithCGImage: croppedImageRef scale: 1 / (imageScale) orientation: image.imageOrientation];
    CGImageRelease(croppedImageRef); 

This is driving me crazy, I just can't get it to crop the area I want. I've got it to scale correctly, but the problem seems to be with the x and y origin of the crop rect, it's quite a bit off from the area it should be taking (and sometimes I get weird results).

Also, it seems for images taken with the phones camera, I have to multiply everything in my crop rect by 2 for it to be the correct size. Very weird.

So I'm wondering, does anyone know how to fix this, or does anyone possible have a better way of cropping (and please keep in mind that I need to crop an area within my photo). Thanks!

3条回答
Ridiculous、
2楼-- · 2020-03-24 09:47

I found the problem. I was trying to grab the crop area before I scaled the image. Now have to figure out how to reduce the image before I do "CGImageCreateWithImageInRect".

查看更多
我命由我不由天
3楼-- · 2020-03-24 09:58

I would like to provide more information/answer for this based on my own experience.

From the UIImage (and thus the CGImageCreateWithImageInRect:) perspective, (0, 0) is in the bottom left. When determining the crop square, you can simply calculate the square based on the standard portrait orientation and then use the method in @greenhouse's answer (posted again here for clarity and changed to use CGFloat to fix a casting error.

- (UIImage *)cropImage:(UIImage*)image toRect:(CGRect)rect {
    CGFloat (^rad)(CGFloat) = ^CGFloat(CGFloat deg) {
        return deg / 180.0f * (CGFloat) M_PI;
    };

    // determine the orientation of the image and apply a transformation to the crop rectangle to shift it to the correct position
    CGAffineTransform rectTransform;
    switch (image.imageOrientation) {
        case UIImageOrientationLeft:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -image.size.height);
            break;
        case UIImageOrientationRight:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -image.size.width, 0);
            break;
        case UIImageOrientationDown:
            rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -image.size.width, -image.size.height);
            break;
        default:
            rectTransform = CGAffineTransformIdentity;
    };

    // adjust the transformation scale based on the image scale
    rectTransform = CGAffineTransformScale(rectTransform, image.scale, image.scale);

    // apply the transformation to the rect to create a new, shifted rect
    CGRect transformedCropSquare = CGRectApplyAffineTransform(rect, rectTransform);
    // use the rect to crop the image
    CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, transformedCropSquare);
    // create a new UIImage and set the scale and orientation appropriately
    UIImage *result = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
    // memory cleanup
    CGImageRelease(imageRef);

    return result;
}

This code shifts the crop square so that it is in the correct relative position.

查看更多
甜甜的少女心
4楼-- · 2020-03-24 10:05

There are so many posts about this topic with all them having the same exact answer, to utilize: CGImageCreateWithImageInRect but none of them fully solve the problem of miss positioning of what is trying to be cropped.

However, only one thread (buried deep deep inside), has a minor detail that everyone else is missing... How to crop a UIImageView to a new UIImage in 'aspect fit' mode?

the 'rect' parameter that goes in CGImageCreateWithImageInRect(image.CGImage, croppedRect) needs to represent (taken from) the UIImage, NOT the UIImageView.

this should solve the issue of miss positioning on the coordinate system.

 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:   (NSDictionary *)info
 {
        oImage = [info valueForKey:UIImagePickerControllerOriginalImage];
        NSLog(@"Original Image size width: %f x height: %f", oImage.size.width, oImage.size.height);


        // crop image according to what the image picker view is displaying
        CGRect rect = CGRectMake(0, 40, 960.0f, 960.0f); // note: 960 x 1280 is what natively comes from capturing and image
        nImage = [BGViewModifiers cropImage:oImage inRect:rect];

        // scale image down for display and creating kombie
        CGSize size = CGSizeMake(320.0f, 320.0f);
        nImage = [BGViewModifiers imageFromImage:nImage scaledToSize:size];

        NSLog(@"New Image size width: %f x height: %f", [nImage size].width, [nImage size].height);
 }

 //ref: http://stackoverflow.com/a/25293588/2298002
 + (UIImage *)cropImage:(UIImage*)image inRect:(CGRect)rect
 {
    double (^rad)(double) = ^(double deg) {
       return deg / 180.0 * M_PI;
    };

    CGAffineTransform rectTransform;
    switch (image.imageOrientation) {
      case UIImageOrientationLeft:
          rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -image.size.height);
          break;
      case UIImageOrientationRight:
          rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -image.size.width, 0);
          break;
      case UIImageOrientationDown:
          rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -image.size.width, -image.size.height);
          break;
      default:
          rectTransform = CGAffineTransformIdentity;
  };
  rectTransform = CGAffineTransformScale(rectTransform, image.scale, image.scale);

  CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], CGRectApplyAffineTransform(rect, rectTransform));
  UIImage *result = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
  CGImageRelease(imageRef);

  return result;
 }

 + (UIImage*)imageFromImage:(UIImage*)image scaledToSize:(CGSize)newSize
 {
    UIGraphicsBeginImageContext( newSize );
    [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
 }
查看更多
登录 后发表回答