I am trying to add a clip mask to my image.
And then making painting with finger touches on the screen.
Finger touches and clip mask works but the problem is my UIImage looks invert up and down.
How can I correct that?
This is the line of code for my mask:
CGContextClipToMask(context, rect, myIconImage.CGImage);
Thanks
I found the answer and I wanna share it.
It is quite simply actually. Since the CGImage is inverting a UIImage I added these lines before the ClipToMask line:
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
with this code, it works!
Related
In the application I'm working at you can take a picture with the iPad camera. After that using CoreGraphics you can draw shapes on that image.
At first the image was upside down and mirrored. I resolved that with this:
CGContextTranslateCTM(myContext, 0, backgroundImage.size.height);
CGContextScaleCTM(myContext, 1.0, -1.0);
But now when you take the image in portrait mode, the imported image is rotated to the left (so it's presented horizontally). I rotated the image back with this code:
UIImage *tempImage = [[UIImage alloc] initWithCGImage:imagetest.CGImage];
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformTranslate(transform, 0, tempImage.size.height);
transform = CGAffineTransformRotate(transform, -M_PI_2);
CGContextRef ctx = CGBitmapContextCreate(NULL, tempImage.size.width, tempImage.size.height,
CGImageGetBitsPerComponent(tempImage.CGImage), 0,
CGImageGetColorSpace(tempImage.CGImage),
CGImageGetBitmapInfo(tempImage.CGImage));
CGContextConcatCTM(ctx, transform);
CGContextDrawImage(ctx, CGRectMake(0,0,tempImage.size.height,tempImage.size.width), tempImage.CGImage);
CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
UIImage *img = [UIImage imageWithCGImage:cgimg];
CGContextRelease(ctx);
CGImageRelease(cgimg);
Now the image is shown in the right way (portrait), but I can't draw properly on it, maybe because the width and height are reversed.
From what I read there is a meta tag with the image orientation that cannot be read by CoreGraphics.
Do you know a better way to rotate the image? Or any solution that would keep the image from rotating when taking a photo in portrait mode?
Yes that is an issue because default orientation of device camera is Landscape, if you take picture in portrait mode and see preview in Photo Gallery it will be fine, but as you use it in your app it will be rotated 90 Degrees, to fix that issue i have written answer in my Recent Post Here
If you tell the image to draw itself, it will respect its own orientation. No need to flip it (it does that itself) and no need to rotate it.
So I'm using the code below to apply a stroke (and fill) to text in a UILabel, and it's coming out like the image below. The stroke is heavier on one side than the other (look at the top of the letters compared to the bottom, and the right compared to the left. The period at the end makes it very noticeable, too, looks like a googly eye). I've not got any shadowing turned on at all, so I don't think it's the shadow interfering with the stroke.
What could be causing this?
- (void) drawTextInRect: (CGRect) rect
{
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetTextDrawingMode(c, kCGTextFillStroke);
CGContextSaveGState(c);
CGContextSetRGBFillColor(c, 1.0, 0.0, 0.0, 1.0);
CGContextSetRGBStrokeColor(c, 0.0, 1.0, 0.0, 1.0);
[super drawTextInRect: rect];
CGContextRestoreGState(c);
}
EDIT: So, for kicks, I took at look at the label with only the fill, and only the stroke. Turning off the stroke creates a perfectly normal-looking piece of text, as if I'd just coloured it in Interface Builder. Turning off the fill, however, shows only the stroke, which doesn't look heavier on any side than any other. **This leads me to believe that the issue is where the fill is positioned in relation to the stroke, and that neither the fill or stroke themselves are at fault. Any other thoughts on this? How can I get the fill directly centred in the stroke?
You should probably just use kCGTextFillStroke as the drawing mode and only draw once (with separate stroke and fill colors set).
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0); // any color you want (this is red)
CGContextSetRGBStrokeColor(context, 0.0, 1.0, 0.0, 1.0); // any color you want (this is green)
CGContextSetTextDrawingMode(context, kCGTextFillStroke);
[self.text drawInRect:rect withFont:self.font];
Alternatively you could just stroke afterwards. Strokes are usually drawn from the center which means that half of the width is inwards and half is outwards. That would mean that if you fill after you stroke some of the stroke is going to get covered up by the fill.
A possibility is that the overridden method translates the CTM using CGContextTranslateCTM or similar functions. The CTM is part of the state of a context and specifies a transform for all following draw calls.
You should try to save the context before the call to the overridden method and restore it afterwards:
CGContextSaveGState(c);
[super drawTextInRect: rect];
CGContextRestoreGState(c);
I have an UIimage with some text drawn on the image. I know the exact coordinates of the text rectangle on the image. When the image pan event is fired, I check if the pan is starting with a click on the rectangle in the image where there is text.
If (pan started from a click on the rectangle) then
I get the Pan translate coordinates and move the rectangle. So what I actually do is get the new coordinates and redraw the image with the rectangle in the new position. this gives the panning effect of the rectangle (for other reasons I cannot use a label but have to redraw).
This works perfectly, except that if the panning is done "too fast" there is an elasticity effect and the rectangle kind of is lagging behind. In theory I neednot redraw the whole image but rather only the intersection of the old and new rectangles. This I think will certainly make it more smoother.
Question: How to make it fast.
//Code where I redraw
UIGraphicsBeginImageContext(img.size);
[img drawInRect: CGRectMake(0,0, img.size.width, img.size.height)];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 0.2);
CGContextFillRect(context, CGRectMake(myRect.origin.x, myRect.origin.y, myRect.size.width, myRect.size.height));
UIImage *theImage=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CurrentImageView.Image = theImage;
I personally think that the most time consuming step here is
[img drawInRect: CGRectMake(0,0, img.size.width, img.size.height)];
It is illogical to be redrawing the whole image. I want to take a old image and just redraw a part of the image and assign it to the view controller. Any suggestions?
Thanks a lot in advance,
prasad.
I'm creating an app which uses UIImagePickerController to present a camera to the user with a custom overlay which includes one of two grids/patterns over the camera "view" itself.
The grids themselves are .png files in a UIImageView which is added to the overlay, they're quite complex so I would really like to steer away from drawing the grid in code, even though that would present I nice clean and simple answer to my question.
I would like to be able to offer the grids in a variety of colours. The obvious solution is create more .png images in different colours, but for each colour there would have to be four separate images (regular and retina for each of the grids) so that would quickly add up to a lot of assets.
The solution which, I think, would be ideal, would be for me to just create the grids in white/gray and then apply a tint to it to colour it appropriately.
Is that possible? Or do I need to seek an alternative solution?
With thanks to Ananth for pointing me to iPhone - How do you color an image?
I've added this method to my code as suggested in the question, with the modification in willc2's answer:
-(UIImage *)colorizeImage:(UIImage *)baseImage color:(UIColor *)theColor {
UIGraphicsBeginImageContext(baseImage.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect area = CGRectMake(0, 0, baseImage.size.width, baseImage.size.height);
CGContextScaleCTM(ctx, 1, -1);
CGContextTranslateCTM(ctx, 0, -area.size.height);
CGContextSaveGState(ctx);
CGContextClipToMask(ctx, area, baseImage.CGImage);
[theColor set];
CGContextFillRect(ctx, area);
CGContextRestoreGState(ctx);
CGContextSetBlendMode(ctx, kCGBlendModeMultiply);
CGContextDrawImage(ctx, area, baseImage.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
...and I'm getting exactly what I'm after.
I want to do some custom drawing with CoreGraphics. I need a linear gradient on my view, but the thing is that this view is a rounded rectangle so I want my gradient to be also rounded at angles. You can see what I want to achieve on the image below:
So is this possible to implement in CoreGraphics or some other programmatic and easy way?
Thank you.
I don't think there is an API for that, but you can get the same effect if you first draw a radial gradient, say, in an (N+1)x(N+1) size bitmap context, then convert the image from the context to a resizable image with left and right caps set to N.
Pseudocode:
UIGraphicsBeginImageContextWithOptions(CGSizeMake(N+1,N+1), NO, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
// <draw the gradient into 'context'>
UIImage* gradientBase = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImage* gradientImage = [gradientBase resizableImageWithCapInsets:UIEdgeInsetsMake(0,N,0,N)];
In case you want the image to scale vertically as well, you just have to set the caps to UIEdgeInsetsMake(N,N,N,N).
I just want to add more sample code for this technique, as some things weren't obvious for. Maybe it will be useful for somebody:
So, let's say, we have our custom view class and in it's drawRect: method we put this:
// Defining the rect in which to draw
CGRect drawRect=self.bounds;
Float32 gradientSize=drawRect.size.height; // The size of original radial gradient
CGPoint center=CGPointMake(0.5f*gradientSize,0.5f*gradientSize); // Center of gradient
// Creating the gradient
Float32 colors[4]={0.f,1.f,1.f,0.2f}; // From opaque white to transparent black
CGGradientRef gradient=CGGradientCreateWithColorComponents(CGColorSpaceCreateDeviceGray(), colors, nil, 2);
// Starting image and drawing gradient into it
UIGraphicsBeginImageContextWithOptions(CGSizeMake(gradientSize, gradientSize), NO, 1.f);
CGContextRef context=UIGraphicsGetCurrentContext();
CGContextDrawRadialGradient(context, gradient, center, 0.f, center, center.x, 0); // Drawing gradient
UIImage* gradientImage=UIGraphicsGetImageFromCurrentImageContext(); // Retrieving image from context
UIGraphicsEndImageContext(); // Ending process
gradientImage=[gradientImage resizableImageWithCapInsets:UIEdgeInsetsMake(0.f, center.x-1.f, 0.f, center.x-1.f)]; // Leaving 2 pixels wide area in center which will be tiled to fill whole area
// Drawing image into view frame
[gradientImage drawInRect:drawRect];
That's all. Also if you're not going to ever change the gradient while app is running, you would want to put everything except last line in awakeFromNib method and then in drawRect: just draw the gradientImage into view's frame. Also don't forget to retain the gradientImage in this case.