UIImage缩放后变得模糊。为什么?(iOS 5.0)

2023-11-25

UIImage缩放后总是变得模糊,如何才能保持清晰?

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

首先,确保在缩放之前对尺寸进行四舍五入。drawInRect:在这种情况下可以模糊原本可用的图像。要舍入到最接近的整数值:

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

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

CILanczosScaleTransform 不可用

然后,忽略我之前推荐的 CILanczosScaleTransform。虽然 Core Image 的部分功能在 iOS 5.0 中可用,但 Lanczos 缩放功能却不可用。如果它确实可用,请利用它。对于使用 Mac OS 的人来说,它是可用的,可以使用它。

虚拟图像缩放

然而,有一个高质量的缩放算法可用vImage。下图显示了使用它的方法 (vImageScaledImage) 与不同上下文插值选项的比较。另请注意这些选项在不同缩放级别的行为有何不同。

On this diagram, it preserved the most line detail: Scaling comparison on diagram

On this photograph, compare the leaves at lower left: Scaling comparison on tree photograph

On this photograph, compare the textures in lower right: Scaling comparison on rock photograph

Do not use it on pixel art; it creates odd scaling artifacts: Scaling comparison on pixel art, showing scaling artifacts

Although it on some images it has interesting rounding effects: Scaling comparison on Space Invader

表现

毫不奇怪,kCGImageInterpolationHigh 是最慢的标准图像插值选项。此处实现的 vImageScaledImage 仍然较慢。将分形图像缩小到原始大小的一半,花费了 UIImageInterpolationHigh 的 110% 的时间。缩小到四分之一,需要 340% 的时间。

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

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;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UIImage缩放后变得模糊。为什么?(iOS 5.0) 的相关文章

随机推荐