Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIImagePickerController editing allowed locks UIImage to max size of 320x320

Update:

With iPhone OS 3.0+, the whole UIImagePickerController API has changed. This question and answer should be considered 2.2. legacy code.


When using the UIImagePickerController and you allow editing of the image. The iPhone allows the user to resize and pan the image. However, the max size of an edited image is capped at 320x320.

As an example, I took an iPhone screenshot and placed it in the photo library, which is a 480x320 png. When I use a UIImagePickerController to select that image, even if I do NOT scale or pan the image, it is cropped to 320x320 before it is returned from the UIImagePickerController. However, if I turn editing off, the image is returned the proper 480x320 size.

My theory: Very subtly, the iPhone displays 2 nonstandard translucent tool bars that overlay over the image. These toolbars leave an innocuous 320x320 "window" over the photo. It appears to me that this window effectively clips the underlying photo.

Note: The callback also returns an editing dictionary with the original image and the clipping rect, but of course the rect is also max 320x320.

Any ideas on how to allow images larger than 320x320 to be scaled and panned?

Some code:

- (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];
    }
like image 208
Corey Floyd Avatar asked Apr 07 '09 04:04

Corey Floyd


2 Answers

As craig said, this is an issue in the dev forums and apples regular discussion board. I did, however, find a way around it. I'm using a bit of code from:

Apple Dev Forums

This includes most of what you need, and takes care of all the camera orientation issues. I've added the following which will take in the editing info and use it to get the original cropping rect with this addition:

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

I updated the call back method from the dev forums post to the following:

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


}
like image 173
Corey Floyd Avatar answered Nov 07 '22 11:11

Corey Floyd


I must be too late to answer this question, but I have got a better way to get this job done.

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

It only crops the original image with the relative CropRect, although this method dosen't scale the image, but it is short and sweet for me. Just for reference :)

like image 5
b123400 Avatar answered Nov 07 '22 11:11

b123400