8

更新:

在 iPhone OS 3.0+ 中,整个 UIImagePickerController API 发生了变化。这个问题和答案应该考虑2.2。遗留代码。


当使用 UIImagePickerController 并且您允许编辑图像时。iPhone 允许用户调整和平移图像。但是,已编辑图像的最大尺寸上限为 320x320。

例如,我截取了一张 iPhone 屏幕截图并将其放入照片库中,即 480x320 png。当我使用 UIImagePickerController 选择该图像时,即使我不缩放或平移图像,它也会在从 UIImagePickerController 返回之前被裁剪为 320x320。但是,如果我关闭编辑,图像将返回正确的 480x320 尺寸。

我的理论:非常巧妙的是,iPhone 显示了 2 个覆盖在图像上的非标准半透明工具栏。这些工具栏在照片上留下一个无害的 320x320“窗口”。在我看来,这个窗口有效地剪辑了底层照片。

注意:回调还返回一个带有原始图像和剪辑矩形的编辑字典,但当然矩形也是最大 320x320。

关于如何允许缩放和平移大于 320x320 的图像的任何想法?

一些代码:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {

        self.myImageView.userInteractionEnabled=YES;
        CGRect imageFrame = myImageView.frame;
        CGPoint imageCenter = myImageView.center;
        imageFrame.size = img.size;
        myImageView.frame = imageFrame;
        self.myImageView.image = img;
        myImageView.center = imageCenter;

        [self dismissModalViewControllerAnimated:YES];
        [self performSelector:@selector(hideToolBars) withObject:nil afterDelay:2.0];
    }
4

6 回答 6

7

正如克雷格所说,这是开发论坛和苹果定期讨论板中的一个问题。但是,我确实找到了解决方法。我正在使用以下代码:

苹果开发者论坛

这包括您需要的大部分内容,并处理所有相机方向问题。我添加了以下内容,这些内容将接收编辑信息并使用它来获取原始裁剪矩形:

- (UIImage*)scaleImage:(UIImage*)anImage withEditingInfo:(NSDictionary*)editInfo{

    UIImage *newImage;

    UIImage *originalImage = [editInfo valueForKey:@"UIImagePickerControllerOriginalImage"];
    CGSize originalSize = CGSizeMake(originalImage.size.width, originalImage.size.height);
    CGRect originalFrame;
    originalFrame.origin = CGPointMake(0,0);
    originalFrame.size = originalSize;

    CGRect croppingRect = [[editInfo valueForKey:@"UIImagePickerControllerCropRect"] CGRectValue];
    CGSize croppingRectSize = CGSizeMake(croppingRect.size.width, croppingRect.size.height);

    CGSize croppedScaledImageSize = anImage.size;

    float scaledBarClipHeight = 80;

    CGSize scaledImageSize;
    float scale;

    if(!CGSizeEqualToSize(croppedScaledImageSize, originalSize)){

        scale = croppedScaledImageSize.width/croppingRectSize.width;
        float barClipHeight = scaledBarClipHeight/scale;

        croppingRect.origin.y -= barClipHeight;
        croppingRect.size.height += (2*barClipHeight);

        if(croppingRect.origin.y<=0){
            croppingRect.size.height += croppingRect.origin.y;
            croppingRect.origin.y=0;
        }

        if(croppingRect.size.height > (originalSize.height - croppingRect.origin.y)){
            croppingRect.size.height = (originalSize.height - croppingRect.origin.y);
        }


        scaledImageSize = croppingRect.size;
        scaledImageSize.width *= scale;
        scaledImageSize.height *= scale;

        newImage =  [self cropImage:originalImage to:croppingRect andScaleTo:scaledImageSize];

    }else{

        newImage = originalImage;

    }

    return newImage;
}

我将开发论坛帖子中的回调方法更新为以下内容:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {

    [self dismissModalViewControllerAnimated:YES];
    self.myImageView.userInteractionEnabled=YES;
    CGRect imageFrame = myImageView.frame;
    CGPoint imageCenter = myImageView.center;
    UIImage *croppedImage;


    NSMutableDictionary *imageDescriptor = [editInfo mutableCopy];

    // CGFloat scaleSize = 400.0f;
    CGFloat scaleSize = 640.0f;
    switch ([picker sourceType]) {
            //done
        case UIImagePickerControllerSourceTypePhotoLibrary:
            croppedImage = [self scaleImage:img withEditingInfo:editInfo];
            [imageDescriptor setObject:croppedImage forKey:@"croppedImage"];
            break;


        case UIImagePickerControllerSourceTypeCamera: {
            UIImageOrientation originalOrientation = [[editInfo objectForKey:UIImagePickerControllerOriginalImage] imageOrientation];
            if (originalOrientation != UIImageOrientationUp) {
                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
                CGRect origRect;
                [[editInfo objectForKey:UIImagePickerControllerCropRect] getValue:&origRect];
                UIImage *rotatedImage = straightenAndScaleImage([editInfo objectForKey:UIImagePickerControllerOriginalImage], scaleSize);
                CGFloat scale = scaleSize/1600.0f;
                origRect.origin.x *= scale;
                origRect.origin.y *= scale;
                origRect.size.width *= scale;
                origRect.size.height *= scale;
                croppedImage = [self cropImage:rotatedImage to:origRect andScaleTo:CGSizeMake(320, 480)];
                [imageDescriptor setObject:croppedImage forKey:@"croppedImage"];
                [pool drain];
            }
            else {
                croppedImage = [self scaleImage:img withEditingInfo:editInfo];
                [imageDescriptor setObject:croppedImage forKey:@"croppedImage"];
            }
        }
            break;

        case UIImagePickerControllerSourceTypeSavedPhotosAlbum: {
            UIImageOrientation originalOrientation = [[editInfo objectForKey:UIImagePickerControllerOriginalImage] imageOrientation];
            if (originalOrientation != UIImageOrientationUp) {
                NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
                CGRect origRect;
                [[editInfo objectForKey:UIImagePickerControllerCropRect] getValue:&origRect];
                UIImage *rotatedImage = straightenAndScaleImage([editInfo objectForKey:UIImagePickerControllerOriginalImage], scaleSize);
                CGFloat scale = scaleSize/640.0f;
                origRect.origin.x *= scale;
                origRect.origin.y *= scale;
                origRect.size.width *= scale;
                origRect.size.height *= scale;
                croppedImage = [self cropImage:rotatedImage to:origRect andScaleTo:CGSizeMake(320, 480)];
                [imageDescriptor setObject:croppedImage forKey:@"croppedImage"];
                [pool drain];
            }
            else {
                croppedImage = [self scaleImage:img withEditingInfo:editInfo];
                [imageDescriptor setObject:croppedImage forKey:@"croppedImage"];
            }
        }
            break;
        default:
            break;
    }

    imageFrame.size = croppedImage.size;
    myImageView.frame = imageFrame;
    myImageView.image = [imageDescriptor objectForKey:@"croppedImage"];
    myImageView.center = imageCenter;


}
于 2009-04-11T17:59:16.910 回答
5

我回答这个问题肯定为时已晚,但我有更好的方法来完成这项工作。

static inline double radians (double degrees) {return degrees * M_PI/180;}

+(UIImage*)editedImageFromMediaWithInfo:(NSDictionary*)info{
    if(![info   objectForKey:UIImagePickerControllerCropRect])return nil;
    if(![info   objectForKey:UIImagePickerControllerOriginalImage])return nil;

    UIImage *originalImage=[info objectForKey:UIImagePickerControllerOriginalImage];
    CGRect rect=[[info objectForKey:UIImagePickerControllerCropRect] CGRectValue];

    CGImageRef imageRef = CGImageCreateWithImageInRect([originalImage CGImage], rect);

    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);
    CGContextRef bitmap = CGBitmapContextCreate(NULL, rect.size.width, rect.size.height, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    if (originalImage.imageOrientation == UIImageOrientationLeft) {
        CGContextRotateCTM (bitmap, radians(90));
        CGContextTranslateCTM (bitmap, 0, -rect.size.height);

    } else if (originalImage.imageOrientation == UIImageOrientationRight) {
        CGContextRotateCTM (bitmap, radians(-90));
        CGContextTranslateCTM (bitmap, -rect.size.width, 0);

    } else if (originalImage.imageOrientation == UIImageOrientationUp) {
        // NOTHING
    } else if (originalImage.imageOrientation == UIImageOrientationDown) {
        CGContextTranslateCTM (bitmap, rect.size.width, rect.size.height);
        CGContextRotateCTM (bitmap, radians(-180.));
    }

    CGContextDrawImage(bitmap, CGRectMake(0, 0, rect.size.width, rect.size.height), imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);

    UIImage *resultImage=[UIImage imageWithCGImage:ref];
    CGImageRelease(imageRef);
    CGContextRelease(bitmap);
    CGImageRelease(ref);

    return resultImage;
}

它只用相对的 CropRect 裁剪原始图像,虽然这种方法不会缩放图像,但对我来说它是简短而甜蜜的。仅供参考:)

于 2011-02-28T16:32:36.940 回答
2

迟到总比没有好:这是orientationTransformForImage函数的来源

CGAffineTransformorientationTransformForImage(UIImage *image, CGSize *newSize) {
    CGImageRef img = [图像 CGImage];
    CGFloat 宽度 = CGImageGetWidth(img);
    CGFloat 高度 = CGImageGetHeight(img);
    CGSize 大小 = CGSizeMake(宽度, 高度);
    CGAffineTransform 变换 = CGAffineTransformIdentity;
    CGFloat origHeight = size.height;
    UIImageOrientation 方向 = image.imageOrientation;
    switch(orient) { /* EXIF 1 到 8 */
        案例 UIImageOrientationUp:
            休息;
        案例 UIImageOrientationUpMirrored:
            变换 = CGAffineTransformMakeTranslation(宽度, 0.0f);
            变换 = CGAffineTransformScale(变换,-1.0f,1.0f);
            休息;
        案例 UIImageOrientationDown:
            变换 = CGAffineTransformMakeTranslation(宽度,高度);
            变换 = CGAffineTransformRotate(变换,M_PI);
            休息;
        案例 UIImageOrientationDownMirrored:
            变换 = CGAffineTransformMakeTranslation(0.0f, 高度);
            变换 = CGAffineTransformScale(变换,1.0f,-1.0f);
            休息;
        案例 UIImageOrientationLeftMirrored:
            尺寸.高度 = 尺寸.宽度;
            size.width = origHeight;
            变换 = CGAffineTransformMakeTranslation(高度,宽度);
            变换 = CGAffineTransformScale(变换,-1.0f,1.0f);
            变换 = CGAffineTransformRotate(变换,3.0f * M_PI / 2.0f);
            休息;
        案例 UIImageOrientationLeft:
            尺寸.高度 = 尺寸.宽度;
            size.width = origHeight;
            变换 = CGAffineTransformMakeTranslation(0.0f, 宽度);
            变换 = CGAffineTransformRotate(变换,3.0f * M_PI / 2.0f);
            休息;
        案例 UIImageOrientationRightMirrored:
            尺寸.高度 = 尺寸.宽度;
            size.width = origHeight;
            变换 = CGAffineTransformMakeScale(-1.0f, 1.0f);
            变换 = CGAffineTransformRotate(变换,M_PI / 2.0f);
            休息;
        案例 UIImageOrientationRight:
            尺寸.高度 = 尺寸.宽度;
            size.width = origHeight;
            变换 = CGAffineTransformMakeTranslation(高度,0.0f);
            变换 = CGAffineTransformRotate(变换,M_PI / 2.0f);
            休息;
        默认:
            ;
    }
    *newSize = 大小;
    返回变换;
}
于 2011-02-18T03:28:00.483 回答
2

在 iPhone OS 3.0+ 中,整个 UIImagePickerController API 发生了变化。这个问题和答案应该考虑2.2。遗留代码。

尽管有你的警告,我还是花了宝贵的开发时间才意识到 iOS 3.0+ 给了我们 UIImagePickerControllerEditedImage ,这使得手动裁剪到用户的捏/缩放和处理方向变得不必要。

这是为了防止有人仍在使用 UIImagePickerControllerOriginalImage 并试图找出如何最好地通过 UIImagePickerControllerCropRect 等应用裁剪。不再需要。

于 2011-03-16T07:57:16.223 回答
1

这似乎是 SDK 的一个障碍,至少在图像选择器上将 allowImageEditing 设置为 TRUE 时是如此。在 Apple 论坛中有一些关于此主题的讨论:

http://discussions.apple.com/message.jspa?messageID=7841993

于 2009-04-07T18:35:36.880 回答
0

在 UIImage 上写了一个提供全分辨率裁剪的类别。最简单的安装方法是使用CocoaPods,将 UIImage-ImagePickerCrop 添加到您的 podfile 中。

#import <UIImage+ImagePickerCrop.h>

...

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo: (NSDictionary *)info {
    [self dismissViewControllerAnimated:YES completion:nil];

    UIImage *croppedImage = [UIImage croppedImageWithImagePickerInfo:info];
    ...
}
于 2014-04-03T18:33:19.987 回答