I'm ok with iOS drawing. I've had no problem drawing circles, lines, etc onto a view. In my latest project I would like to restrict my drawing to an irregular area on my view. Basically I have a paper doll outline (jpg) of a person. I want to be able to draw within that outline but have drawing stop when I reach the border. I'm honestly not really sure what my approach can be to accomplish this. Do I have to do hit testing to see if I'm within this irregular region? I don't think that is realistic if I start with a JPG. Do I need to use a "special" color outside my region and test for that color under my brush? I'm worried that won't be accurate as I'm using a big fat fuzzy brush to draw.
Is it possible to restrict drawing within an irregular boundary?
Of course it's possible!
If you are drawing with CoreGraphics (Quartz), you could use a clipping path, or a bitmap mask.
If you are using CoreAnimation, then try a mask layer.
(It sounds like a bitmap mask is what you want, since you're talking about using an arbitrary JPEG image.)
Related
I know how to draw simple shapes - rectangles, ellipses and lines etc. using iOS Quartz 2D drawing.
Just now I'm trying to draw a relatively complex shape though, the tail of a musical quaver:
Can anybody suggest a good way to approach this problem?
Can you design the quaver in a graphics program like Inkscape, export as an SVG, and then render using SVGKit? From a development level, it would be much easier to maintain something that you can visually update, rather than trying to draw a shape with code.
What I have learned from my designers is, that you start with a simple form and then extend and change it in single, small steps. Sometime later you arrive at the complex form. So, like answered by #Duncan C building a path. Now I know that is quite tedious. One alternative not mentioned here is PaintCode, an app that produces Cocoa code from your drawing. It is called PaintCode and should do what you want. Btw I am not affiliated with the makers of PaintCode!
You could draw that as a filled UIBezierPath (which is a UIKit wrapper on a CGPath).
You'd open a path, draw a sequence of straight lines and cubic or quadratic bezier curves, then close the path. Then you'd draw it as a filled path.
Once you have the path created, you could draw it with a single call.
A couple of alternatives, as Duncan seems to have answered this.
One option would be to dynamically scale a high resolution image.
There is one caveat with this approach: you should not scale anything below 1/2 of the original size, otherwise the interpolation tends to glitch.
So you would need to store image at say 64x64, 128x128, 256x256 etc
You could pack all of these into a single 256x512, and this is what a lot of games do.
Another option is to render a quaver unicode character http://www.fileformat.info/info/unicode/char/266a/index.htm
I would like to draw an interface with knob, similar to "overdrive" (green) in this photo:
In iOS, such as vector graphics should I use? Quartz, OpenGL ES, or something else?
I'm sure can be done with OpenGL, but I think it's very complicated. So if you can I would avoid it using something more "simple."
It depends to a large extent how the rest of your GUI is rendered. However, unless you're already using OpenGL, Quartz or CoreAnimation are probably your best bet.
Looking at the screenshot, it seems you could probably achieve the effect with two image layers, a background (static) and a foreground (rotating).
The background image could have the scale (painted on the pedal) and shadow, then the black knob border and shiny metal middle. Then you can just draw the black tick mark indicator at the appropriate angle, either using Quartz or using a CGLayer and rotating it (especially if you wanted to have part of the button texture rotating with it).
It looks like the knob is smooth, so you don't need to worry about rotating the edges. And assuming the light source is fixed, the highlight on the top-left edge and the shine on the metal middle can be static too.
However, if you wanted to be more realistic, you could try having a third layer with just the shiny middle, and rotating this back and forth slightly to animate the knob middle as the pointer rotates. It doesn't need to go around all the way; maybe 10 degrees or so of variation should help sell the effect.
We can draw rectangle on the UIImage. And we can also add a sub-view with a backgroundcolor or border. I guess there is other methods to make it, too.
Did someone try to analyze them?
Which is the fastest way?
Thanks!
I would say, drawing rectangles using Quartz engine and UIImage is more CPU intensive that using UIView. If your scene is heavy and dynamic, Quartz is the best way of doing drawings because you can update your drawings.
Using UIView is not CPU intensive, but it'll have a heavy memory foot print if you want to draw a lot of rectangles.
So, if you want to draw just one or two rectangle for GUI design, I'd say go for using UIViews. But If you are trying to do some complex drawings involving more shapes go for Quartz.
As a learning project I'm attempting to re-create the procedurally generated hills from Tiny Wings using the HTML5 canvas. My goal is to generate textures like the hill in this picture:
Thus far, I have a seamless repeating texture that I've generated. It looks a little like this:
As you can see, this is part way there, however in Tiny Wings, the sinusoid patterns are often rotated on an angle. My question is this: Is it possible to take a seamlessly repeating pattern, rotate it, then clip it to a rectangle and still have a seamlessly repeating pattern?
I originally thought this was trivial, that any rotated repeating pattern clipped to it's original dimensions would still repeat. However my investigations lead me to believe this is not the case.
If what I'm describing isn't possible, how would I use a rotated version of the image I have generated as the pattern / fill for a shape? So far the only solution I can think of is to use a canvas clip region. Are there any other ways to accomplish this?
Related Questions:
html5 canvas shapes fill
HTML5 Canvas - Fill circle with image
To achieve what is in the image from tiny wings using the shape(texture) you supplied.
draw your texture-shape vertically to screen (it looks like it has been skew'ed not rotated)
apply a few semi-transparent hill shaped lines with a wide stroke width to create the phong shading effect.
clip the texture-shape with the shape of the hill.
apply a semi-transparent grunge texture to the whole canvas.
I have an application which requires that a solid black outline be drawn around a partly-transparent UIImage. Not around the frame of the image, but rather around all the opaque parts of the image itself. I.e., think of a transparent PNG with an opaque white "X" on it -- I need to outline the "X" in black.
To make matters trickier, AFTER the outline is drawn, the opacity of the original image will be adjusted, but the outline must remain opaque -- so the outline I generate has to include only the outline, and not the original image.
My current technique is this:
Create a new UIView which has the dimensions of the original image.
Duplicate the UIImage 4 times and add the duplicates as subviews of the UIView, with each UIImage offset diagonally from the original location by a couple pixels.
Turn that UIView into an image (via the typical UIGraphicsGetImageFromCurrentImageContext method).
Using CGImageMaskCreate and CGImageCreateWithMask, subtract the original image from this new image, so only the outline remains.
It works. Even with only the 4 offset images, the result looks quite good. However, it's horribly inefficient, and causes a good solid 4-second delay on an iPhone 4.
So what I need is a nice, speedy, efficient way to achieve the same thing, which is fully supported by iOS 4.0.
Any great ideas? :)
I would like to point out that whilst a few people have suggested edge detection, this is not an appropriate solution. Edge detection is for finding edges within image data where there is no obvious exact edge representation in the data.
For you, edges are more well defined, you are looking for the well defined outline. An edge in your case is any pixel which is on a fully transparent pixel and next to a pixel which is not fully transparent, simple as that! iterate through every pixel in the image and set them to black if they fulfil these conditions.
Alternatively, for an anti-aliased result, get a boolean representation of the image, and pass over it a small anti-aliased circle kernel. I know you said custom filters are not supported, but if you have direct access to image data this wouldn't be too difficult to implement by hand...
Cheers, hope this helps.
For the sake of contributing new ideas:
A variant on your current implementation would use CALayer's support for shadows, which it calculates from the actual pixel contents of the layer rather than merely its bounding rectangle, and for which it uses the GPU. You can try amping up the shadowOpacity to some massive value to try to eliminate the feathering; failing that you could to render to a suitable CGContext, take out the alpha layer only and manually process it to apply a threshold test on alpha values, pushing them either to fully opaque or fully transparent.
You can achieve that final processing step on the GPU even under ES 1 through a variety of ways. You'd use the alpha test to apply the actual threshold, you could then, say, prime the depth buffer to 1.0, disable colour output and the depth test, draw the version with the shadow at a depth of 0.5, draw the version without the shadow at a depth of 1.0 then enable colour output and depth tests and draw a solid black full-screen quad at a depth of 0.75. So it's like using the depth buffer to emulate stencil (since the GPU Apple used before the ES 2 capable device didn't support a stencil buffer).
That, of course, assumes that CALayer shadows appear outside of the compositor, which I haven't checked.
Alternatively, if you're willing to limit your support to ES 2 devices (everything 3GS+) then you could upload your image as a texture and do the entire process over on the GPU. But that would technically leave some iOS 4 capable devices unsupported so I assume isn't an option.
You just need to implement an edge detection algorithm, but instead of using brightness or color to determine where the edges are, use opacity. There are a number of different ways to go about that. For example, you can look at each pixel and its neighbors to identify areas where the opacity crosses whatever threshold you've set. Whenever you need to look at every pixel of an image in MacOS X or iOS, think Core Image. There's a helpful series of blog posts starting with this one that looks at implementing a custom Core Image filter -- I'd start there to build an edge detection filter.
instead using UIView, i suggest just push a context like following:
UIGraphicsBeginImageContextWithOptions(image.size,NO,0.0);
//draw your image 4 times and mask it whatever you like, you can just copy & paste
//current drawing code here.
....
outlinedimage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
this will be much faster than your UIView.