UIImage在缩放时变得模糊。为什么?(iOS 5.0) [英] UIImage become Fuzzy when it was scaled.Why?(iOS 5.0)

查看:196
本文介绍了UIImage在缩放时变得模糊。为什么?(iOS 5.0)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

UIImage在缩放时总是变得模糊不清。如果让它保持清晰,我该怎么办?

   - (UIImage * )rescaleImageToSize:(CGSize)size {
CGRect rect = CGRectMake(0.0,0.0,size.width,size.height);
UIGraphicsBeginImageContext(rect.size);
[self drawInRect:rect]; //将图像缩放到rect
UIImage * resImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
返回resImage;
}


解决方案

舍入



首先,确保在缩放之前缩小尺寸。 drawInRect:在这种情况下可以模糊其他可用的图像。要舍入到最接近的整数值:

  size.width = truncf(size.width); 
size.height = truncf(size.height);

对于某些任务,您可能需要向下舍入(floorf)或向上舍入(ceilf)。



CILanczosScaleTransform不可用



然后,忽略我之前推荐的CILanczosScaleTransform。虽然Core Image的部分版本在iOS 5.0中可用,但Lanczos缩放不是。如果它确实可用,请使用它。对于在Mac OS上工作的人,可以使用它。



vImage Scaling



但是,有,比较左下方的叶子:



在这个上它具有有趣的舍入效果:



性能



毫不奇怪,kCGImageInterpolationHigh是最慢的标准图像插值选项。这里实现的vImageScaledImage更慢。为了将分形图像缩小到原始尺寸的一半,它花费了UIImageInterpolationHigh的110%的时间。缩小到四分之一,花费了340%的时间。



如果你在模拟器中运行它,你可能会想到其他情况;在那里,它可以比kCGImageInterpolationHigh快得多。据推测,vImage多核优化使其在桌面上具有相对优势。



代码



  //方法:vImageScaledImage:(UIImage *)sourceImage withSize:(CGSize)destSize 
//返回比使用kCGInterpolationHigh绘制到上下文更好的缩放比例。
//这使用了Accelerate.framework中的vImage例程。
//有关vImage的更多信息,请参阅https://developer.apple.com/library/mac/#documentation/performance/Conceptual/vImage/Introduction/Introduction.html#//apple_ref/doc/uid/ TP30001001-CH201-TPXREF101
//手动分配大量内存,并(希望)在这里释放。在使用此方法之前和之后测试您的应用程序是否存在泄漏。
- (UIImage *)vImageScaledImage:(UIImage *)sourceImage withSize:(CGSize)destSize;
{
UIImage * destImage = nil;

if(sourceImage)
{
//首先,将UIImage转换为字节数组,格式为vImage。
//谢谢:http://stackoverflow.com/a/1262893/1318452
CGImageRef sourceRef = [sourceImage CGImage];
NSUInteger sourceWidth = CGImageGetWidth(sourceRef);
NSUInteger sourceHeight = CGImageGetHeight(sourceRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char * sourceData =(unsigned char *)calloc(sourceHeight * sourceWidth * 4,sizeof(unsigned char));
NSUInteger bytesPerPixel = 4;
NSUInteger sourceBytesPerRow = bytesPerPixel * sourceWidth;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(sourceData,sourceWidth,sourceHeight,
bitsPerComponent,sourceBytesPerRow,colorSpace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
CGContextDrawImage(context,CGRectMake(0,0,sourceWidth,sourceHeight),sourceRef);
CGContextRelease(context);

//我们现在拥有源数据。构造一个像素数组
NSUInteger destWidth =(NSUInteger)destSize.width;
NSUInteger destHeight =(NSUInteger)destSize.height;
NSUInteger destBytesPerRow = bytesPerPixel * destWidth;
unsigned char * destData =(unsigned char *)calloc(destHeight * destWidth * 4,sizeof(unsigned char));

//现在为两个像素阵列创建vImage结构。
//谢谢:https://github.com/dhoerl/PhotoScrollerNetwork
vImage_Buffer src = {
.data = sourceData,
.height = sourceHeight,
。 width = sourceWidth,
.rowBytes = sourceBytesPerRow
};

vImage_Buffer dest = {
.data = destData,
.height = destHeight,
.width = destWidth,
.rowBytes = destBytesPerRow
};

//执行缩放。
vImage_Error err = vImageScale_ARGB8888(
& src,
& dest,
NULL,
kvImageHighQualityResampling
);

//不再需要源字节。
free(sourceData);

//将目标字节转换为UIImage。
CGContextRef destContext = CGBitmapContextCreate(destData,destWidth,destHeight,
bitsPerComponent,destBytesPerRow,colorSpace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
CGImageRef destRef = CGBitmapContextCreateImage(destContext);

//存储结果。
destImage = [UIImage imageWithCGImage:destRef];

//释放剩余的内存。
CGImageRelease(destRef);

CGColorSpaceRelease(colorSpace);
CGContextRelease(destContext);

//不再需要目标字节。
free(destData);

if(err!= kvImageNoError)
{
NSString * errorReason = [NSString stringWithFormat:@vImageScale返回错误代码%d,错误];
NSDictionary * errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
sourceImage,@sourceImage,
[NSValue valueWithCGSize:destSize],@destSize,
nil];

NSException * exception = [NSException exceptionWithName:@HighQualityImageScalingFailureExceptionreason:errorReason userInfo:errorInfo];

@throw例外;
}
}
返回destImage;
}


UIImage always become indistinct when it was scaled.What can i do if make it keep clearness?

- (UIImage *)rescaleImageToSize:(CGSize)size {
    CGRect rect = CGRectMake(0.0, 0.0, size.width, size.height);
    UIGraphicsBeginImageContext(rect.size);
    [self drawInRect:rect];  // scales image to rect
    UIImage *resImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return resImage;
}

解决方案

Rounding

First, make sure that you're rounding your size before scaling. drawInRect: can blur an otherwise usable image in this case. To round to the nearest integer value:

size.width = truncf(size.width);
size.height = truncf(size.height);

For certain tasks, you may want to round down (floorf) or round up (ceilf) instead.

CILanczosScaleTransform not available

Then, disregard my previous recommendation of CILanczosScaleTransform. While parts of Core Image are available in iOS 5.0, Lanczos scaling is not. If it ever does become available, make use of it. For people working on Mac OS, it is available, use it.

vImage Scaling

However, there is a high-quality scaling algorithm available in vImage. The following pictures show how a method using it (vImageScaledImage) compares with the different context interpolation options. Also note how those options behave differently at different zoom levels.

On this diagram, it preserved the most line detail:

On this photograph, compare the leaves at lower left:

On this photograph, compare the textures in lower right:

Do not use it on pixel art; it creates odd scaling artifacts:

Although it on some images it has interesting rounding effects:

Performance

Not surprisingly, kCGImageInterpolationHigh is the slowest standard image interpolation option. vImageScaledImage, as implemented here, is slower still. For shrinking the fractal image to half its original size, it took 110% of the time of UIImageInterpolationHigh. For shrinking to a quarter, it took 340% of the time.

You may think otherwise if you run it in the simulator; there, it can be much faster than kCGImageInterpolationHigh. Presumably the vImage multi-core optimisations give it a relative edge on the desktop.

Code

// Method: vImageScaledImage:(UIImage*) sourceImage withSize:(CGSize) destSize
// Returns even better scaling than drawing to a context with kCGInterpolationHigh.
// This employs the vImage routines in Accelerate.framework.
// For more information about vImage, see https://developer.apple.com/library/mac/#documentation/performance/Conceptual/vImage/Introduction/Introduction.html#//apple_ref/doc/uid/TP30001001-CH201-TPXREF101
// Large quantities of memory are manually allocated and (hopefully) freed here.  Test your application for leaks before and after using this method.
- (UIImage*) vImageScaledImage:(UIImage*) sourceImage withSize:(CGSize) destSize;
{
    UIImage *destImage = nil;

    if (sourceImage)
    {
        // First, convert the UIImage to an array of bytes, in the format expected by vImage.
        // Thanks: http://stackoverflow.com/a/1262893/1318452
        CGImageRef sourceRef = [sourceImage CGImage];
        NSUInteger sourceWidth = CGImageGetWidth(sourceRef);
        NSUInteger sourceHeight = CGImageGetHeight(sourceRef);
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        unsigned char *sourceData = (unsigned char*) calloc(sourceHeight * sourceWidth * 4, sizeof(unsigned char));
        NSUInteger bytesPerPixel = 4;
        NSUInteger sourceBytesPerRow = bytesPerPixel * sourceWidth;
        NSUInteger bitsPerComponent = 8;
        CGContextRef context = CGBitmapContextCreate(sourceData, sourceWidth, sourceHeight,
                                                     bitsPerComponent, sourceBytesPerRow, colorSpace,
                                                     kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
        CGContextDrawImage(context, CGRectMake(0, 0, sourceWidth, sourceHeight), sourceRef);
        CGContextRelease(context);

        // We now have the source data.  Construct a pixel array
        NSUInteger destWidth = (NSUInteger) destSize.width;
        NSUInteger destHeight = (NSUInteger) destSize.height;
        NSUInteger destBytesPerRow = bytesPerPixel * destWidth;
        unsigned char *destData = (unsigned char*) calloc(destHeight * destWidth * 4, sizeof(unsigned char));

        // Now create vImage structures for the two pixel arrays.
        // Thanks: https://github.com/dhoerl/PhotoScrollerNetwork
        vImage_Buffer src = {
            .data = sourceData,
            .height = sourceHeight,
            .width = sourceWidth,
            .rowBytes = sourceBytesPerRow
        };

        vImage_Buffer dest = {
            .data = destData,
            .height = destHeight,
            .width = destWidth,
            .rowBytes = destBytesPerRow
        };

        // Carry out the scaling.
        vImage_Error err = vImageScale_ARGB8888 (
                                                 &src,
                                                 &dest,
                                                 NULL,
                                                 kvImageHighQualityResampling 
                                                 );

        // The source bytes are no longer needed.
        free(sourceData);

        // Convert the destination bytes to a UIImage.
        CGContextRef destContext = CGBitmapContextCreate(destData, destWidth, destHeight,
                                                         bitsPerComponent, destBytesPerRow, colorSpace,
                                                         kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
        CGImageRef destRef = CGBitmapContextCreateImage(destContext);

        // Store the result.
        destImage = [UIImage imageWithCGImage:destRef];

        // Free up the remaining memory.
        CGImageRelease(destRef);

        CGColorSpaceRelease(colorSpace);
        CGContextRelease(destContext);

        // The destination bytes are no longer needed.
        free(destData);

        if (err != kvImageNoError)
        {
            NSString *errorReason = [NSString stringWithFormat:@"vImageScale returned error code %d", err];
            NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:
                                       sourceImage, @"sourceImage", 
                                       [NSValue valueWithCGSize:destSize], @"destSize",
                                       nil];

            NSException *exception = [NSException exceptionWithName:@"HighQualityImageScalingFailureException" reason:errorReason userInfo:errorInfo];

            @throw exception;
        }
    }
    return destImage;
}

这篇关于UIImage在缩放时变得模糊。为什么?(iOS 5.0)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆