Redimensionner une UIImage en étant Threadsafe

Il y a peu, je vous présentais ici même comment redimensionner une UIImage. Je vous replace dans le contexte: Dans certains cas, il peut être utile de redimensionner une UIImage. En effet, même si UIImageView gère très bien le redimensionnement, on peut vouloir exporter une image dans une certaine taille. De même, il n’est pas forcement utile de stocker (en mémoire ou bien en dur) une image de grande taille si c’est pour l’afficher réduite par la suite.

Le code qui était présenté est fonctionnel … Oui, mais un collègue m’a fait remarquer que ce n’était pas le cas en multi-threads. Pourquoi ? Tout simplement parce que quand on fait UIGraphicsBeginImageContext(), on travaille dans un contexte unique. Ainsi, quand on voudra redimensionner deux images en même temps, elles partageront le même contexte. Clairement, ça ne peut pas marcher. D’ailleurs: ça ne marche pas !

Partant de là il y a deux options: soit on gère un système de sémaphore, soit on trouve un moyen de créer un contexte spécifique. L’idée du sémaphore est à exclure d’emblée. Ceci pour la simple et bonne raison qu’elle nous enlève l’avantage principal d’utiliser des threads: pouvoir exécuter des opérations en simultané.

Il faut donc créer un contexte bitmap spécifique à notre thread. Ensuite, on dessine notre image à redimensionner dans ce contexte que l’on vient de créer. Pour finir, on n’oubliera pas de libérer les différents refs créées. Dans le code, voilà ce que cela donne:

//  UIImageAdditions.m
//  Untitled
//
//  Created by Julien on 28/05/09.
//  Copyright 2009 Julien Quéré - Webd.fr. All rights reserved.
//

#import "UIImageAdditions.h"

@implementation UIImage(UIImageAdditions)

- (UIImage *)resizeWithSize:(CGSize)size {
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 5, size.width*2, colorSpace, kCGImageAlphaNoneSkipFirst); //5bpc
	// size.width*2 = 2bbp
	CGRect rect = CGRectMake(0, 0, size.width, size.height);

	CGContextDrawImage(context, rect, self.CGImage);
	CGImageRef refNewImage = CGBitmapContextCreateImage(context);
	UIImage *newImage = [UIImage imageWithCGImage:refNewImage];

	CGImageRelease(refNewImage);
	CGColorSpaceRelease(colorSpace);
	CGContextRelease(context);

	return newImage;
}
@end

//  UIImageAdditions.h
//  Untitled
//
//  Created by Julien on 28/05/09.
//  Copyright 2009 Julien Quéré - Webd.fr. All rights reserved.
//

#import 

@interface UIImage(UIImageAdditions)
- (UIImage *)resizeWithSize:(CGSize)size;
@end

Pour l’utilisation de CGBitmapContextCreate, référez vous à la littérature Apple sur le sujet. La seule chose qui aurait besoin d’être explicité c’est le premier paramètre: le NULL. Le premier paramètre correspond à un pointeur où les données du contexte doivent être stockées. Quand on passe NULL, on indique en fait que l’on se fiche d’où les données seront stockées (ce qui est notre cas).

Une fois l’addition de UIImage mise en place, l’utilisation du code est assez simple:

	UIImage *myPic = [UIImage imageNamed:@"poney.jpg"];
	[myPic resizeWithSize:CGSizeMake(50, 50)];
	[im setImage:myPic]; //im is an UIImageView

Merci à Loïc Dardant pour le code et le coup de main.

Laisser un commentaire

Un nom (requis)

Un mail (requis)

Peut être une URL ?

Réaction:

 

Coins sympas