MKOverlayView and changing its alpha - ios

I have a custom MKOverlay and MKOverlayView. When the MKOverlayView is created, I can set the alpha of the view:
-(void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
DatasetOverlay *datasetOverlay = (DatasetOverlay *)self.overlay;
UIImage *image = [UIImage imageWithData:datasetOverlay.imageData];
CGImageRef imageReference = image.CGImage;
MKMapRect theMapRect = [self.overlay boundingMapRect];
CGRect theRect = [self rectForMapRect:theMapRect];
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, -theRect.size.height);
CGContextSetAlpha(context, 1);
CGContextDrawImage(context, theRect, imageReference);
}
But I want to be able to change the alpha of the view after its draw.
How can I do that?
I am have not worked much with Core Graphics yet.

-(void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
DLog(#"Fired");
DatasetOverlay *datasetOverlay = (DatasetOverlay *)self.overlay;
UIImage *image = [UIImage imageWithData:datasetOverlay.imageData];
CGImageRef imageReference = image.CGImage;
MKMapRect theMapRect = [self.overlay boundingMapRect];
CGRect theRect = [self rectForMapRect:theMapRect];
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, -theRect.size.height);
// CGContextSetAlpha(context, 1);
CGContextDrawImage(context, theRect, imageReference);
}
K, thanks to #ttarules's comment, I did some testing and realized I needed to remove the CGContextSetAlpha() and just set the alpha with the MKOverlayView's alpha property. I can now change the alpha outside of initialization and give me what I need.

Related

Rotating UIImageView data -

Hi in my iOS application I want to rotate the UIImage data in 90 Degrees.
I used the below code for 180 degree rotation - and it works fine.
- (UIImage*)upsideDownBunny:(UIImage *)img {
CGSize imgSize = [img size];
UIGraphicsBeginImageContext(imgSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextRotateCTM(context, M_PI);
CGContextTranslateCTM(context, -imgSize.width, -imgSize.height);
[img drawInRect:CGRectMake(0, 0, imgSize.width, imgSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
But when I try to rotate in 90 degree it is not working - please correct me
- (UIImage *)upsideDownBunny:(UIImage *)img {
CGSize imgSize = [img size];
UIGraphicsBeginImageContext(imgSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextRotateCTM(context, M_PI_2);
CGContextTranslateCTM(context, -imgSize.width, -imgSize.height);
[img drawInRect:CGRectMake(0, 0, imgSize.width, imgSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Try this...
UIImage * LandscapeImage = [UIImage imageNamed: imgname];
UIImage * PortraitImage = [[UIImage alloc] initWithCGImage: LandscapeImage.CGImage
scale: 1.0
orientation: UIImageOrientationLeft];
hope this helps you!
Try this
- (UIImage *)upsideDownBunny:(UIImage *)image {
// Rotate in degrees
CGFloat degrees = M_PI_2;
// Calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
CGAffineTransform transform = CGAffineTransformMakeRotation(degrees);
rotatedViewBox.transform = transform;
CGSize rotatedSize = rotatedViewBox.frame.size;
// Create image context
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef context = UIGraphicsGetCurrentContext();
// Move the origin to the middle of the image.
CGContextTranslateCTM(context, rotatedSize.width * 0.5f, rotatedSize.height * 0.5f);
// Rotate the image context
CGContextRotateCTM(context, degrees);
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(-image.size.width * 0.5f, -image.size.height * 0.5f, image.size.width, image.size.height), [image CGImage]);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
The problem is your context is being rotated around (0,0) which is the top left corner and after 90 degrees rotate it will go out of bounds. So you need to move the origin of the context to middle.

Apply a transform in CGContextRef for drawInRect

In the code below I'm adding a small image to a large image. I need to be able to apply a transform to the small image. Right now something weird is going on, for example if I pass in a transform of CGAffineTransformMakeRotation(M_PI_2), the newImage is not rotated in place but rather drawn somewhere off screen. How can I fix this?
+ (UIImage*)addToImage:(UIImage *)baseImage newImage:(UIImage*)newImage atPoint:(CGPoint)point transform:(CGAffineTransform)transform {
UIGraphicsBeginImageContextWithOptions(baseImage.size, NO, 1);
CGContextRef context = UIGraphicsGetCurrentContext();
[baseImage drawInRect:CGRectMake(0, 0, baseImage.size.width, baseImage.size.height)];
CGRect newRect = CGRectMake(point.x,
point.y,
newImage.size.width,
newImage.size.height);
CGContextConcatCTM(context, transform);
[newImage drawInRect:newRect];
UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
Note that I only want to apply the transform to newImage, not baseImage.
Seems like you just forgot to translate the origin of the context before and after the rotation. Here, try this:
- (UIImage*)addToImage:(UIImage *)baseImage newImage:(UIImage*)newImage atPoint:(CGPoint)point transform:(CGAffineTransform)transform {
UIGraphicsBeginImageContextWithOptions(baseImage.size, NO, [[UIScreen mainScreen] scale]);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect baseRect = CGRectMake(0, 0, baseImage.size.width, baseImage.size.height);
[baseImage drawInRect:baseRect];
CGRect newRect = CGRectMake(point.x, point.y, newImage.size.width, newImage.size.height);
CGContextTranslateCTM(context, point.x, point.y);
CGContextConcatCTM(context, transform);
CGContextTranslateCTM(context, -point.x, -point.y);
[newImage drawInRect:newRect];
UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
EDIT:
If you want to rotate the image around its center, add the halves of the image's sides to the corresponding translation values:
float xTranslation = point.x+newRect.size.width/2;
float yTranslation = point.y+newRect.size.height/2;
CGContextTranslateCTM(context, xTranslation, yTranslation);
CGContextConcatCTM(context, transform);
CGContextTranslateCTM(context, -xTranslation, -yTranslation);

Gradient Filling a PNG with Quartz

How can I fill the non-transparent areas of a PNG UIImage with a linear gradient? I'd like to reuse a PNG shape for MKAnnotationViews, but change the gradient per annotation's properties.
To use an image as a mask for a gradient (i.e. to have a gradient in the shape of the non-transparent pixels of your image), you can:
create a simple view with a gradient (you can either create a simple UIView and use the addGradientLayerToView shown below to give it a gradient or you can create the gradient PNG in advance and add it to your bundle).
apply your PNG as a mask to that gradient view:
UIImage *mask = [UIImage imageNamed:#"mask.png"];
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = CGRectMake(0, 0, mask.size.width, mask.size.height);
maskLayer.contents = (id)[mask CGImage];
gradientViewToMask.layer.mask = maskLayer;
To apply a gradient to the transparent pixels, you can either:
Create a new image with a gradient:
- (UIImage *)imageWithGradient:(UIImage *)image
{
UIGraphicsBeginImageContextWithOptions(image.size, NO, 1.0);
CGContextRef context = UIGraphicsGetCurrentContext();
size_t locationCount = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 0.0, 0.8, 0.8, 1.0, // Start color
0.9, 0.9, 0.9, 1.0 }; // End color
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents (colorspace, components, locations, locationCount):
CGPoint startPoint = CGPointMake(0.0, 0.0);
CGPoint endPoint = CGPointMake(0.0, image.size.height);
CGContextDrawLinearGradient (context, gradient, startPoint, endPoint, 0);
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextDrawImage(context, CGRectMake(0.0, 0.0, image.size.width, image.size.height), [image CGImage]);
UIImage *gradientImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGGradientRelease(gradient);
CGColorSpaceRelease(colorspace);
return gradientImage;
}
You can also add a CAGradientLayer to a view and then add the UIImageView as a subview of that view.
- (void)addGradientLayerToView:(UIView *)view
{
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = #[(id)[[UIColor colorWithRed:0.0 green:0.8 blue:0.8 alpha:1.0] CGColor],
(id)[[UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:1.0] CGColor]];
[view.layer insertSublayer:gradient atIndex:0];
}
Note, you have to #import <QuartzCore/QuartzCore.h> as well as add the QuartzCore framework to your project.
I ended up hacking together some bits of Rob's code and an extension to UIImage I found at http://coffeeshopped.com/2010/09/iphone-how-to-dynamically-color-a-uiimage
+ (UIImage *)imageNamed:(NSString *)name withGradient:(CGGradientRef)gradient
{
// load the image
UIImage *img = [UIImage imageNamed:name];
// begin a new image context, to draw our colored image onto
UIGraphicsBeginImageContextWithOptions(img.size, NO, [[UIScreen mainScreen] scale]);
// get a reference to that context we created
CGContextRef context = UIGraphicsGetCurrentContext();
// 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 overlay, and the original image
CGContextSetBlendMode(context, kCGBlendModeOverlay);
CGRect rect = CGRectMake(0, 0, img.size.width, img.size.height);
// set a mask that matches the shape of the image, then draw (overlay) a colored rectangle
CGContextClipToMask(context, rect, img.CGImage);
CGContextAddRect(context, rect);
//gradient
CGPoint startPoint = CGPointMake(0.0, img.size.height);
CGPoint endPoint = CGPointMake(0.0, 0.0);
CGContextDrawLinearGradient (context, gradient, startPoint, endPoint, 0);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGGradientRelease(gradient);
//return the color-burned image
return coloredImg;
}

MKOverlayView to be rotated

I have an overlay of route to be placed over a map. I have to adjust its rotation so that it overlaps exactly with the underlying map view. How can I achieve this? I have found the angle to rotate. How can I rotate my overlay view? Far till now I have added the overlay but can't rotate using transforms. What I noticed is that when I change the angle, the image is not rotating, instead it slides along x axis(side ways).
Here is the code that I tried
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
NSString *imagePath = [[NSBundle mainBundle] pathForResource:#"routeImage" ofType:#"png"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:imagePath];
MKMapRect theMapRect = self.overlay.boundingMapRect;
CGRect theRect = [self rectForMapRect:theMapRect];
CGAffineTransform transform = CGAffineTransformMakeRotation((-35.88) / 180.0 * M_PI);
[self setTransform:transform];
CGContextSaveGState(context);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, -theRect.size.height);
CGContextDrawImage(context, theRect,image.CGImage);
CGContextRestoreGState(context);
}
This is what I get
I have a workaround in which I manually rotate the image using GIMP and place it. But I need it to be customized.
This is the image transformed using GIMP and when placed on map as overlay
and this is when I rotate Context using transform [note: while rotating the context the image is rotated but is not at the exact location See image. Also the image breaks on zooming]
This is what I did
//Hayl-Road-Final.png is the actual image without transformation using GIMP
UIImage *image = [[UIImage imageNamed:#"Hayl-Road-Final.png"] retain];
CGImageRef imageReference = image.CGImage;
MKMapRect theMapRect = [self.overlay boundingMapRect];
CGRect theRect = [self rectForMapRect:theMapRect];
// We need to flip and reposition the image here
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextTranslateCTM(ctx, 0.0, -theRect.size.height);
CGContextRotateCTM(ctx,-35.88);
//drawing the image to the context
CGContextDrawImage(ctx, theRect, imageReference);
Try adding this method:
- (UIImage *) rotate: (UIImage *) image angle:(double)
{
//double angle = 20;
CGSize s = {image.size.width, image.size.height};
UIGraphicsBeginImageContext(s);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, 0,image.size.height);
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextRotateCTM(ctx, 2*M_PI*angle/360);
CGContextDrawImage(ctx,CGRectMake(0,0,image.size.width, image.size.height),image.CGImage);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
From your code, you change order of two line. It will be ok:
CGContextScaleCTM(ctx, 1.0, -1.0);
CGContextRotateCTM(ctx,-35.88);
CGContextTranslateCTM(ctx, 0.0, -theRect.size.height);
CGContextDrawImage(ctx, theRect, imageReference);
It is correct with me, please try

Drawing into a loaded UIImage in iOS

I have a couple of questions.
I have a loaded UIImage and i would like to:
1st - draw another image onto my loaded UIImage
2nd - draw a line (with color and thickness) onto my loaded UIImage
I would greatly appreciate if you would come up with some basic stuff, i'm still a noob :)
There's another alternative and it comes using core-graphics.
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
UIImage *bottomImage = ...;
CGRect bottomImageRect = ...;
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0, -bottomImageRect.size.height);
CGContextDrawImage(context, bottomImageRect, bottomImage.CGImage);
CGContextRestoreGState(context);
CGContextSaveGState(context);
UIImage *topImage = ...;
CGRect topImageRect = ...;
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0, -topImageRect.size.height);
CGContextDrawImage(context, topImageRect, topImage.CGImage);
CGContextRestoreGState(context);
CGPoint origin = ...;
CGPoint end = ...;
CGContextMoveToPoint(context, origin.x, origin.y);
CGContextAddLineToPoint(context, end.x, end.y);
CGContextSetStrokeColorWithColor(context, [UIColor whatever].CGColor);
CGContextStrokePath(context);
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
EDIT:
Changed the code a little so that images are not inverted

Resources