I want to capture screen of my view from my iPhone app. I have white background view and on that I draw a lines on that view's layer using this method .
- (void)draw {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
if (self.fillColor) {
[self.fillColor setFill];
[self.path fill];
}
if (self.strokeColor) {
[self.strokeColor setStroke];
[self.path stroke];
}
CGContextRestoreGState(context);
}
- (void)drawRect:(CGRect)rect {
// Drawing code.
for (<Drawable> d in drawables) {
[d draw];
}
[delegate drawTemporary];
}
I have use delegate methods to draw lines on layer.
This is the project link from where I get help for this.
https://github.com/search?q=dudel&type=Everything&repo=&langOverride=&start_value=1
Now when I use the following context methods to save the drawing only I successfully save it without that white background.
drawImage.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
But When I use the following method of Bezier Pathe I cannot save the drawing without its white background,It saves the whole screen i.e. that drawing and its background.
UIGraphicsBeginImageContext(self.view.bounds.size);
[dudelView.layer renderInContext:UIGraphicsGetCurrentContext()];
//UIImage *finishedPic = UIGraphicsGetImageFromCurrentImageContext();
So can anybody help me how can I save the drawing only here in this app.
(You've tagged this as MapKit related, but make no mention of MapKit.)
Why don't you just split your drawing sequence into three chunks?
Draw your paths into an image context and get a UIImage, as you described.
Draw a background color.
Draw the UIImage.
Then you can use the UIImage for your "screenshot" as well.
I should also note that if the only thing you don't want in your captured UIImage is the background color, you are better off creating a UIImageView, setting its background color (-setBackgroundColor:), and setting its image to be your UIImage.
UIImageView internally has a number of optimizations that allow it to display graphics with much higher performance than you can get with a custom -drawRect: implementation.
Why don't you just save the drawables array? Those are all the drawings without the underlying image :)
Related
The programm sets the background as an image through:
[backgroundViewProxy setBackgroundColor:[UIColor colorWithPatternImage:[theme backgroundImage]]];
The drawRect of the correspoinding UIView is:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGSize phase = self.backgroundShift; //set this property to affect the positioning of the background image
CGContextSetPatternPhase(context, phase);
CGColorRef color = self.backgroundColor.CGColor;
CGContextSetFillColorWithColor(context, color);
CGContextFillRect(context, self.bounds);
CGContextRestoreGState(context);
}
I did not wrote the code on my own. I have to modify it.
I do understand what is going on here, but i cannot find a way to solve this problem:
I want the image to be centered on the screen (with and height) and it should not be streched or repeated.
At the moment, the image is repeated to fill the screen.
I have searched around the internet, but did not find a clear solution for centering(or positioning) the image in a similar context like this.
I would be glad if someone could help.
From apple's docs:
+ (UIColor *)colorWithPatternImage:(UIImage *)image
You can use pattern colors to set the fill or stroke color just as you would a solid color. During drawing, the image in the pattern color is tiled as necessary to cover the given area.
An alternative could be setting view.layer.contents to you image by casting it as type (id)
I followed #Rob answer and its drawn as I want...but when I saved this image....stroke not transparent anymore
Objective-C How to avoid drawing on same color image having stroke color of UIBezierPath
For save image I written this code
-(void)saveImage {
UIGraphicsBeginImageContextWithOptions(self.upperImageView.bounds.size, NO, 0);
if ([self.upperImageView respondsToSelector:#selector(drawViewHierarchyInRect:afterScreenUpdates:)])
[self.upperImageView drawViewHierarchyInRect:self.upperImageView.bounds afterScreenUpdates:YES]; // iOS7+
else
[self.upperImageView.layer renderInContext:UIGraphicsGetCurrentContext()]; // pre iOS7
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndPDFContext();
UIImageWriteToSavedPhotosAlbum(self.upperImageView.image, self,#selector(image:didFinishSavingWithError:contextInfo:), nil);
}
You are either setting the alpha of the image view with the paths to 1.0 somewhere, or you are using something that doesn't permit transparencies (e.g. UIGraphicsBeginImageContextWithOptions with YES for the opaque parameter, or staging the image in a format that doesn't preserve alpha, such as JPEG).
A few additional thoughts:
I notice that you're only drawing upperImageView. If you want the composite image, you need to draw both. Or are you only trying to save one of the image views?
(For those unfamiliar with that other question, the entire point was how to draw multiple paths over an image, and have the full set of those paths with the same reduced alpha, rather than having the intersection of paths lead to some additive behavior. This was accomplished by having two separate image views, one for the underlying image, and one for the drawn paths. The key to the answer to that question was that one should draw the paths at 100% alpha, but to add that as a layer to a view that, itself, has a reduced alpha.)
What is the alpha of the image view upon which you are drawing.
NB: In the answer to that other question, when saving a temporary copy of the combined paths. we had to temporarily set the alpha to 1.0. But when saving the final result here, we want to keep the "path" image view's alpha at its reduced value.
Unrelated, but you faithfully transcribed a typo (since fixed) in my original example where I accidentally called UIGraphicsEndPDFContext rather than UIGraphicsEndImageContext. You should use the latter.
So, considering two image views, one with the photograph and one with the drawn path, called imageImageView (with alpha of 1.0) and pathsImageView (with alpha of 0.5), respectively, I can save the snapshot like so:
- (void)saveSnapshot {
CGRect rect = self.pathsImageView.bounds;
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
if ([self.pathsImageView respondsToSelector:#selector(drawViewHierarchyInRect:afterScreenUpdates:)]) {
[self.imageImageView drawViewHierarchyInRect:rect afterScreenUpdates:YES]; // iOS7+
[self.pathsImageView drawViewHierarchyInRect:rect afterScreenUpdates:YES];
} else {
[self.imageImageView.layer renderInContext:UIGraphicsGetCurrentContext()]; // pre iOS7
[self.pathsImageView.layer renderInContext:UIGraphicsGetCurrentContext()];
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image:didFinishSavingWithError:contextInfo:), nil);
}
When I did that, the resulting composite image was in my photo album:
I have a UIView whose layer has two sublayers, each of which has a 1.5 pixel border around the outside. I am trying to create a UIImage from this view with the following code
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0f);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO];
UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
The code does return a UIImage, but the image is clipped – that is, the image doesn't include the all of the borders on the sublayers. I've tried tweaking the sizes/bounds but to no effect. Any suggestions of what else I might try?
Thanks!
What happens if you send the parent layer a
drawInContext: message instead of telling the view to draw itself?
The images that goes through here are PNGs of different shapes with a transparent background. In addition to merging them (which works fine), I'd like to give the new image a couple of pixels thick outline. But I can't seem to manage that.
(So just to clarify, I'm after an outline around the actual shapes in the context, not a rectangle around the entire image.)
+ (UIImage *)mergeBackgroundImage:(UIImage *)backgroundImage withOverlayingImage:(UIImage *)overlayImage{
UIGraphicsBeginImageContextWithOptions(backgroundImage.size, NO, backgroundImage.scale);
[backgroundImage drawInRect:CGRectMake(0, 0, backgroundImage.size.width, backgroundImage.size.height)];
[overlayImage drawInRect:CGRectMake(backgroundImage.size.width - overlayImage.size.width, backgroundImage.size.height - overlayImage.size.height, overlayImage.size.width, overlayImage.size.height)];
//Add stroke.
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
Thanks for your time!
Markus
If you make a CALayer who's backing is set to a CGImage of your image, you can then use it as a masking layer for your layer that requires an outline1. And once you've done that, you can render your layer into another context, and then get another UIImage from that.
// edit: Something like what's describe in this answer.
I'm trying to make a transition between two ViewControllers. My Transition class has a property for the destination view controller. When I try to get a screenshot of the destination's view, I use this method:
+ (UIImage *)renderImageFromView:(UIView *)view withRect:(CGRect)frame {
// Create a new context the size of the frame
UIGraphicsBeginImageContextWithOptions(frame.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
// Render the view
[view.layer renderInContext:context];
// Get the image from the context
UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
// Cleanup the context you created
UIGraphicsEndImageContext();
return renderedImage;
}
So when I want the image, I'll do this:
UIImage *image = [UIImage renderImageFromView:destinationController.view withRect:destinationController.view.bounds];
I tried it on a blank UIViewController with an orange background color and a label. I get the orange background color, but I do not get the label that was created in IB. Is there a way to get a proper screenshot of the new view I plan on showing? Thanks!
You need to make sure the view's layer is drawn to first. Calling renderInContext on a CALayer will only recursively call additional child CALayers. You need your child UIViews to draw themselves, not just using the CALayer.
Try calling
[view drawrect:frame];
instead of
[view.layer renderInContext:context];
As long as you have an open graphics context(which you do at that point), drawrect should draw directly into that.