iOS, How to draw a rough line, for fun apps? - ios

I'm trying to draw a rough line, a normal straight line just looks odd in my app. I'm using a fun font etc and a straight line just doesn't work.
When I say rough, I mean I want to add some noise or texture to it.
I've tried adding an image as a texture but the options I've tried use a uniform tiled approach which looks too georometricly sound.
I need to either add a scatter effect to draw my texture image roughly in the shape of a line or some sort of random approach to add noise.
I know I could just draw a rough line in a imaging app and use that, but I'm not sure about colouring and size at this stage and I'd rather use something dynamic.
I've spend far too long on this issue and a lot if time googling and can't find anything I can use, so if you have a solution please provide or point me at some example code.
Thanks.
This is the best solution I've found, but it's too uniform...
#import "DrawTexturedLine.h"
#implementation DrawTexturedLine
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[self patternMake2:rect context:context];
}
void pattern2Callback (void *info, CGContextRef context) {
UIImage *image = [UIImage imageNamed:#"particle.png"];
CGImageRef imageRef = [image CGImage];
CGContextDrawImage(context, CGRectMake(0, 0, 50, 25), imageRef);
}
- (void)patternMake2:(CGRect)rect context:(CGContextRef)context
{
static const CGPatternCallbacks callbacks = { 0, &pattern2Callback, NULL };
CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
CGContextSetFillColorSpace(context, patternSpace);
CGColorSpaceRelease(patternSpace);
CGSize patternSize = CGSizeMake(25/2.0, 25);
CGPatternRef pattern = CGPatternCreate(NULL, self.bounds,
CGAffineTransformIdentity, patternSize.width, patternSize.height,
kCGPathFillStroke, true, &callbacks);
CGFloat alpha = 1;
CGContextSetFillPattern(context, pattern, &alpha);
CGPatternRelease(pattern);
CGContextFillRect(context, rect);
//CGContextRestoreGState(context);
}
#end

Not quite answering your question but you could draw the lines in a paint package and include those with your app and then use code like this to set the colour of the lines.
https://coffeeshopped.com/2010/09/iphone-how-to-dynamically-color-a-uiimage
If you were to use Sprite Kit it becomes much easier to change colors of images
[SKAction colorizeWithColor:[self randomColor]
colorBlendFactor:1.0
duration:0]];

I'm just returning to this issue and I've spent far too much time on this, looking at various tinting solutions. In the end I had to use a paint package to do most of the work. If I had been better with it I could have done the whole thing in a paint package.
I ended up drawing some lines with a black marker scanning them into gray scale then colorizing it.

Related

Set background - centered and not stretched

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)

How to render offscreen IOS

I am trying to make a metaball implementation in swift but have ran into this problem on the way. Basically I need to draw some alpha radial gradients offscreen and then check each pixel value to see wether it is above a certain alpha threshold if it is than the pixel becomes black other wise it is white.
The problem is that I cant figure out how to make an offscreen context that I can draw on and perform calculations on and then display it on the screen.
I have searched endlessly but I am very confused with the differences between UIcontexts and CGContext. In my current attempt I use a CGBitmapContext but to no avail. Any help would be greatly appreciated (preferably in swift, but anything goes).
You could draw to a bitmap graphics context as described here.
Here is how you can create an image context, draw to it using CG calls, and then get a UIImage:
// Create an N*N image
CGSize size = CGSizeMake(N, N);
UIGraphicsBeginImageContext(size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
// EG:
CGColorRef backColor = [UIColor lightGrayColor].CGColor;
CGContextSetFillColorWithColor(ctx, backColor);
CGContextFillRect(ctx, r1);
.... more drawing code
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
You can get a CGImageRef very easily:
CGImageRef cgImage = image.CGImage;
Finally, you can get the underlying bytes as explained here.

iOS: Adding an outline/stroke to an image context with a transparent background

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.

Drawing cumulatively to an image - really?

I'm drawing beziers and rather than memorize every bezier ever and re-draw it every frame, I'm occasionally taking a picture of the image with:
+ (UIImage *) imageWithView:(UIView *)view: (CGRect)theBounds
{
UIGraphicsBeginImageContextWithOptions(theBounds.size, NO, 0.0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
Then I draw the image at the beginning of every drawRect, add new paths as they come in, occasionally take another picture, and repeat.
Is there a better way? It's working but I feels 'stupid.'
Ahaaa layer context.
That's all you had to say.
http://developer.apple.com/library/ios/#documentation/GraphicsImaging/Reference/CGLayer/Reference/reference.html
BTW this is better, although I disagree with the phrase "non destructive." I wish I had found the below at the start of my project, but I never would have searched for "Non destructive." Although, who would ever search for "Cumulatively?" lol me no smartest
UIView: how to do non-destructive drawing?

Tinting UIImage to a different color, OR, generating UIImage from vector

I have a circle with a black outline, and a white fill that I need to programmatically make the white into another color (via a UIColor). I've tried a handful of other stackoverflow solutions but none of them seem to work correctly, either filling just the outside or an outline.
I have two ways I could do this but I am unsure of how I would get the right results:
Tint just the white color to whatever the UIColor should be,
or,
Make a UIImage from two circles, one being filled and one overlapping that with black.
If you decide to use two circles, one white and one black, then you may find this helpful. This method will tint a uiimage one for you but it addresses the problem of only tinting the opaque part, meaning it will only tint the circle if you provide a png with transparency around the circle. So instead of filling the entire 24x24 frame of the image it fills only the opaque parts. This isn't exactly your question but you'll probably come across this problem if you go with the second option you listed.
-(UIImage*)colorAnImage:(UIColor*)color :(UIImage*)image{
CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
UIGraphicsBeginImageContextWithOptions(rect.size, NO, image.scale);
CGContextRef c = UIGraphicsGetCurrentContext();
[image drawInRect:rect];
CGContextSetFillColorWithColor(c, [color CGColor]);
CGContextSetBlendMode(c, kCGBlendModeSourceAtop);
CGContextFillRect(c, rect);
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
Extend a UIView and just implement the drawRect method. For example, this will draw a green circle with a black outline.
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGContextRef gc = UIGraphicsGetCurrentContext();
[[UIColor greenColor] setFill];
CGContextFillEllipseInRect(gc, CGRectMake(0,0,24,24));
[[UIColor blackColor] set];
CGContextStrokeEllipseInRect(gc, CGRectMake(0,0,24,24));
}
For such simple shapes, just use CoreGraphics to draw a square and a circle -- adding the ability to set the fill color in your implementation.
If it's just black and white - then altering the white to another color is not so difficult when you know the color representations. Unfortunately, this is more complex to write and execute so… my recommendation is to just go straight to CoreGraphics for the simple task you outlined (bad pun, sorry).
here's a quick demo:
static void InsetRect(CGRect* const pRect, const CGFloat pAmount) {
const CGFloat halfAmount = pAmount * 0.5f;
*pRect = CGRectMake(pRect->origin.x + halfAmount, pRect->origin.y + halfAmount, pRect->size.width - pAmount, pRect->size.height - pAmount);
}
static void DrawBorderedCircleWithWidthInContext(const CGRect pRect, const CGFloat pWidth, CGContextRef pContext) {
CGContextSetLineWidth(pContext, pWidth);
CGContextSetShouldAntialias(pContext, true);
CGRect r = pRect;
/* draw circle's border */
CGContextSetRGBStrokeColor(pContext, 0.8f, 0.7f, 0, 1);
InsetRect(&r, pWidth);
CGContextStrokeEllipseInRect(pContext, r);
/* draw circle's fill */
CGContextSetRGBFillColor(pContext, 0, 0, 0.3f, 1);
InsetRect(&r, pWidth);
CGContextFillEllipseInRect(pContext, r);
}

Resources