2012-05-29 11 views
6

Estoy fusionando dos UIImages en un contexto. Funciona, pero funciona bastante lento y necesito una solución más rápida. Como mi solución es que tarda unos 400 ms en realizar la llamada mergeImage: withImage: en un iPad 1G.Fusionando dos UIImages más rápido que CGContextDrawImage

Aquí es lo que hago:

-(CGContextRef)mergeImage:(UIImage*)img1 withImage:(UIImage*)img2 
{ 
    CGSize size = [ImageToolbox getScreenSize]; 
    CGContextRef context = [ImageToolbox createARGBBitmapContextFromImageSize:CGSizeMake(size.width, size.height)]; 

    CGContextSetRenderingIntent(context, kCGRenderingIntentSaturation); 

    CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), img1.CGImage); 
    CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), img2.CGImage); 


    return context; 
} 

Y aquí es los métodos estáticos de la clase ImageToolbox:

static CGRect screenRect; 

+ (CGContextRef)createARGBBitmapContextFromImageSize:(CGSize)imageSize 
{ 
    CGContextRef context = NULL; 
    CGColorSpaceRef colorSpace; 
    void *   bitmapData; 
    int    bitmapByteCount; 
    int    bitmapBytesPerRow; 

    size_t pixelsWide = imageSize.width; 
    size_t pixelsHigh = imageSize.height; 

    bitmapBytesPerRow = (pixelsWide * 4); 
    bitmapByteCount  = (bitmapBytesPerRow * pixelsHigh); 

    colorSpace = CGColorSpaceCreateDeviceRGB(); 
    if (colorSpace == NULL) 
    { 
     fprintf(stderr, "Error allocating color space\n"); 
     return NULL; 
    } 

    bitmapData = malloc(bitmapByteCount); 
    if (bitmapData == NULL) 
    { 
     fprintf (stderr, "Memory not allocated!"); 
     CGColorSpaceRelease(colorSpace); 
     return NULL; 
    } 

    context = CGBitmapContextCreate (bitmapData, 
            pixelsWide, 
            pixelsHigh, 
            8,  // bits per component 
            bitmapBytesPerRow, 
            colorSpace, 
            kCGImageAlphaPremultipliedFirst); 
    if (context == NULL) 
    { 
     free (bitmapData); 
     fprintf (stderr, "Context not created!"); 
    } 

    CGColorSpaceRelease(colorSpace); 

    return context; 
} 

+(CGSize)getScreenSize 
{ 
    if (screenRect.size.width == 0 && screenRect.size.height == 0) 
    { 
     screenRect = [[UIScreen mainScreen] bounds];  

    } 
    return CGSizeMake(screenRect.size.height, screenRect.size.width-20); 
} 

Cualquier sugerencia para aumentar el rendimiento?

+0

¿Puedes medir cuánto tiempo está tomando cada método? – EmilioPelaez

+0

Las llamadas a drawImage toman alrededor de 400 ms, el resto de los métodos tienen menos de 10 ms cada uno. –

+0

¿Estas imágenes las puedes combinar de antemano y enviar con tu aplicación? El golpe de rendimiento es más probable debido a un combo de tu espacio de color y Premultiplying de alfa. Juega con ellos un poco. –

Respuesta

0

No logré encontrar una manera más rápida de unir las imágenes. Reduje los tamaños de las imágenes para acelerar la operación.

0

Definitivamente recomendaría usar Instruments para perfilar qué mensaje está tomando más tiempo para que realmente pueda descomponerlo. Además, he escrito un par de métodos que creo que deberían hacer lo mismo con mucho menos código, pero debes tener todo escrito de la forma en que lo haces para mantener las cosas personalizables. Aquí están todos modos:

-(CGContextRef)mergeImage:(UIImage *)img1 withImage:(UIImage *)img2 
{ 
    CGSize size = [ImageToolbox getScreenSize]; 
    CGRect rect = CGRectMake(0, 0, size.width, size.height); 

    UIGraphicsBeginImageContextWithOptions(size, YES, 1.0); 

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    CGContextSetRenderingIntent(context, kCGRenderingIntentSaturation); 

    [img1 drawInRect:rect]; 
    [img2 drawInRect:rect]; 

    UIGraphicsEndImageContext(); 

    return context; 
} 

O si quería la imagen combinada de inmediato:

- (UIImage *)mergeImage:(UIImage *)img1 withImage:(UIImage *)img2 
{ 
    CGSize size = [ImageToolbox getScreenSize]; 
    CGRect rect = CGRectMake(0, 0, size.width, size.height); 

    UIGraphicsBeginImageContextWithOptions(size, YES, 1.0); 

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    CGContextSetRenderingIntent(context, kCGRenderingIntentSaturation); 

    [img1 drawInRect:rect]; 
    [img2 drawInRect:rect]; 

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 

    UIGraphicsEndImageContext(); 

    return image; 
} 

no tengo ni idea de si estarían más rápido o no, pero realmente no sabrían cómo agiliza lo que tienes muy fácilmente a menos que tengas el perfil del instrumento averiado.

En cualquier caso, espero que esto ayude.

+0

Me acabo de dar cuenta de que puede haber todo tipo de problemas de memoria estúpidos con mis métodos, pero son soluciones simples. Puede conservar el contexto fácilmente si necesita o no. Pero se entiende la idea. – Ben

+0

Sus soluciones no funcionan sin una llamada CGContextDrawImage. Tendrás que hacer un CGContextDrawImage después de las llamadas drawInRect. Pero pude obtener los tiempos de ejecución de los métodos: drawInRect toma 400ms por sí mismo, que termina en 200ms en img_decode_stage y 200ms en img_interpolate_read. –

+0

Ahh sí, podría usarlo fácilmente en lugar de drawInRect. Solo sirve para mostrar que menos no siempre es mejor con el código. Obviamente en cualquier solución los mensajes que tomarán más tiempo son los mensajes de dibujo reales. Para los tuyos, tendrás que ser quisquilloso con los detalles si realmente quieres exprimir el rendimiento. Por ejemplo: en lugar de usar CGRectMake dos veces, úselo una vez en var y reutilícelo, ya que la asignación de los hombres es un poco exigente, aunque con una pequeña estructura así probablemente no importe. Cuando asigna el contexto, use el tamaño var en lugar de Asignar un nuevo CGSize. – Ben