如何执行方形切割相机胶卷中的照片? [英] How to perform square cut to the photos in camera roll?

查看:153
本文介绍了如何执行方形切割相机胶卷中的照片?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Instagram上尝试一些像Instagram的图像过滤功能。
我使用imagePickerController从相机胶卷获取照片。我理解,imagePickerController返回的图像被减少以节省内存。将原始图像加载到UIImage是不明智的。但是如何处理图像,然后将其保存为原始像素?
我使用iPhone 4S作为我的开发设备。

I would like to try some image filter features on iPhone like instagram does. I use imagePickerController to get photo from camera roll. I understand that the image return by imagePickerController was reduced to save memory. And it's not wise to load the original image to an UIImage. But how can I processe the image then save it back as the original pixels? I use iPhone 4S as my development device.

相机胶卷中的原始相片为3264 * 2448。

The original photo in camera roll is 3264 * 2448.

UIImagePickerControllerOriginalImage返回的图片为1920 * 1440

The image return by UIImagePickerControllerOriginalImage is 1920 * 1440

由UIImagePickerControllerEditedImage返回的图片为640 * 640

The image return by UIImagePickerControllerEditedImage is 640 * 640

imageViewOld(使用UIImagePickerControllerCropRect [80,216,1280,1280]通过UIImagePickerControllerOriginalImage裁剪图像)是1280 * 1224

imageViewOld(use UIImagePickerControllerCropRect [80,216,1280,1280] to crop the image return by UIImagePickerControllerOriginalImage) is 1280 * 1224

imageViewNew(使用双倍大小的UIImagePickerControllerCropRect [80,216,2560,2560]裁剪由UIImagePickerControllerOriginalImage返回的图像)是1840 * 1224。

imageViewNew(use double sized UIImagePickerControllerCropRect [80,216,2560,2560] to crop the image return by UIImagePickerControllerOriginalImage) is 1840 * 1224.

我检查同一张照片按照instagram是1280 * 1280

I check the same photo proceed by instagram is 1280 * 1280

我的问题是: / p>

My questions are:


  1. 为什么UIImagePickerControllerOriginalImage不会返回原始照片?为什么要将图片缩小到1920 * 1440?

  2. 为什么UIImagePickerControllerEditedImage不会以1280 * 1280返回图片?由于

    UIImagePickerControllerCropRect显示它被削减了1280 * 1280平方?

  1. Why UIImagePickerControllerOriginalImage does not return the "Original" photo? Why reduced it to 1920 * 1440?
  2. Why UIImagePickerControllerEditedImage does not return the image by 1280 * 1280? As the
    UIImagePickerControllerCropRect shows it is cut by 1280 * 1280 square?

如何对原始照片进行正方形裁剪a 2448 * 2448 image?

How can I do a square cut to original photo to be a 2448 * 2448 image?


下面是我的代码:

Thanks in advance. Below is my code:

  - (void)imagePickerController:(UIImagePickerController *)picker  didFinishPickingMediaWithInfo:(NSDictionary *)info
  {

   NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
   if ([mediaType isEqualToString:@"public.image"])
   {

    UIImage *imageEdited = [info objectForKey:UIImagePickerControllerEditedImage];
    UIImage *imagePicked = [info objectForKey:UIImagePickerControllerOriginalImage];

    CGRect cropRect;
    cropRect = [[info valueForKey:@"UIImagePickerControllerCropRect"] CGRectValue];

    NSLog(@"Original width = %f height= %f ",imagePicked.size.width, imagePicked.size.height);
    //Original width = 1440.000000 height= 1920.000000

    NSLog(@"imageEdited width = %f height = %f",imageEdited.size.width, imageEdited.size.height);
    //imageEdited width = 640.000000 height = 640.000000

    NSLog(@"corpRect %f %f %f %f", cropRect.origin.x, cropRect.origin.y , cropRect.size.width, cropRect.size.height);
    //corpRect 80.000000 216.000000 1280.000000 1280.000000

    CGRect rectNew = CGRectMake(cropRect.origin.x, cropRect.origin.y , cropRect.size.width*2, cropRect.size.height*2);

    CGRect rectOld = CGRectMake(cropRect.origin.x, cropRect.origin.y , cropRect.size.width, cropRect.size.height);

    CGImageRef imageRefNew = CGImageCreateWithImageInRect([imagePicked CGImage], rectNew);
    CGImageRef imageRefOld = CGImageCreateWithImageInRect([imagePicked CGImage], rectOld);

    UIImageView *imageViewNew = [[UIImageView alloc] initWithImage:[UIImage imageWithCGImage:imageRefNew]];
    CGImageRelease(imageRefNew);

    UIImageView *imageViewOld = [[UIImageView alloc] initWithImage:[UIImage imageWithCGImage:imageRefOld]];
    CGImageRelease(imageRefOld);


    NSLog(@"imageViewNew width = %f height = %f",imageViewNew.image.size.width, imageViewNew.image.size.height);
    //imageViewNew width = 1840.000000 height = 1224.000000

    NSLog(@"imageViewOld width = %f height = %f",imageViewOld.image.size.width, imageViewOld.image.size.height);
    //imageViewOld width = 1280.000000 height = 1224.000000

     UIImageWriteToSavedPhotosAlbum(imageEdited, nil, nil, NULL);

     UIImageWriteToSavedPhotosAlbum([imageViewNew.image imageRotatedByDegrees:90.0], nil, nil, NULL);
     UIImageWriteToSavedPhotosAlbum([imageViewOld.image imageRotatedByDegrees:90.0], nil, nil, NULL);


    //assign the image to an UIImage Control
    self.imageV.contentMode = UIViewContentModeScaleAspectFit;
    self.imageV.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.width);
    self.imageV.image = imageEdited;


  }

  [self dismissModalViewControllerAnimated:YES];

 }


推荐答案

已观察到UIImagePickerController将返回缩小编辑图像有时640x640有时320x320(设备相关)。

As you have observed the UIImagePickerController will return a scaled down edited image sometimes 640x640 sometimes 320x320 (device dependent).

您的问题:


如何对原始相片进行方形切割要成为一个2448 * 2448的图像?

How can I do a square cut to original photo to be a 2448 * 2448 image?

为此,您需要先使用 UIImagePickerControllerCropRect 使用信息字典的 UIImagePickerControllerOriginalImage 键从原始图像创建新图像。使用Quartz Core方法, CGImageCreateWithImageInRect 可以创建一个新图像,其中只包含由传递矩形限定的像素;在这种情况下是作物矩形。您将需要考虑方向,以使其正常工作。然后,您只需要缩放图像到您想要的大小。重要的是要注意,裁剪矩形相对于原始图像,当它已经被正确定向后,而不是它从相机或照片库。这是为什么当我们开始使用Quartz方法创建新图片时,我们需要转换裁剪矩形以匹配方向。

To do this you need to first use the UIImagePickerControllerCropRect to create a new image from the original image obtained using the UIImagePickerControllerOriginalImage key of the info dictionary. Using the Quartz Core method, CGImageCreateWithImageInRect you can create a new image that only contains the pixels bounded by the passed rect; in this case the crop rect. You will need to take into account orientation in order for this to work properly. Then you need only scale the image to your desired size. It's important to note that the crop rect is relative to the original image when after it has been oriented correctly, not as it comes out of the camera or photo library. This is why we need to transform the crop rect to match the orientation when we start using Quartz methods to create new images, etc.

我把你的代码放在上面,最后基于裁剪矩形从原始图像创建1280x1280图像。在这里仍然有一些边缘情况,即考虑到crop rect有时可能有负值,(代码假设一个正方形croprect rect)尚未解决。

I took your code above and set it up to create a 1280x1280 image from the original image based on the crop rect. There are still some edge cases here, i.e. taking into account that the crop rect can sometimes have negative values, (the code assumes a square cropping rect) that have not been addressed.


  1. 首先转换裁剪矩形,以考虑到传入图像和大小的方向。此 transformCGRectForUIImageOrientation 函数来自 NiftyBean

  2. 创建一个裁剪到转换后裁剪区域的图片。

  3. 缩放图像到所需的大小。即1280x1280。

  4. 从CGImage以正确的比例和方向创建UIImage。

  1. First transform the crop rect to take into account the orientation of the incoming image and size. This transformCGRectForUIImageOrientation function is from NiftyBean
  2. Create an image that is cropped to the transformed cropping rect.
  3. Scale (and rotate) the image to the desired size. i.e. 1280x1280.
  4. Create a UIImage from the CGImage with correct scale and orientation.

更改: UPDATE 已在此下添加新代码,以便处理缺少的案例。

Here is your code with the changes: UPDATE New code has been added below this that should take care of the missing cases.

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:@"public.image"])
{

    UIImage *imageEdited = [info objectForKey:UIImagePickerControllerEditedImage];
    UIImage *imagePicked = [info objectForKey:UIImagePickerControllerOriginalImage];

    CGRect cropRect;
    cropRect = [[info valueForKey:@"UIImagePickerControllerCropRect"] CGRectValue];

    NSLog(@"Original width = %f height= %f ",imagePicked.size.width, imagePicked.size.height);
    //Original width = 1440.000000 height= 1920.000000

    NSLog(@"imageEdited width = %f height = %f",imageEdited.size.width, imageEdited.size.height);
    //imageEdited width = 640.000000 height = 640.000000

    NSLog(@"corpRect %@", NSStringFromCGRect(cropRect));
    //corpRect 80.000000 216.000000 1280.000000 1280.000000

    CGSize finalSize = CGSizeMake(1280,1280); 
    CGImageRef imagePickedRef = imagePicked.CGImage;

    CGRect transformedRect = transformCGRectForUIImageOrientation(cropRect, imagePicked.imageOrientation, imagePicked.size);
    CGImageRef cropRectImage = CGImageCreateWithImageInRect(imagePickedRef, transformedRect);
    CGColorSpaceRef colorspace = CGImageGetColorSpace(imagePickedRef);
    CGContextRef context = CGBitmapContextCreate(NULL, 
                                                 finalSize.width, 
                                                 finalSize.height,
                                                 CGImageGetBitsPerComponent(imagePickedRef),
                                                 CGImageGetBytesPerRow(imagePickedRef),
                                                 colorspace,
                                                 CGImageGetAlphaInfo(imagePickedRef));
    CGContextSetInterpolationQuality(context, kCGInterpolationHigh); //Give the context a hint that we want high quality during the scale
    CGContextDrawImage(context, CGRectMake(0, 0, finalSize.width, finalSize.height), cropRectImage);
    CGImageRelease(cropRectImage);

    CGImageRef instaImage = CGBitmapContextCreateImage(context);
    CGContextRelease(context);

    //assign the image to an UIImage Control
    UIImage *image = [UIImage imageWithCGImage:instaImage scale:imagePicked.scale orientation:imagePicked.imageOrientation];
    self.imageView.contentMode = UIViewContentModeScaleAspectFit;
    self.imageView.image = image;
    CGImageRelease(instaImage);

    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}

[self dismissModalViewControllerAnimated:YES];

}

CGRect transformCGRectForUIImageOrientation(CGRect source, UIImageOrientation orientation, CGSize imageSize) {
switch (orientation) {
    case UIImageOrientationLeft: { // EXIF #8
        CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
        CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI_2);
        return CGRectApplyAffineTransform(source, txCompound);
    }
    case UIImageOrientationDown: { // EXIF #3
        CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
        CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI);
        return CGRectApplyAffineTransform(source, txCompound);
    }
    case UIImageOrientationRight: { // EXIF #6
        CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(0.0, imageSize.width);
        CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI + M_PI_2);
        return CGRectApplyAffineTransform(source, txCompound);
    }
    case UIImageOrientationUp: // EXIF #1 - do nothing
    default: // EXIF 2,4,5,7 - ignore
        return source;
}
}

UPDATE 一些方法将处理其余的情况。
步骤基本相同,有几个修改。

UPDATE I have made a couple of methods that will take care of the rest of the cases. The steps are basically the same, with a couple of modifications.


  1. 第一个修改是正确转换和缩放上下文以处理传入图像的方向,

  2. ,第二个是支持非正方形作物,你可以从
    UIImagePickerController 获得。在这些情况下,方形图片是以您选择的颜色填充的

  1. First modification is to correctly transform and scale the context to handle the orientation of the incoming image,
  2. and the second is to support the non square crops you can get from the UIImagePickerController. In these cases the square image is filled with a color of your choosing.

新代码

// CropRect is assumed to be in UIImageOrientationUp, as it is delivered this way from the UIImagePickerController when using AllowsImageEditing is on.
// The sourceImage can be in any orientation, the crop will be transformed to match
// The output image bounds define the final size of the image, the image will be scaled to fit,(AspectFit) the bounds, the fill color will be
// used for areas that are not covered by the scaled image. 
-(UIImage *)cropImage:(UIImage *)sourceImage cropRect:(CGRect)cropRect aspectFitBounds:(CGSize)finalImageSize fillColor:(UIColor *)fillColor {

CGImageRef sourceImageRef = sourceImage.CGImage;

//Since the crop rect is in UIImageOrientationUp we need to transform it to match the source image.
CGAffineTransform rectTransform = [self transformSize:sourceImage.size orientation:sourceImage.imageOrientation];
CGRect transformedRect = CGRectApplyAffineTransform(cropRect, rectTransform);

//Now we get just the region of the source image that we are interested in.
CGImageRef cropRectImage = CGImageCreateWithImageInRect(sourceImageRef, transformedRect);

//Figure out which dimension fits within our final size and calculate the aspect correct rect that will fit in our new bounds
CGFloat horizontalRatio = finalImageSize.width / CGImageGetWidth(cropRectImage);
CGFloat verticalRatio = finalImageSize.height / CGImageGetHeight(cropRectImage);
CGFloat ratio = MIN(horizontalRatio, verticalRatio); //Aspect Fit
CGSize aspectFitSize = CGSizeMake(CGImageGetWidth(cropRectImage) * ratio, CGImageGetHeight(cropRectImage) * ratio);


CGContextRef context = CGBitmapContextCreate(NULL,
                                             finalImageSize.width,
                                             finalImageSize.height,
                                             CGImageGetBitsPerComponent(cropRectImage),
                                             0,
                                             CGImageGetColorSpace(cropRectImage),
                                             CGImageGetBitmapInfo(cropRectImage));

if (context == NULL) {
    NSLog(@"NULL CONTEXT!");
}

//Fill with our background color
CGContextSetFillColorWithColor(context, fillColor.CGColor);
CGContextFillRect(context, CGRectMake(0, 0, finalImageSize.width, finalImageSize.height));

//We need to rotate and transform the context based on the orientation of the source image.
CGAffineTransform contextTransform = [self transformSize:finalImageSize orientation:sourceImage.imageOrientation];
CGContextConcatCTM(context, contextTransform);

//Give the context a hint that we want high quality during the scale
CGContextSetInterpolationQuality(context, kCGInterpolationHigh); 

//Draw our image centered vertically and horizontally in our context.
CGContextDrawImage(context, CGRectMake((finalImageSize.width-aspectFitSize.width)/2, (finalImageSize.height-aspectFitSize.height)/2, aspectFitSize.width, aspectFitSize.height), cropRectImage);

//Start cleaning up..
CGImageRelease(cropRectImage);

CGImageRef finalImageRef = CGBitmapContextCreateImage(context);
UIImage *finalImage = [UIImage imageWithCGImage:finalImageRef];

CGContextRelease(context);
CGImageRelease(finalImageRef);
return finalImage;
}

//Creates a transform that will correctly rotate and translate for the passed orientation.
//Based on code from niftyBean.com
- (CGAffineTransform) transformSize:(CGSize)imageSize orientation:(UIImageOrientation)orientation {

CGAffineTransform transform = CGAffineTransformIdentity;
switch (orientation) {
    case UIImageOrientationLeft: { // EXIF #8
        CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
        CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI_2);
        transform = txCompound;
        break;
    }
    case UIImageOrientationDown: { // EXIF #3
        CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
        CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI);
        transform = txCompound;
        break;
    }
    case UIImageOrientationRight: { // EXIF #6
        CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(0.0, imageSize.width);
        CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,-M_PI_2);
        transform = txCompound;
        break;
    }
    case UIImageOrientationUp: // EXIF #1 - do nothing
    default: // EXIF 2,4,5,7 - ignore
        break;
}
return transform;

}

这篇关于如何执行方形切割相机胶卷中的照片?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆