Effacer et effacer une image dans UIImageVIew avec le toucher en utilisant coregraphics

Ma question est la même que celle mentionnée ici . J'utilise également deux images dans mon application et tout ce dont j'ai besoin est d'effacer une image supérieure au toucher. Effacez ensuite (si nécessaire) la partie effacée au toucher. J'utilise le code suivant pour effacer l'image supérieure. Il y a aussi un problème dans cette approche. Ce qui veut dire que les images sont grandes et j'utilise le mode contenu d'Aspect Fit pour les afficher correctement. Quand je touche sur l'écran, il efface dans le coin pas l'endroit touché. Je pense que le calcul du sharepoint contact est nécessaire. Toute aide serait appréciée.

Le deuxième problème est que comment effacer la partie effacée par le toucher?

UIGraphicsBeginImageContext(self.imgTop.image.size); [self.imgTop.image drawInRect:CGRectMake(0, 0, self.imgTop.image.size.width, self.imgTop.image.size.height)]; self.frame.size.width, self.frame.size.height)]; CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); GContextSetLineWidth(UIGraphicsGetCurrentContext(), pinSize); CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 0, 0, 0, 1.0); CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeCopy); CGContextBeginPath(UIGraphicsGetCurrentContext()); CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y); CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y); CGContextStrokePath(UIGraphicsGetCurrentContext()); self.imgTop.contentMode = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); 

Votre code est assez ambigu: vous créez un context avec imgTop à l' intérieur, puis vous kCGBlendModeCopy avec kCGBlendModeCopy la couleur noire? Cela entraînerait la copy de la couleur noire sur imgTop . Je suppose que vous vouliez définir la propriété de content la couche alors?

Quoi qu'il en soit, cette class fait ce dont vous avez besoin. Il n'y a que quelques methods intéressantes (elles sont en haut), les autres ne sont que des propriétés ou des routines init...

 @interface EraseImageView : UIView { CGContextRef context; CGRect contextBounds; } @property (nonatomic, retain) UIImage *backgroundImage; @property (nonatomic, retain) UIImage *foregroundImage; @property (nonatomic, assign) CGFloat touchWidth; @property (nonatomic, assign) BOOL touchRevealsImage; - (void)resetDrawing; @end @interface EraseImageView () - (void)createBitmapContext; - (void)drawImageScaled:(UIImage *)image; @end @implementation EraseImageView @synthesize touchRevealsImage=_touchRevealsImage, backgroundImage=_backgroundImage, foregroundImage=_foregroundImage, touchWidth=_touchWidth; #pragma mark - Main methods - - (void)createBitmapContext { // create a grayscale colorspace CGColorSpaceRef grayscale=CGColorSpaceCreateDeviceGray(); /* TO DO: instead of saving the bounds at the moment of creation, override setFrame:, create a new context with the right size, draw the previous on the new, and replace the old one with the new one. */ contextBounds=self.bounds; // create a new 8 bit grayscale bitmap with no alpha (the mask) context=CGBitmapContextCreate(NULL, (size_t)contextBounds.size.width, (size_t)contextBounds.size.height, 8, (size_t)contextBounds.size.width, grayscale, kCGImageAlphaNone); // make it white (touchRevealsImage==NO) CGFloat white[]={1., 1.}; CGContextSetFillColor(context, white); CGContextFillRect(context, contextBounds); // setup drawing for that context CGContextSetLineCap(context, kCGLineCapRound); CGContextSetLineJoin(context, kCGLineJoinRound); CGColorSpaceRelease(grayscale); } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch *touch=(UITouch *)[touches anyObject]; // the new line that will be drawn CGPoint points[]={ [touch previousLocationInView:self], [touch locationInView:self] }; // setup width and color CGContextSetLineWidth(context, self.touchWidth); CGFloat color[]={(self.touchRevealsImage ? 1. : 0.), 1.}; CGContextSetStrokeColor(context, color); // stroke CGContextStrokeLineSegments(context, points, 2); [self setNeedsDisplay]; } - (void)drawRect:(CGRect)rect { if (self.foregroundImage==nil || self.backgroundImage==nil) return; // draw background image [self drawImageScaled:self.backgroundImage]; // create an image mask from the context CGImageRef mask=CGBitmapContextCreateImage(context); // set the current clipping mask to the image CGContextRef ctx=UIGraphicsGetCurrentContext(); CGContextSaveGState(ctx); CGContextClipToMask(ctx, contextBounds, mask); // now draw image (with mask) [self drawImageScaled:self.foregroundImage]; CGContextRestoreGState(ctx); CGImageRelease(mask); } - (void)resetDrawing { // draw black or white CGFloat color[]={(self.touchRevealsImage ? 0. : 1.), 1.}; CGContextSetFillColor(context, color); CGContextFillRect(context, contextBounds); [self setNeedsDisplay]; } #pragma mark - Helper methods - - (void)drawImageScaled:(UIImage *)image { // just draws the image scaled down and centered CGFloat selfRatio=self.frame.size.width/self.frame.size.height; CGFloat imgRatio=image.size.width/image.size.height; CGRect rect={0.,0.,0.,0.}; if (selfRatio>imgRatio) { // view is wider than img rect.size.height=self.frame.size.height; rect.size.width=imgRatio*rect.size.height; } else { // img is wider than view rect.size.width=self.frame.size.width; rect.size.height=rect.size.width/imgRatio; } rect.origin.x=.5*(self.frame.size.width-rect.size.width); rect.origin.y=.5*(self.frame.size.height-rect.size.height); [image drawInRect:rect]; } #pragma mark - Initialization and properties - - (id)initWithCoder:(NSCoder *)aDecoder { if ((self=[super initWithCoder:aDecoder])) { [self createBitmapContext]; _touchWidth=10.; } return self; } - (id)initWithFrame:(CGRect)frame { if ((self=[super initWithFrame:frame])) { [self createBitmapContext]; _touchWidth=10.; } return self; } - (void)dealloc { CGContextRelease(context); [super dealloc]; } - (void)setBackgroundImage:(UIImage *)value { if (value!=_backgroundImage) { [_backgroundImage release]; _backgroundImage=[value retain]; [self setNeedsDisplay]; } } - (void)setForegroundImage:(UIImage *)value { if (value!=_foregroundImage) { [_foregroundImage release]; _foregroundImage=[value retain]; [self setNeedsDisplay]; } } - (void)setTouchRevealsImage:(BOOL)value { if (value!=_touchRevealsImage) { _touchRevealsImage=value; [self setNeedsDisplay]; } } @end 

Quelques notes:

  • Cette class conserve les deux images dont vous avez besoin. Il possède une propriété touchRevealsImage pour définir le mode de dessin ou d'effacement et vous pouvez définir la largeur de la ligne.

  • Lors de l'initialisation, il crée un CGBitmapContextRef , en niveaux de gris, 8bpp, sans alpha, de la même taille de la vue. Ce context est utilisé pour stocker un masque, qui sera appliqué à l'image de premier plan.

  • Chaque fois que vous déplacez un doigt sur l'écran, une ligne est dessinée sur le CGBitmapContextRef utilisant CoreGraphics, blanc pour révéler l'image, noir pour le cacher. De cette façon, nous stockons le dessin ab / w.

  • La routine drawRect: dessine simplement l'arrière-plan, puis crée un CGImageRef partir de CGBitmapContextRef et l'applique au context actuel en tant que masque. Dessine ensuite l'image de premier plan. Pour dessiner des images, il utilise - (void)drawImageScaled:(UIImage *)image , qui dessine juste l'image mise à l'échelle et cinput.

  • Si vous envisagez de resize la vue, vous devez implémenter une méthode pour copyr ou recréer le masque avec une nouvelle taille, en - (void)setFrame:(CGRect)frame .

  • La méthode de - (void)reset efface simplement le masque.

  • Même si le context bitmap n'a pas de canal alpha, l'espace colorimésortingque en niveaux de gris utilisé est alpha: c'est pourquoi chaque fois qu'une couleur est définie, j'ai dû spécifier deux composants.

Exemple d'application avec la classe <code> EraseImageView </ code>