Iphone 如何对相机卷中的照片进行方形剪切?

Iphone 如何对相机卷中的照片进行方形剪切?,iphone,camera,Iphone,Camera,我想像instagram一样在iPhone上尝试一些图像过滤功能。 我使用imagePickerController从相机卷中获取照片。据我所知,imagePickerController返回的图像已减少,以节省内存。将原始图像加载到UIImage是不明智的。但是如何处理图像,然后将其保存回原始像素? 我使用iphone4s作为我的开发设备 相机卷中的原始照片为3264*2448 UIImagePickerControllerOriginalImage返回的图像为1920*1440 UIImag

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

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

UIImagePickerControllerOriginalImage返回的图像为1920*1440

UIImagePickerControllerEditedImage返回的图像为640*640

imageViewOld(使用UIIMAGEPICKERCONTROLERCROPRECT[80216112801280]裁剪UIIMAGEPICKERCONTROLERORIGINALIMAGE返回的图像)为1280*1224

imageViewNew(使用双尺寸UIImagePickerControllerCropRect[802162560]裁剪UIImagePickerControllerOriginalImage返回的图像)为1840*1224

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

我的问题是:

  • 为什么UIImagePickerController原始图像不返回“原始”照片?为什么将其减少到1920*1440
  • 为什么UIImagePickerControllerEditedImage不按1280*1280返回图像?作为
    UIIMAGEPICKERCONTROLERCROPRECT显示它被切割1280*1280平方米

  • 如何将原始照片进行方形切割,使其成为2448*2448图像

  • 提前谢谢。 下面是我的代码:

      - (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(取决于设备)

    你的问题:

    如何将原始照片进行方形切割,使其成为2448*2448图像

    为此,您需要首先使用
    UIImagePickerControllerCropRect
    从使用信息字典的
    UIImagePickerControllerOriginalImage
    键获得的原始图像创建新图像。使用Quartz Core方法,
    CGImageCreateWithImageInRect
    可以创建一个新图像,该图像仅包含由传递的rect限定的像素;在本例中,裁剪矩形。为了使其正常工作,您需要考虑方向。然后只需将图像缩放到所需大小。重要的是要注意,裁剪矩形在正确定向后是相对于原始图像的,而不是从相机或照片库中出来的。这就是为什么当我们开始使用石英方法创建新图像时,我们需要变换裁剪矩形以匹配方向,等等

    我将上面的代码设置为基于裁剪矩形从原始图像创建1280x1280图像。这里仍然存在一些边缘情况,即考虑到裁剪矩形有时可能具有未解决的负值(代码假定为方形裁剪矩形)

  • 首先变换裁剪矩形以考虑传入图像的方向和大小。此
    transformCGRectForUIImageOrientation
    函数来自
  • 创建裁剪为变换裁剪矩形的图像
  • 将图像缩放(并旋转)到所需大小。i、 e.1280x1280
  • 从CGImage创建具有正确比例和方向的UIImage
  • 以下是您的代码及其更改:更新在下面添加了新代码,可以处理丢失的案例

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

    更新我已经制定了一些方法来处理其余的案例。 这些步骤基本相同,只是做了一些修改

  • 第一个修改是正确变换和缩放上下文,以处理传入图像的方向
  • 第二是支持你可以从中获得的非方形作物
    UIImagePickerController
    。在这些情况下,方形图像是 充满了你选择的颜色
  • 新代码

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

    是 啊它确实有用!你能告诉我为什么UIImagePickerController不给我相机胶卷中的原始图像吗?我不知道背后的原因是什么。我观察到,当你用相机拍照时,你肯定会得到一个全分辨率的版本。如果您需要获得完整的分辨率版本,我认为您可以使用
    UIImagePickerControllerReferenceURL
    ALAssetLibrary
    类来检索它。使用此框架将要求您的用户获得访问其位置的权限,因为原始图像将被地理标记。此外。。更新了代码以更合理地处理旋转,并且即使裁剪矩形不是方形,也可以处理获得方形图像。希望有帮助。你的代码解决了我的一天,尝试了很多没有正确结果的解决方案,你的“新代码”做得很好,旋转和缩放。谢谢不幸的是,这在所有iphone上都能很好地工作,而不是iPad
    // 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;
    
    }