简体   繁体   English

如何在相机胶卷中对照片进行方形切割?

[英]How to perform square cut to the photos in camera roll?

I would like to try some image filter features on iPhone like instagram does. 我想尝试iPhone上的一些图像过滤功能,就像Instagram一样。 I use imagePickerController to get photo from camera roll. 我使用imagePickerController从相机胶卷中获取照片。 I understand that the image return by imagePickerController was reduced to save memory. 据我所知,imagePickerController返回的图像被减少以节省内存。 And it's not wise to load the original image to an UIImage. 将原始图像加载到UIImage并不明智。 But how can I processe the image then save it back as the original pixels? 但是,我如何处理图像然后将其保存为原始像素? I use iPhone 4S as my development device. 我使用iPhone 4S作为我的开发设备。

The original photo in camera roll is 3264 * 2448. 相机胶卷中的原始照片为3264 * 2448。

The image return by UIImagePickerControllerOriginalImage is 1920 * 1440 UIImagePickerControllerOriginalImage返回的图像是1920 * 1440

The image return by UIImagePickerControllerEditedImage is 640 * 640 UIImagePickerControllerEditedImage返回的图像为640 * 640

imageViewOld(use UIImagePickerControllerCropRect [80,216,1280,1280] to crop the image return by UIImagePickerControllerOriginalImage) is 1280 * 1224 imageViewOld(使用UIImagePickerControllerCropRect [80,216,1280,1280]裁剪图像返回UIImagePickerControllerOriginalImage)是1280 * 1224

imageViewNew(use double sized UIImagePickerControllerCropRect [80,216,2560,2560] to crop the image return by UIImagePickerControllerOriginalImage) is 1840 * 1224. imageViewNew(使用双倍大小的UIImagePickerControllerCropRect [80,216,2560,2560]来裁剪UIImagePickerControllerOriginalImage返回的图像)是1840 * 1224。

I check the same photo proceed by instagram is 1280 * 1280 我检查同一张照片继续Instagram是1280 * 1280

My questions are: 我的问题是:

  1. Why UIImagePickerControllerOriginalImage does not return the "Original" photo? 为什么UIImagePickerControllerOriginalImage不会返回“原始”照片? Why reduced it to 1920 * 1440? 为什么减少到1920 * 1440?
  2. Why UIImagePickerControllerEditedImage does not return the image by 1280 * 1280? 为什么UIImagePickerControllerEditedImage不会返回1280 * 1280的图像? As the 作为
    UIImagePickerControllerCropRect shows it is cut by 1280 * 1280 square? UIImagePickerControllerCropRect显示它被1280 * 1280平方切割?

  3. How can I do a square cut to original photo to be a 2448 * 2448 image? 如何将原始照片的正方形切割为2448 * 2448图像?

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

 }

As you have observed the UIImagePickerController will return a scaled down edited image sometimes 640x640 sometimes 320x320 (device dependent). 正如您所观察到的那样,UIImagePickerController将返回缩小的编辑图像,有时640x640有时为320x320(取决于设备)。

Your question: 你的问题:

How can I do a square cut to original photo to be a 2448 * 2448 image? 如何将原始照片的正方形切割为2448 * 2448图像?

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. 为此,您需要首先使用UIImagePickerControllerCropRect从使用信息字典的UIImagePickerControllerOriginalImage键获取的原始图像创建新图像。 Using the Quartz Core method, CGImageCreateWithImageInRect you can create a new image that only contains the pixels bounded by the passed rect; 使用Quartz Core方法CGImageCreateWithImageInRect您可以创建一个新图像,该图像仅包含由传递的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. 这就是为什么当我们开始使用Quartz方法创建新图像等时,我们需要转换裁剪矩形以匹配方向。

I took your code above and set it up to create a 1280x1280 image from the original image based on the crop rect. 我将上面的代码设置为基于裁剪矩形从原始图像创建1280x1280图像。 There are still some edge cases here, ie 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. First transform the crop rect to take into account the orientation of the incoming image and size. 首先变换裁剪矩形以考虑输入图像和大小的方向。 This transformCGRectForUIImageOrientation function is from NiftyBean transformCGRectForUIImageOrientation函数来自NiftyBean
  2. Create an image that is cropped to the transformed cropping rect. 创建裁剪为变换后的裁剪矩形的图像。
  3. Scale (and rotate) the image to the desired size. 将图像缩放(并旋转)到所需的大小。 ie 1280x1280. 即1280x1280。
  4. Create a UIImage from the CGImage with correct scale and orientation. 使用正确的比例和方向从CGImage创建UIImage。

Here is your code with the changes: UPDATE New code has been added below this that should take care of the missing cases. 以下是包含更改的代码: UPDATE在此下面添加了新代码,可以处理丢失的情况。

- (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 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. 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 . 第二个是支持你可以从UIImagePickerController获得的非方形作物。 In these cases the square image is filled with a color of your choosing. 在这些情况下,方形图像将填充您选择的颜色。

New Code 新规范

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

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何从相机胶卷中获取照片? - How to get photos from camera roll? 如何将使用iOS SDK拍摄的照片添加到用户的相机胶卷中? - How to add photos taken with the iOS SDK to the user's camera roll? 将相机卷照片获取到自定义集合视图 - Get Camera Roll photos to a Custom Collection View 从iPhone的相机胶卷中选择多张照片 - Select multiple photos from camera roll in iPhone 如何自动将相机胶卷中的所有照片上传到亚马逊S3存储桶中,例如相机同步或保管箱 - How to auto upload the camera roll all photos to amazon s3 bucket like camera sync or dropbox doing Phonegap:显示相机胶卷中的照片列表吗? - Phonegap: display list of photos in camera roll? iPhone - 如何以编程方式创建自定义相册并为相机胶卷中的照片指定自定义名称? - iPhone - How to create a custom album and give custom names to photos in camera roll programmatically? 如何使用PhoneGap的文件API删除从iPhone相机胶卷的照片? - How to delete photos from camera roll in iphone using phonegap file api? 未经用户明确同意,我可以将照片保存到相机胶卷吗? - Can i save photos to the camera roll without user explicit consent? iPhone有没有办法分析相机胶卷上所有照片的时间戳? - iPhone is there a way to analyze timestamps of all photos on the camera roll?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM