UIGraphicsBeginImageContext vs CGBitmapContextCreate
Je suis en train de changer de couleur d'une image dans un thread d'arrière-plan.
Apple doc a dit UIGraphicsBeginImageContext ne peut être appelé à partir de thread principal, et je suis en train d'utiliser CGBitmapContextCreate:
contexte = CGBitmapContextCreate
(bitmapData,
pixelsWide,
pixelsHigh,
8, //bits par composantebitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedFirst);
J'ai deux versions de "changeColor" premier à utiliser UIGraphisBeginImageContext, le second, à l'aide de CGBitmapContextCreate.
Le premier correctement les changements de couleur, mais le second ne l'est pas.
Pourquoi est-ce?
- (UIImage*) changeColor: (UIColor*) aColor
{
if(aColor == nil)
return self;
UIGraphicsBeginImageContext(self.size);
CGRect bounds;
bounds.origin = CGPointMake(0,0);
bounds.size = self.size;
[aColor set];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0, self.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextClipToMask(context, bounds, [self CGImage]);
CGContextFillRect(context, bounds);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
- (UIImage*) changeColor: (UIColor*) aColor
{
if(aColor == nil)
return self;
CGContextRef context = CreateARGBBitmapContext(self.size);
CGRect bounds;
bounds.origin = CGPointMake(0,0);
bounds.size = self.size;
CGColorRef colorRef = aColor.CGColor;
const CGFloat *components = CGColorGetComponents(colorRef);
float red = components[0];
float green = components[1];
float blue = components[2];
CGContextSetRGBFillColor(context, red, green, blue, 1);
CGContextClipToMask(context, bounds, [self CGImage]);
CGContextFillRect(context, bounds);
CGImageRef imageRef = CGBitmapContextCreateImage(context);
UIImage* img = [UIImage imageWithCGImage: imageRef];
unsigned char* data = (unsigned char*)CGBitmapContextGetData (context);
CGContextRelease(context);
free(data);
return img;
}
CGContextRef CreateARGBBitmapContext(CGSize size)
{
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
//Get image width, height. We'll use the entire image.
size_t pixelsWide = size.width;
size_t pixelsHigh = size.height;
//Declare the number of bytes per row. Each pixel in the bitmap in this
//example is represented by 4 bytes; 8 bits each of red, green, blue, and
//alpha.
bitmapBytesPerRow = (pixelsWide * 4);
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
//Use the generic RGB color space.
colorSpace = CGColorSpaceCreateDeviceRGB();
if (colorSpace == NULL)
{
fprintf(stderr, "Error allocating color space\n");
return NULL;
}
//Allocate memory for image data. This is the destination in memory
//where any drawing to the bitmap context will be rendered.
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL)
{
fprintf (stderr, "Memory not allocated!");
CGColorSpaceRelease( colorSpace );
return NULL;
}
//Create the bitmap context. We want pre-multiplied ARGB, 8-bits
//per component. Regardless of what the source image format is
//(CMYK, Grayscale, and so on) it will be converted over to the format
//specified here by CGBitmapContextCreate.
context = CGBitmapContextCreate (bitmapData,
pixelsWide,
pixelsHigh,
8, //bits per component
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedFirst);
if (context == NULL)
{
free (bitmapData);
fprintf (stderr, "Context not created!");
}
//Make sure and release colorspace before returning
CGColorSpaceRelease( colorSpace );
return context;
}
En fait, dans l'iOS 4.0 UIKit fonctions de dessin sont maintenant des threads: cocoabuilder.com/archive/cocoa/... . Cela semble inclure
est la citation d'autorité? stackoverflow.com/questions/4451855/... il y a des débats sur, je suppose?, et mon code de test est mort avec UIGraphicsBeginImageContext() sur un thread séparé. bien que je ne peux pas être sûr à 100% que c'est la vraie raison.
c'est une autre question, quand vous dites que l'iOS 4.0, il ne s'applique pas lorsque je cible iOS < 4.0 mais compiler avec iOS >= 4.0 ? ou le code doit s'exécuter sur la machine avec iOS >=4.0?
David Duncan est un ingénieur de chez Apple, donc je dirais que sa déclaration, combiné avec les notes de version, fait autorité. Ce n'est thread-safe lorsqu'il est exécuté sur iOS 4.0+, parce qu'bâtiment contre la 4.x SDK utilise toujours les locaux de l'OS de la mise en œuvre si le ciblage des versions plus anciennes. Si vous avez besoin d'anciens OS de soutien, vous aurez toujours besoin d'aller à la pure Graphiques de Base de l'itinéraire.
UIGraphicsBeginImageContext()
. Vous ne pouvez pas besoin de la pure Graphiques de Base de la mise en œuvre de la version 4.0+.est la citation d'autorité? stackoverflow.com/questions/4451855/... il y a des débats sur, je suppose?, et mon code de test est mort avec UIGraphicsBeginImageContext() sur un thread séparé. bien que je ne peux pas être sûr à 100% que c'est la vraie raison.
c'est une autre question, quand vous dites que l'iOS 4.0, il ne s'applique pas lorsque je cible iOS < 4.0 mais compiler avec iOS >= 4.0 ? ou le code doit s'exécuter sur la machine avec iOS >=4.0?
David Duncan est un ingénieur de chez Apple, donc je dirais que sa déclaration, combiné avec les notes de version, fait autorité. Ce n'est thread-safe lorsqu'il est exécuté sur iOS 4.0+, parce qu'bâtiment contre la 4.x SDK utilise toujours les locaux de l'OS de la mise en œuvre si le ciblage des versions plus anciennes. Si vous avez besoin d'anciens OS de soutien, vous aurez toujours besoin d'aller à la pure Graphiques de Base de l'itinéraire.
OriginalL'auteur eugene | 2011-01-13
Vous devez vous connecter pour publier un commentaire.
Votre deuxième méthode est de faire un travail que les premiers ne l'ont jamais fait. Voici un ajustement de la seconde méthode pour mieux correspondre à la première:
Les deux changements que j'ai faits ont été je me suis converti pour utiliser
CGContextSetFillColorWithColor()
, et j'ai enlevé la dangereuse et erronéefree()
de la sauvegarde des données de l'image bitmap contexte. Si ce bout de code ne se comportent pas de façon identique à la première, alors vous allez avoir à regarder dans votre mise en œuvre deCreateARGBBitmapContext()
pour vérifier qu'elle est correcte.Bien sûr, comme Brad Larson mentionné dans les commentaires, si vous ciblez iOS 4.0 et ci-dessus, le UIKit méthodes graphiques sont (selon les notes de version) et thread-safe, vous devriez être en mesure d'utiliser la première méthode de l'amende juste.
Ah, je vois ce qu'il se passe. Vous êtes malloc avec vos propres données, puis la suppression de la référence à elle. De sorte que les données n'a en effet besoin d'être libéré plus tard. Il se sent juste assez méchant pour extraire les données à partir du contexte et de l'appel
free()
. Si vous voulez une alternative, au lieu demalloc()
vous pouvez créer uneNSMutableData
de la bonne taille et de saisir-mutableBytes
. Qui vous donnera le même tampon, mais autoreleased. Bien sûr, si vous n'avez que le contexte doit être libérée avant l'autorelease pool pop (mais tu fais ici de toute façon).une chose de plus, dois-je libérer le imageRef avec CGImageRelease?
la haine de la documentation d'apple, ne dit pas clairement si j'ai besoin de libérer ou non 🙁
Oh oui, vous devrait à l'évidence.
CGBitmapContextCreateImage()
vous donne une propriété de référence.+[UIImage imageWithCGImage:]
de conserver laCGImageRef
pour la durée de vie de laUIImage
objet. Mais vous aurez votre propriété de référence, qui vous avez besoin pour libérer avecCGImageRelease()
.OriginalL'auteur Lily Ballard