2012-05-29 10 views
6

Sto unendo due UIImages in un unico contesto. Funziona, ma funziona piuttosto lentamente e ho bisogno di una soluzione più veloce. Poiché la mia soluzione è che ci vogliono circa 400ms per effettuare la chiamata mergeImage: withImage: su un iPad 1G.Unione di due UIImages più veloce di CGContextDrawImage

Ecco quello che faccio:

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

Ed ecco i metodi statici della classe 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); 
} 

Qualche suggerimento per aumentare le prestazioni?

+0

È possibile misurare la durata di ciascun metodo? – EmilioPelaez

+0

Le chiamate drawImage impiegano circa 400 ms, il resto dei metodi è inferiore a 10ms ciascuno. –

+0

Sono queste immagini che puoi combinare in anticipo e spedire con la tua app? Il risultato della prestazione è molto probabilmente dovuto a una combinazione del tuo spazio colore e al premoltiplicazione di alfa. Gioca un po 'con quelli. –

risposta

0

Non sono riuscito a trovare un modo più veloce di unire le immagini. Ho ridotto le dimensioni delle immagini per rendere l'operazione più veloce.

0

Consiglio vivamente di utilizzare gli strumenti per definire quale messaggio impiega più tempo in modo da poterlo abbattere. Inoltre, ho scritto un paio di metodi che penso dovrebbero fare la stessa cosa con molto meno codice, ma devi avere tutto scritto come fai per mantenere le cose personalizzabili. Eccoli comunque:

-(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 se si voleva l'immagine combinata subito:

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

non ho idea se sarebbe più veloce o no, ma io davvero non saprebbero accelera ciò che hai molto facilmente a meno che non ti sia rotto il profilo degli strumenti.

In ogni caso, spero che questo aiuti.

+0

Ho appena realizzato che potrebbero esserci tutti i tipi di problemi di memoria stupidi con i miei metodi, ma sono semplici soluzioni. Si potrebbe facilmente mantenere il contesto se è necessario o meno. Ma tu hai l'idea. – Ben

+0

Le tue soluzioni non funzionano senza una chiamata CGContextDrawImage. Dovrai creare una CGContextDrawImage dopo le chiamate drawInRect. Ma sono stato in grado di ottenere i tempi di esecuzione dei metodi: drawInRect richiede 400ms da solo che termina con 200ms su img_decode_stage e 200ms su img_interpolate_read. –

+0

Ahh si si potrebbe facilmente usare quello invece di drawInRect. Basta mostrare che meno non è sempre meglio con il codice. Ovviamente in qualsiasi soluzione i messaggi che richiederanno il tempo più lungo sono i messaggi di disegno reali. Per i tuoi dovrai essere pignoli se vuoi davvero spremere le prestazioni. Per esempio: invece di usare CGRectMake due volte, usalo una volta in una var e riutilizzalo, dato che l'allocazione degli uomini è leggermente onerosa, sebbene con una piccola struttura come quella probabilmente non avrà importanza. Quando si assegna il contesto, utilizzare la dimensione var invece di Allocare un nuovo CGSize. – Ben