I'm trying to create a graphic in Sketch (a vector-based graphic design application). I export to PDF and this is what my original graphic looks like:
But when I set it as the image of an NSButton, it gets drawn like this:
Why does this occur? The right and bottom edges in particular are altered a lot. I'm not sure if this is a Cocoa drawing issue or an issue with my original graphic.
The problem is with (mis)alignment with the pixel grid and anti-aliasing. It looks like you've scaled the image so that the borders on the left, right, and bottom are roughly one pixel in thickness. However, the right and bottom borders are straddling the boundary between pixels. The result is that they contribute half their "darkness" to the pixel on one side of the boundary and the other half to the pixel on the other side of the boundary.
You should tweak either the proportions of the image or the size at which you're drawing it to avoid that particular alignment. It looks as though it's being rendered as roughly 10.5 pixels wide. You want it to be either 10 pixels or 11 pixels wide, so the right edge corresponds more closely to a pixel column.
Related
I have PNG images with rounded corners, inner shadows and a fill gradient, that I thought I could slice in Asset Catalogs horizontal and vertically. But no matter what I try, the gradient slice doesn't stretch or tile as I expected. With Xcode 9.1.
The gradient is not copied (although the inner shadow is), and in IB and the simulator, there are just two bars and no gradient.
What am I missing?
Here are the original image:
Here's how I sliced them:
And what they looked like in IB:
And here's what it looks like in IB (with the colors reversed in the simulator (with a red view and another similar image as background without any gradient) and device.
The center is the part that is getting tiled. You defined a 1x1 square that’s getting repeated on the interior of your image in order to make the image fill the space you defined, which isn’t your stated goal. What you can do is change your center to Stretches, and increase the center’s height and width to take up everything in your image that doesn’t include your rounded corners end caps.
I have a system that removes the colour white (give or take a few shades), from an image and replaces it with an alpha channel. (The image is taken from the users phone camera, and tries to remove selected colouring)
This leaves harsh edges most of the time, and I want to know if it is possible to add some type of anti-aliasing on top.
The system works by taking in the image, and searching through each pixel data. If the pixel is white (or close), it will replace it with an alpha colour.
So I guess my question is, how do I make the edges less harsh. Thanks.
Anti aliasing is not what you are looking for. This takes care of effects caused by the limited resolution of your image. However, your problem is not related to resolution, you would still have it with infinite resolution.
What you need to do is when you find a white pixel, increase the transparency of the pixel itself and the pixels around it.
You can just include the four pixels immediately above, below, left or right of your white pixel, or you an choose any other shape, e.g. all pixels which lie inside a circle of given radius around the white pixel.
Also you can choose a function which determines how transparency is distributed over that shape. You can make everything half-transparent or you can decrease the effect towards the edges of that shape (though I don't think that this will be necessary).
Thus each pixel will receive transparency from several pixels around them. The resulting transparency must be computed from all these contributions. Simply multiplying them probably won't do, because you will have a hard time ever reaching alpha=0. You may however, interpret (255-alpha) as a measure of transparency, add all contributing transparencies and then convert back into alpha. Something like max (0, 255 - (255-a1) + (255-a2) ...).
It will be difficult to do this in-place, i.e. with just ony copy of the image. You might need an intermediate "image", where each pixel is associated with all transparency contributions from the pixels around it.
I was creating an effects library for a PhotoBooth App. I have created effects like Black/White, Vintage, Sepia, Retro etc. etc.
I wanted to create a few effects now in which I wanted to have a Dark Border at the edges which kind of form a frame for the image .. something like this -> Example Effect
How can I do this using Pixel Bender and Flash ?
The effect you are describing is called vignetting. It is basically just darkening the pixels with some weight that changes depending on distance from the center of the image. In image editing it corresponds to overlaying the image with black color and applying a circular or elliptic mask to it, for example:
(source: johnhpanos.com)
You can do this by several methods depending on how you operate with image and its pixels. For example by multiplying the pixels by a weight coefficient that is smaller when closer to the center and bigger when farther away from it. The distance can be calculated from the difference between pixel coordinates.
I'm developing a custom control. One of the requirements is to draw lines. Although this works, I noticed that my 1 pixel wide lines do not really look like 1 pixel wide lines - I know, they're not really pixels but you know what I mean. They look more like two or three pixels wide. This becomes very apparent when I draw a dashed line with a 1 pixel dash and a 2 pixel gap. The 1 pixel dashes actually look like tiny lines in stead of dots.
I've read the Cocoa Drawing documentation and although Apple mentions the setLineWidth method, changing the line width to values smaller than 1.0 will only make the line look more vague and not thinner.
So, I suspect there's something else influencing the way my lines look.
Any ideas?
Bezier paths are drawn centered on their path, so if you draw a 1 pixel wide path along the X-coordinate, the line actually draws along Y-coordinates { -0.5, 0.5 } The solution is usually to offset the coordinate by 0.5 so that the line is not drawn in the sub pixel boundaries. You should be able to shift your bounding box by 0.5 to get sharper drawing behavior.
Francis McGrew already gave the right answer, but since I did a presentation on this once, I thought I'd add some pictures.
The problem here is that coordinates in Quartz lie at the intersections between pixels. This is fine when filling a rectangle, because every pixel that lies inside the coordinates gets filled. But lines are technically (mathematically!) invisible. To draw them, Quartz has to actually draw a rectangle with the given line width. This rectangle is centered over the coordinates:
So when you ask Quartz to stroke a rectangle with integral coordinates, it has the problem that it can only draw whole pixels. But here you see that we have half pixels. So what it does is it averages the color. For a 50% black (the line color) and 50% white (the background) line, it simply draws each pixel in grey:
This is where your washed-out drawings come from. The fix is now obvious: Don't draw between pixels, and you achieve that by moving your points by half a pixel, so your coordinate is centered over the desired pixel:
Now of course just offsetting may not be what you wanted. Because if you compare the filled variant to the stroked one, the stroke is one pixel larger towards the lower right. If you're e.g. clipping to the rectangle, this will cut off the lower right:
Since people usually expect the rectangle to stroke inside the specified rectangle, what you usually do is that you offset by 0.5 towards the center, so the lower right effectively moves up one pixel. Alternately, many drawing apps offset by 0.5 away from the center, to avoid overlap between the border and the fill (which can look odd when you're drawing with transparency).
Note that this only holds true for 1x screens. 2x Retina screens actually exhibit this problem differently, because each of the pixels below is actually drawn by 4 Retina pixels, which means they can actually draw the half-pixels. However, you still have the same problem if you want a sharp 0.5pt line. Also, since Apple may in the future introduce other Retina screens where e.g. every pixel is made up of 9 Retina pixels (3x), or whatever, you should really not rely on this. Instead, there are now API calls to convert rectangles to "backing aligned", which does this for you, no matter whether you're running 1x, 2x, or a fictitious 3x.
PS - Since I went to the hassle of writing this all up, I've put this up on my web site: http://orangejuiceliberationfront.com/are-your-rectangles-blurry-pale-and-have-rounded-corners/ where I'll update and revise this description and add more images.
The answer is (buried) in the Apple Docs:
"To avoid antialiasing when you draw a one-point-wide horizontal or vertical line, if the line is an odd number of pixels in width, you must offset the position by 0.5 points to either side of a whole-numbered position"
Hidden in Drawing and Printing Guide for iOS: iOS Drawing Concepts, though nothing that specific to be found in the current, standard (OS X) Cocoa Drawing Guide..
As for the effects of invoking setDefaultLineWidth: the docs also state that:
"A width of 0 is interpreted as the thinnest line that can be rendered on a particular device. The actual rendered line width may vary from the specified width by as much as 2 device pixels, depending on the position of the line with respect to the pixel grid and the current anti-aliasing settings. The width of the line may also be affected by scaling factors specified in the current transformation matrix of the active graphics context."
I found some info suggesting that this is caused by anti aliasing. Turning anti aliasing off temporarily is easy:
[[NSGraphicsContext currentContext] setShouldAntialias: NO];
This gives a crisp, 1 pixel line. After drawing just switch it on again.
I tried the solution suggested by Francis McGrew by offsetting the x coordinate with 0.5, however that did not make any difference to the appearance of my line.
EDIT:
To be more specific, I changed x and y coordinates individually and together with an offset of 0.5.
EDIT 2:
I must have done something wrong, as changing the coordinates with an offset of 0.5 actually does work. The end result is better than the one obtained by switching off the anti aliasing so I'll make Francis MsGrew's answer the accepted answer.
I have a bunch of game elements being drawn to the screen with OpenGL-ES and I'd like to be able to render a small rectangle in the bottom corner of the screen that shows, say, what's presently being displayed in the top left quarter of the screen.
In that way it's similar to a picture-in-picture from a tv, only the smaller picture would be showing part of the same thing the bigger picture is showing.
I'm comfortable with scaling in OpenGL-ES, but what I don't know how to do is get the proper rectangle of renderbuffer data and use that chunk as the data for an inset frame buffer for the next render pass. I imagine there's some trick along these lines to do this efficiently.
I've tried re-rendering the game elements at a smaller scale for this inset window and it just seems horribly inefficient when the data is already elsewhere and just needs to be scaled down a bit.
I'm not sure I'm asking this clearly or in the right terms, So any and all illumination is welcome and appreciated - especially examples. Thank you!
Have a look at glCopyTexImage2D. It lets you copy a portion of the framebuffer into a texture. So the order of operation would be:
Draw your scene normally
Bind your picture-in-picture texture
glCopyTexImage2D
Draw a quad with that texture in the bottom corner