Cómo dibujar un trazo transparente (o, en cualquier caso, borrar una parte de una imagen) en el iPhone

votos
18

Tengo una pequeña aplicación que permite al usuario dibujar en la pantalla con el dedo. Tengo una UIImageViewdonde el usuario dibuja, creando una CGContextRefy varias CG drawfunciones. Principalmente dibujo trazos / líneas con la funciónCGContextAddLineToPoint

Ahora mi problema es este: el usuario puede dibujar líneas de varios colores. Quiero darle la capacidad de usar una rubberherramienta para eliminar alguna parte de la imagen dibujada hasta el momento, con el dedo. Inicialmente hice esto usando un color blanco para el trazo (configurado con la CGContextSetRGBStrokeColorfunción) pero no funcionó ... porque descubrí más tarde que el UIImageen UIImageViewrealidad tenía un fondo transparente, no blanco ... así que lo haría ¡termina con una imagen transparente con líneas blancas!

¿Hay transparentalguna forma de establecer un color de trazo o hay alguna otra forma de borrar el contenido CGContextRefdebajo del dedo del usuario, cuando lo mueve? Gracias

Publicado el 10/03/2009 a las 10:18
fuente por usuario
En otros idiomas...                            


6 respuestas

votos
57

Esto va a hacer el truco:

CGContextSetBlendMode(context, kCGBlendModeClear)
Respondida el 27/04/2010 a las 19:29
fuente por usuario

votos
6

Terminé usando el algoritmo de línea de Bresenham (recordando los días de antaño cuando tuve que escribir mis propias rutinas gráficas) ...

- (void) contextEraseLine:(CGContextRef) ctx from:(CGPoint)startPoint to:(CGPoint) endPoint withThickness:(int)thickness {
    int x, cx, deltax, xstep,
    y, cy, deltay, ystep,
    error, st, dupe;

    int x0, y0, x1, y1;

    x0 = startPoint.x;
    y0 = startPoint.y;
    x1 = endPoint.x;
    y1 = endPoint.y;

    // find largest delta for pixel steps
    st = (abs(y1 - y0) > abs(x1 - x0));

    // if deltay > deltax then swap x,y
    if (st) {
        (x0 ^= y0); (y0 ^= x0); (x0 ^= y0); // swap(x0, y0);
        (x1 ^= y1); (y1 ^= x1); (x1 ^= y1); // swap(x1, y1);
    }

    deltax = abs(x1 - x0);
    deltay = abs(y1 - y0);
    error  = (deltax / 2);
    y = y0;

    if (x0 > x1) { xstep = -1; }
    else         { xstep =  1; }

    if (y0 > y1) { ystep = -1; }
    else         { ystep =  1; }

    for ((x = x0); (x != (x1 + xstep)); (x += xstep))
    {
        (cx = x); (cy = y); // copy of x, copy of y

        // if x,y swapped above, swap them back now
        if (st) { (cx ^= cy); (cy ^= cx); (cx ^= cy); }

        (dupe = 0); // initialize no dupe

        if(!dupe) { // if not a dupe, write it out
            //NSLog(@"(%2d, %2d)", cx, cy);

            CGContextClearRect(ctx, CGRectMake(cx, cy, thickness, thickness));

    }

        (error -= deltay); // converge toward end of line

        if (error < 0) { // not done yet
            (y += ystep);
            (error += deltax);
        }
    }
}

¡Uf! Eso es un largo camino por recorrer para crear una línea de borrador (algo) torpe.

Para usarlo, haz algo como:

- (void)eraseStart {
    // erase lines
    UIGraphicsBeginImageContext(drawingBoard.size);
    ctx = UIGraphicsGetCurrentContext();
    CGContextDrawImage(ctx,CGRectMake(0,0,drawingBoard.size.width, drawingBoard.size.height),[drawingBoard CGImage]); 
}

- (void)eraseEnd {
    drawingBoard = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    [drawingView removeFromSuperview];
    [drawingView release];

    drawingView = [[UIImageView alloc] initWithImage:drawingBoard];
    drawingView.frame = CGRectMake(intEtchX, intEtchY, intEtchWidth, intEtchHeight);

    [self.view addSubview:drawingView];
}

Esto supone que ya ha creado un drawingView (UIImageView) y drawingBoard (UIImage).

Luego, para borrar una línea, simplemente haz algo como:

CGContextRef ctx = UIGraphicsGetCurrentContext();
[self eraseStart];
[self contextEraseLine:ctx from:CGPointMake (x1, y1) to:CGPointMake (x2, y2) withThickness:10];
[self eraseEnd];

(reemplace x1, y1, x2 e y2 con los valores apropiados) ...

Respondida el 04/04/2009 a las 06:33
fuente por usuario

votos
1

He intentado usar:

CGContextSetStrokeColorWithColor (myContext, [[UIColor clearColor] CGColor]);

pero eso no funciona, porque parece estar "dibujando" en la parte superior del contexto con un color invisible (y un color invisible + cualquier color en el que se dibuja = el color en el que se dibuja).

La única solución que he encontrado (que no es óptima) es:

CGContextClearRect (myContext, CGRectMake(x, y, width, height));

Desafortunadamente, eso significa que debe rastrear una serie de rectas y generar la línea usted mismo ...

Respondida el 30/03/2009 a las 21:59
fuente por usuario

votos
0

Si desea borrar la imagen con este toque es mi código .... la parte unerase no recomienda que está trabajando, pero un poco lento.

func addNewPathToImage(){
    print("Start erasing or not erasing")

    UIGraphicsBeginImageContextWithOptions(TopImageUIImageView.bounds.size, false, UIScreen.main.scale) // or 0 for the scale

//My image is aspect fit so I need to get rect

    let aspect = TopImageUIImageView.image!.size.width / TopImageUIImageView.image!.size.height
    let viewRatio = TopImageUIImageView.bounds.size.width / TopImageUIImageView.bounds.size.height


    if aspect < viewRatio {
        let scale = TopImageUIImageView.bounds.size.height / TopImageUIImageView.image!.size.height
        let width = scale * TopImageUIImageView.image!.size.width
        let topLeftX = (TopImageUIImageView.bounds.size.width - width) * 0.5
        rect = CGRect(x: topLeftX, y: 0, width: width, height: TopImageUIImageView.bounds.size.height)
    }
    else {
        let scale = TopImageUIImageView.bounds.size.width / TopImageUIImageView.image!.size.width
        let height = scale * TopImageUIImageView.image!.size.height
        let topLeftY = (TopImageUIImageView.bounds.size.height - height) * 0.5
        rect = CGRect(x: 0.0, y: topLeftY, width: TopImageUIImageView.bounds.size.width, height: height)
    }
    ////
    context = UIGraphicsGetCurrentContext()
    TopImageUIImageView.image?.draw(in: rect)
    context?.setLineCap(.round)
    context?.setLineWidth(brushSize)



    if isErasing == true {

        context?.setShadow(offset: CGSize(width: 0, height: 0), blur: blurNumber)
        context?.setStrokeColor(UIColor.white.cgColor)
        context?.setBlendMode(.clear)


    }else{

        print("test the unerase image .... ?")
        context?.setStrokeColor(UIColor.init(patternImage: topImage.af_imageAspectScaled(toFit: CGSize(width: TopImageUIImageView.bounds.size.width, height: TopImageUIImageView.bounds.size.height))).cgColor)

    }


   // I am using these because I am using touch to define what to erase 
        context?.move(to: CGPoint(x: lastTouch.x, y: lastTouch.y))
        context?.addLine(to: CGPoint(x: currentTouch.x, y: currentTouch.y))
        context?.strokePath()
        context?.closePath() // when add this line or the "context?.beginPath" get ERROR CGContextClosePath: no current point.
        print("close the path")




        //get your image 
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        TopImageUIImageView.image = image

}
Respondida el 28/03/2019 a las 14:01
fuente por usuario

votos
-2
//erase part
if(mouseSwiped)
{

//**************Working Code*************// 


UIGraphicsBeginImageContext(frontImage.frame.size);
[frontImage.image drawInRect:CGRectMake(0, 0, frontImage.frame.size.width, frontImage.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(),kCGImageAlphaNone); //kCGImageAlphaPremultipliedLast);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 10);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), 1, 0, 0, 10);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextClearRect (UIGraphicsGetCurrentContext(), CGRectMake(lastPoint.x, lastPoint.y, 10, 10));
CGContextStrokePath(UIGraphicsGetCurrentContext());
frontImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();


lastPoint = currentPoint;

mouseMoved++;

if (mouseMoved == 10) 
{
    mouseMoved = 0;
}
}
Respondida el 24/08/2011 a las 16:25
fuente por usuario

votos
-13
UIColor *clearColor = [UIColor clearColor];
Respondida el 10/03/2009 a las 15:07
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more