8

I am trying to make a view that lets a user draw with their finger. I have a png made in Pixelmator of the brush. My drawRect: method looks like this:

- (void)drawRect:(CGRect)rect
{

    NSAssert(brush != nil, @"");

    for (UITouch *touch in touchesNeedingDrawing)
    {
        //Draw the touch
        [brush drawInRect:CGRectWithPoints([touch locationInView:self], [touch previousLocationInView:self]) blendMode:0 alpha:1];
    }

    [touchesNeedingDrawing removeAllObjects];
}

The brush image is a png with transparency, but when I run the app, there is no transparency. Does anyone know why, and how to fix it?

Edit: I discovered that the image is transparent, but when I call drawInRect, the image draws the transparent pixels as the background color of the view. Is there a CGBlendMode I can use to fix this?

Adrian Sarli
  • 2,286
  • 3
  • 20
  • 31
  • brush is a UIImage, just to clarify. – Adrian Sarli Jul 31 '11 at 15:19
  • why can't you use an UIImageView? – ySgPjx Aug 01 '11 at 12:39
  • Because I would need hundreds of UIImageView subviews, which would be impractical. I am trying to let a user paint with their finger with a brush image, and each time their finger moves, I would need a new UIImageView. I would also have problems deleting. – Adrian Sarli Aug 01 '11 at 12:51
  • You don't need an UIImageView for every touch. Actually the usual way to do this task is to create an UIImageView and draw on it based on user input. – ySgPjx Aug 01 '11 at 13:11
  • I'm doing almost what you're suggesting, only I'm just using a UIView. Every time someone drags their finger, I tell the UIImage to draw itself at that location. – Adrian Sarli Aug 01 '11 at 13:13

6 Answers6

5

Solution is very simple, testes on my own project. In class which you updated with custom - (void)drawRect:(CGRect)rect set in -(id)init background color for self

[self setBackgroundColor:[UIColor clearColor]];

And thats all. Tested on my project.

Serhii Mamontov
  • 4,942
  • 22
  • 26
  • +1. Great. Especially seeing the "I believe that...", "It seems like.." and "I should.." answers. Facts. Love it :-) – vstrien Aug 06 '11 at 21:51
  • @moonlight — I think you meant "tested" on your own project, not "testes" on your own project. – Todd Lehman May 09 '13 at 03:45
1

It seems like it could be taking the current fill color of the context.

Try setting the fill color for the context with CGContextSetFillColorWithColor() to [UIColor clearColor].CGColor

If that doesn't work, the only other solution that is simple and shouldn't have a performance hit is to have 2 views:

  • Background View - This will be view that has the proper background color or image
  • Overlay View - This view will detect the touches etc and then draw all of the brush strokes on top. The background color of this view can then be [UIColor clearColor] so when you draw the brush images, the alpha will be filled with [UIColor clearColor]. Basically the same view you have now, just with a clear background.

Note: You shouldn't need to mess with the blend mode to make this work. You should be able to use the default drawInRect: method

MayorJustin
  • 281
  • 2
  • 6
0

Is the brush png loaded to an imageView? That is, the variable brush is an object of UIImageView, isn't it? If so, perhaps simple

brush.backgroundColor = [UIColor clearColor];

will help

makaron
  • 1,585
  • 2
  • 16
  • 30
  • 1
    i suggest making it a UIImageView. `UIImageView *brush = [UIImageView imageNamed:@"brush.png"];` – ColdLogic Jul 28 '11 at 19:04
  • Btw perhaps it is the reason why I thought it's gonna be UIImageView. Seems I collided with the same problem, working with UIImage. – makaron Jul 28 '11 at 19:06
  • The only problem with that is that I'd end up with a huge number of views that I could never get rid of. – Adrian Sarli Jul 28 '11 at 19:14
0

i think you should try destination out blend mode: kCGBlendModeDestinationOut.

You could also draw at point instead draw in rect:

[brush drawAtPoint:[touch locationInView:self] blendMode:kCGBlendModeDestinationOut alpha:1]
Swapnil Luktuke
  • 10,385
  • 2
  • 35
  • 58
0

A possible issue is that you are setting the blendMode to 0. I suggest using the -drawInRect: method without a blend mode. The issue may also be that your view has a black background, but that is doubtful. I would also suggest attempting to display the UIImage in a UIImageView as a test. The issue may be related to the way that PixelMator exports images.

Alex Nichol
  • 7,512
  • 4
  • 32
  • 30
0

Your problem is a fundamental misconception of how drawRect: actually works. Every time you draw something into the current graphics context, everything that was there previously will be cleared (so that only the backgroundColor remains).

Since you're only drawing the current touch(es) (touchesNeedingDrawing is emptied), there's nothing under the rectangle you're filling that could show the transparency of the image you're drawing, so the background color shows through.

You basically have two options to resolve this:

1) Keep all touches that contribute to the drawing around (don't empty the touchesNeedingDrawing array) and redraw all of them every time – this is going to be easy but quite slow.

2) Draw into a buffer of some kind (e.g. a UIImage, using UIGraphicsBeginImageContext etc.). Every time your drawing changes, create a new buffer. Draw the old buffer into the new buffer and the images for the new stroke on top of it.

omz
  • 53,243
  • 5
  • 129
  • 141