Pregunta sobre ios, scale, uiimage – UIImage se vuelve borroso cuando se escala. ¿Por qué? (IOS 5.0)

12

UIImage siempre se vuelve indistinto cuando se escala. ¿Qué puedo hacer si lo hago para mantener la claridad?

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

Tu respuesta

4   la respuesta
2

Intenta poner:

<code>CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
</code>

Antes de dibujar para obtener interpolación de alta calidad.

@shuiyouren Eso es lo mejor que puedes conseguir. AFAIK, Quartz2D usa bilineal, porque es más rápido en tiempo real. La calidad es más baja que bicúbica. Si desea una calidad aún mayor, es posible que tenga que usar sus propios algoritmos de interpolación. He Shiming
Intentado, pero no se efectúa. shuiyouren
0

y queriendo mantener las esquinas nítidas, desea desactivar la interpolación de la imagen. Si tu imagen es pixel art, esto es lo que quieres. En la mayoría de los otros casos, no lo es.

<code>UIGraphicsBeginImageContext(rect.size);

// Turn off interpolation to keep the scaled image from being blurred.
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);

[self drawInRect:rect];  // scales image to rect
UIImage *resImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
</code>

Si está reduciendo la escala, simplemente dibujar con kCGInterpolationHigh tampoco es la mejor opción.Esta bien peroCILanczosScaleTransform es un poco más agudo.

Editar: a partir de iOS 5.1, CILanczosScaleTransform no está disponible. Vea mi otra respuesta para una rutina de escalado de alta calidad que puede usar.

@shuiyouren: Perdón por preguntar lo imposible. De todos modos, he descrito las circunstancias en las que necesita CILanczosScaleTransform. ¿Puede confirmar que estos se aplican a su problema? Dondragmer
¿Me diste un ejemplo para esta pregunta sobre CILanczosScaleTransform? shuiyouren
wow, Dios mío, gana más de 10 reputación para publicar imágenes. shuiyouren
Creo que CILanczosScaleTransform puede resolverlo. Intento buscar instrucciones sobre cómo usar CILanczosScaleTransform. shuiyouren
@shuiyouren: No he dado un ejemplo de CILanczosScaleTransform porque no sé si lo necesita. Adjunte dos imágenes a su publicación original: la imagen antes de escalar y la imagen después de escalar. Entonces alguien puede decirte qué algoritmo necesitas. Dondragmer
5

esultado no fue lo suficientemente buena (estoy reduciendo el tamaño de la imagen con una proporción de 1/10).

Esta solución funcionó para mí sin embargo:DrawInrect de UIImage: suaviza la imagen

Básicamente, solo dice que en la pantalla de retina necesita crear el contexto gráfico con el parámetro de retina:

<code>UIGraphicsBeginImageContextWithOptions(size, NO, 2.0f);
</code>
Nada de lo anterior o de abajo funcionó para mí, pero este, me quedé atascado por 2 días, ¡voté arriba y voté por el original, saludos! AamirR
46
Redondeo

asegúrese de redondear su tamaño antes de escalar.drawInRect: Puede desenfocar una imagen de otro modo utilizable en este caso. Para redondear al valor entero más cercano:

<code>size.width = truncf(size.width);
size.height = truncf(size.height);
</code>

Para ciertas tareas, es posible que desee redondear hacia abajo (floorf) o redondear hacia arriba (ceilf) en su lugar.

CILanczosScaleTransform no disponible

Luego, ignore mi recomendación anterior de CILanczosScaleTransform. Mientras que partes de Core Image están disponibles en iOS 5.0, la escala de Lanczos no lo está. Si alguna vez llega a estar disponible, hazlo. Para las personas que trabajan en Mac OS, está disponible, úselo.

escala de imagen

Sin embargo, hay un algoritmo de escalado de alta calidad disponible envimagen. Las siguientes imágenes muestran cómo un método que lo usa (vImageScaledImage) se compara con las diferentes opciones de interpolación de contexto. También tenga en cuenta cómo esas opciones se comportan de manera diferente en diferentes niveles de zoom.

En estediagrama, conservó el mayor detalle de la línea:

En estefotografía, compara las hojas en la parte inferior izquierda:

En estefotografía, compara las texturas en la parte inferior derecha:

No lo uses enarte de pixel; crea artefactos de escala extraña:

Aunque enalgunas imagenes Tiene interesantes efectos de redondeo:

Actuación

No es sorprendente que kCGImageInterpolationHigh sea la opción de interpolación de imagen estándar más lenta. vImageScaledImage, como se implementa aquí, es aún más lento. Para reducir la imagen fractal a la mitad de su tamaño original, tomó 110% del tiempo de UIImageInterpolationHigh. Para reducir a un cuarto, tomó el 340% del tiempo.

Puedes pensar de otra manera si lo ejecutas en el simulador; allí, puede ser mucho más rápido que kCGImageInterpolationHigh. Presumiblemente, las optimizaciones de múltiples núcleos de vImage le dan una ventaja relativa en el escritorio.

Código
<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;
}
</code>
El autor de {PhotoScrollerNetwork dice gracias por la atribución en el código: // Gracias:github.com/dhoerl/PhotoScrollerNetwork :-) David H

Preguntas relacionadas