Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

High Quality Scaling of UIImage

I need to scale the resolution of an image coming from a view layer in an iPhone application. The obvious way is to specify a scale factor in UIGraphicsBeginImageContextWithOptions, but any time the scale factor is not 1.0 then quality of the image goes to pot -- far more than would be expected from the loss of pixels.

I've tried several other scaling techniques, but they all seem to revolve around CGContext stuff and all appear to do the same thing.

Simply changing image "size" (without changing the dot resolution) isn't sufficient, mostly because that info seems to be discarded very quickly by other hands in the pipeline (the image will be converted to a JPG and emailed).

Is there any other way to scale an image on iPhone?

like image 783
Hot Licks Avatar asked May 18 '11 23:05

Hot Licks


People also ask

What is the difference between UIImage and UIImageView?

UIImage contains the data for an image. UIImageView is a custom view meant to display the UIImage .

How do you resize Ciimage?

Compute the scaling factor for the vertical dimension to get the desired height, then compute the result of this scaling applied to the horizontal dimension. This may not match the target width, so compute the aspect ratio to apply to the scaled width to correct it to the desired target width.

How do I change the size of my UIImageView?

The simplest way is to set the frame of your UIImageView and set the contentMode to one of the resizing options. I would NOT retain the result here. newImage will be autoreleased already, and it should up to the method that called this to retain it or not.


2 Answers

Swift extension:

extension UIImage{

        // returns a scaled version of the image
        func imageScaledToSize(size : CGSize, isOpaque : Bool) -> UIImage{

            // begin a context of the desired size
            UIGraphicsBeginImageContextWithOptions(size, isOpaque, 0.0)

            // draw image in the rect with zero origin and size of the context
            let imageRect = CGRect(origin: CGPointZero, size: size)
            self.drawInRect(imageRect)

            // get the scaled image, close the context and return the image
            let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()

            return scaledImage
       }
}

Example:

aUIImageView.image = aUIImage.imageScaledToSize(aUIImageView.bounds.size, isOpaque : false)

Set isOpaque to true if the image has no alpha: drawing will have better performance.

like image 53
J.Williams Avatar answered Sep 18 '22 02:09

J.Williams


About UIImage resize problem, this post give many ways to handle UIImage object. The UIImage has some orientation problems need to be fixed. This and Another post will address it.


-(UIImage*)resizedImageToSize:(CGSize)dstSize
{
    CGImageRef imgRef = self.CGImage;
    // the below values are regardless of orientation : for UIImages from Camera, width>height (landscape)
    CGSize  srcSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); // not equivalent to self.size (which is dependant on the imageOrientation)!

    /* Don't resize if we already meet the required destination size. */
    if (CGSizeEqualToSize(srcSize, dstSize)) {
        return self;
    }

    CGFloat scaleRatio = dstSize.width / srcSize.width;

    // Handle orientation problem of UIImage
    UIImageOrientation orient = self.imageOrientation;
    CGAffineTransform transform = CGAffineTransformIdentity;
    switch(orient) {

        case UIImageOrientationUp: //EXIF = 1
            transform = CGAffineTransformIdentity;
            break;

        case UIImageOrientationUpMirrored: //EXIF = 2
            transform = CGAffineTransformMakeTranslation(srcSize.width, 0.0);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            break;

        case UIImageOrientationDown: //EXIF = 3
            transform = CGAffineTransformMakeTranslation(srcSize.width, srcSize.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationDownMirrored: //EXIF = 4
            transform = CGAffineTransformMakeTranslation(0.0, srcSize.height);
            transform = CGAffineTransformScale(transform, 1.0, -1.0);
            break;

        case UIImageOrientationLeftMirrored: //EXIF = 5
            dstSize = CGSizeMake(dstSize.height, dstSize.width);
            transform = CGAffineTransformMakeTranslation(srcSize.height, srcSize.width);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2);
            break;  

        case UIImageOrientationLeft: //EXIF = 6  
            dstSize = CGSizeMake(dstSize.height, dstSize.width);
            transform = CGAffineTransformMakeTranslation(0.0, srcSize.width);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2);
            break;  

        case UIImageOrientationRightMirrored: //EXIF = 7  
            dstSize = CGSizeMake(dstSize.height, dstSize.width);
            transform = CGAffineTransformMakeScale(-1.0, 1.0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;  

        case UIImageOrientationRight: //EXIF = 8  
            dstSize = CGSizeMake(dstSize.height, dstSize.width);
            transform = CGAffineTransformMakeTranslation(srcSize.height, 0.0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;  

        default:  
            [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];  

    }  

    /////////////////////////////////////////////////////////////////////////////
    // The actual resize: draw the image on a new context, applying a transform matrix
    UIGraphicsBeginImageContextWithOptions(dstSize, NO, self.scale);

    CGContextRef context = UIGraphicsGetCurrentContext();

       if (!context) {
           return nil;
       }

    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
        CGContextScaleCTM(context, -scaleRatio, scaleRatio);
        CGContextTranslateCTM(context, -srcSize.height, 0);
    } else {  
        CGContextScaleCTM(context, scaleRatio, -scaleRatio);
        CGContextTranslateCTM(context, 0, -srcSize.height);
    }

    CGContextConcatCTM(context, transform);

    // we use srcSize (and not dstSize) as the size to specify is in user space (and we use the CTM to apply a scaleRatio)
    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, srcSize.width, srcSize.height), imgRef);
    UIImage* resizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return resizedImage;
}
like image 21
AechoLiu Avatar answered Sep 19 '22 02:09

AechoLiu