How to create transparent areas in a UIImage? - ios

i'm creating a game for iPhone, with xcode. I have a starting image, from which i'd like to have a second image with some (four) transparent areas in it, e.g. just like this one:
The problem is that i don't know how to achieve it; have i to handle the original image and to cut the areas from it? or have i to create a new image where i put only the visible parts from the original one?
Any suggestion or snippet would be really appreciated.

Well, I'd do it by creating custom UIView subclass and using its drawRect method to draw the portion.
Fo example:
-(void)drawRect:(
CGRect)rect
{
[super drawRect:rect];
CGContextRef ctx = UIGraphicsGetCurrentContext(); // get drawing context
CGContextSaveGState(ctx); //remember current state
CGContextClipToRect(ctx, CGRectMake(0, 0, 100, 100)); //set clipping
CGContextDrawImage(ctx, CGRectMake(0, 0, img.size.width, img.size.height), img.CGImage);
CGContextRestoreGState(ctx); //restore state, so the previous clipping will be canceled
CGContextSaveGState(ctx);
CGContextClipToRect(ctx, CGRectMake(100, 100, 100, 100));
CGContextDrawImage(ctx, CGRectMake(0, 0, img.size.width, img.size.height), img.CGImage);
CGContextRestoreGState(ctx);
}
This will draw two small rects. In this code img is an UIImage.
However, this is the easiest way to do this, not the most efficient - it requres to redraw for each portion. You might want to check CGContextClipToRects and CGContextClip functions, to make it more efficient and flexible.

Related

Zoom effect in a UIView image

When user hovers over the image,tapping on certain body part presents the magnified image of that area. I wanted to know any possible third party frameworks that address such kind of feature or code snippets(like using which gesturerecognizers) that can help me attain this feature.
Question 2: Also I have to add a dynamic clickable Label at the point where the touch happens and ends (as you can see the wrist label in image) so that I can take the user to a separate view from this screen on clicking the label. How to make this possible?
In your drawRect method, mask off a circle (using a monochrome bitmap containing the 'mask' of your magnifying glass) and draw your subject view in there with a 2x scale transform. Then draw a magnifying glass image over that and you're done.
- (void) drawRect: (CGRect) rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect bounds = self.bounds;
CGImageRef mask = [UIImage imageNamed: #"loupeMask"].CGImage;
UIImage *glass = [UIImage imageNamed: #"loupeImage"];
CGContextSaveGState(context);
CGContextClipToMask(context, bounds, mask);
CGContextFillRect(context, bounds);
CGContextScaleCTM(context, 2.0, 2.0);
//draw your subject view here
CGContextRestoreGState(context);
[glass drawInRect: bounds];
}
Check this link for complete example.

Scaling an image is slow on an iPad 4th gen, are there faster alternatives?

I'm trying to zoom and translate an image on the screen.
here's my drawRect:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetShouldAntialias(context, NO);
CGContextScaleCTM (context, senderScale, senderScale);
[self.image drawAtPoint:CGPointMake(imgposx, imgposy)];
CGContextRestoreGState(context);
}
When senderScale is 1.0, moving the image (imgposx/imgposy) is very smooth. But if senderScale has any other value, performance takes a big hit and the image stutters when I move it.
The image I am drawing is a UIImageobject. I create it with
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
and draw a simple UIBezierPath(stroke):
self.image = UIGraphicsGetImageFromCurrentImageContext();
Am I doing something wrong? Turning off the anti-aliasing did not improve things much.
Edit:
I tried this:
rectImage = CGRectMake(0, 0, self.frame.size.width * senderScale, self.frame.size.height * senderScale);
[image drawInRect:rectImage];
but it was just as slow as the other method.
If you want this to perform well, you should let the GPU do the heavy lifting by using CoreAnimation instead of drawing the image in your -drawRect: method. Try creating a view and doing:
myView.layer.contents = self.image.CGImage;
Then zoom and translate it by manipulating the UIView relative to its superview. If you draw the image in -drawRect: you're making it do the hard work of blitting the image for every frame. Doing it via CoreAnimation only blits once, and then subsequently lets the GPU zoom and translate the layer.

How to move the image on the CGContextRef

An image has been drawn on the CGContextRef:
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image);
In another function, I want to move the image to the rect like
CGRectMake(100, 100, width, height);
How can I do?
void func(CGContextRef context)//there is just one parameter
{
//move the image
}
Once you've drawn to the context it can't be undone. You can draw over the previous image, perhaps with a solid color to match the background. I don't know why you would ever want to draw to a context and then move it.
I'm going to assume the first function that draws the image calls the second one that positions it. If that is the case, you can have the second function simply apply a translation transform to the context and then have the first function draw the image after calling the second.
Try this
void func(CGContextRef context, CGFloat x, CGFloat y)
{
CGContextDrawImage(context, CGRectMake(x,y, width, height), image);
}

How to smooth edges of drawn image?

I'm using this code to colorize some images of a UIButton subclass:
UIImage *img = [self imageForState:controlState];
// begin a new image context, to draw our colored image onto
UIGraphicsBeginImageContextWithOptions(img.size, NO, 0.0f);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// set the fill color
[self.buttonColor setFill];
CGContextSetAllowsAntialiasing(context, true);
CGContextSetShouldAntialias(context, true);
// translate/flip the graphics context (for transforming from CG* coords to UI* coords
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// set the blend mode to multiply, and the original image
CGContextSetBlendMode(context, kCGBlendModeScreen);
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
CGContextDrawImage(context, rect, img.CGImage);
// set a mask that matches the shape of the image, then draw the colored image
CGContextClipToMask(context, rect, img.CGImage);
CGContextAddRect(context, rect);
CGContextDrawPath(context,kCGPathFill);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//return the colored image
[self setImage:coloredImg forState:controlState];
But the images come out with rough edges. I've tried using screen, lighten, and plusLighter blend modes, because some of the images have white parts that I want to stay white. The only part I want colorized is the black areas. I've attached the original button images, and after they've been colorized. I can't get the edges to look good. When I had them as white images that were colorized using multiply blend mode, it looked much better. But I want to use black so I can use one method for colorizing images with and without white in them. I tried with anti-aliasing, that didn't help either. It looks like it just isn't anti-aliasing it. I haven't worked with Core Graphics enough to know what's up with it.
EDIT
Here's what the original PNGs look like:
and here's what it should look like:
and here's what it does look like:
The size if different, but you can see the bad quality around the edges.
Maybe your original icons (PNGs?) are just "too sharp"? Could you show us? You just draw the image at its original size without resizing, so the problem could be right from the start.
I'm not sure what is what you are trying to accomplish here. Are you trying to round the edges of the images? If so, you are better of by changing the round corner property of the UIButton's layer. Since UIButton is a subclass of UIView, you can get its layer property and change the edge color and round its corner.

why CGContextSaveGState is not required even after several modification to the current context?

I am really strugggling with Quartz2D for more then 10 days please help me understand few concepts I will be really grateful, please look at this code and screenshot url.
This code draw image with border and write text to it and the image become whole new image with border and text.
//part 1
CGSize cgs = CGSizeMake(250.0, 400.0);
UIGraphicsBeginImageContext(cgs);
CGRect rectangle = CGRectMake(0,0,cgs.width,cgs.height);
CGRect imageRect = CGRectInset(rectangle, 5.4, 5.4);
imageRect.size.height -= 100;
UIImage *myImage = [UIImage imageNamed:#"BMW.jpg"];
[myImage drawInRect:imageRect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 10.0);
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 1.0, 1.0);
CGContextStrokeRect(context, rectangle);
//
//part 2
1. CGRect contextRect = rectangle;
2. CGContextTranslateCTM(context, 0, contextRect.size.height);
3. CGContextScaleCTM(context, 1, -1);
4. float w, h;
5. w = contextRect.size.width;
6. h = contextRect.size.height;
7. CGContextSelectFont (context, "Helvetica-Bold", 25,
kCGEncodingMacRoman);
8. CGContextSetCharacterSpacing (context, 5);
9. CGContextSetRGBFillColor(context, 0.0, 1.0, 1.0, 1.0);
10. CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);
11. CGContextShowTextAtPoint(context, 45, 50, "Quartz 2D", 9);
//
//part 3
UIImage *testImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[testImg drawAtPoint:CGPointMake(35, 10)];
//
http://i40.tinypic.com/140aptv.png
part 1 and part 3 of the code is very clear to me
problem is regarding part 2
on line 2 and 3 coordinates are transformed so the text do not display
upside down, but uiimage already take care of this internally, why it
didn't transformed to upside down? why it is still displaying in
correct position after transform is applied for text using same
context? I am asking this because when uiimage coordinates are already
modified then this coordinate transform will not make uiimage again
upside down?
on line 9 and 10 fillcolor and strokecolor methods are called and
fillcolor changes the text color, but strokecolor not doing any thing
to text why? And why without CGContextSaveGState it modified the
color of text not the border color?
regarding these both points I mentioned above the common confusion is
why its working perfectly why this code didn't need
CGContextSaveGState and CGContextRestoreGState. How it is possible
that context is modified and it didn't effect the perviously drawing
item like blue border in this case and coordinates transformation for
text.
Please correct me if I am lacking in any way to make you understand my points.
Thanks in advance,
Regards.
Quartz 2D uses the "painter's model." That means, you draw one thing, and it's done. Then you draw another thing, and it goes on top of what you drew before. Then you draw another thing and that goes on top, etc. If I pick up a stamp, dip it in paint and press it to paper, then turn it over and do it again to another part of the paper, the first stamped image doesn't flip over just because I flipped the stamp.
Every time you see "stroke" or "draw," you're modifying the final image. Later changes to the context don't effect that.

Resources