[cairo] How to exactly overwrite anti-aliased shapes?
Bill Spitzak
spitzak at gmail.com
Fri Sep 16 17:51:54 UTC 2016
All that is stored in the pixel from the first drawing is what percentage
of the pixel was covered by the shape. It does not remember exactly what
parts of the pixel are covered.
When drawing the new shape, for any pixels that are not fully covered, it
cannot tell how much of the old shape was covered. It could be all of it
(if it was all under the new shape) or none of it (if it was all in the
area of the pixel not covered by the new shape). So Cairo does a reasonable
guess, which is that the old shape covers the pixel evenly (you could think
of it as an infinitely fine pattern that covers exactly that percentage of
the pixel). Say the old percentage of cover is X. The new shape covers Y
percent of the pixel, leaving (1-Y)*X of the old shape visible. And this is
the color it produces.
The only real solution is to draw a much higher resolution with coverage
rounded to exactly zero or one for each pixel. This aliasing will not be
visible to the user as the pixels are too small (or a number of them are
averaged together to make the real on-screen pixel). Contrary to what many
people think this is not possible yet, aliasing artifacts are still visible
on many graphics and will be unless resolution is raised huge magnitudes.
Therefore antialiasing is still applied to lines and characters at least.
On Fri, Sep 16, 2016 at 5:55 AM, Josh Sanford <xrjoshs at gmail.com> wrote:
> [I previously posted this on stackoverflow, but that appears not to be the
> best forum for the question.]
>
> While using Cairo 1.14.6 for display purposes, I found that overwriting
> the very same path with another color does not necessarily overwrite all
> pixels, and leaves undesirable artifacts behind.
>
> As evidence of my claim I offer this output from a short self-contained
> example, the source for which follows further below.
>
> [image: enter image description here] <http://i.stack.imgur.com/QBXjh.png>
>
> An explanation of the six parts of the image, from left to right:
>
> 1. Original shape stroked in blue.
> 2. Original shape overwritten in RGBA white.
> 3. Original shape overwritten in RGB white.
> 4. Original shape overwritten in RGBA white with CAIRO_OPERATOR_SOURCE
> mode.
> 5. Original shape overwritten in RGBA white with CAIRO_OPERATOR_SOURCE
> mode and CAIRO_ANTIALIAS_NONE.
> 6. Original shape overwritten in RGBA white with CAIRO_OPERATOR_SOURCE
> mode and CAIRO_ANTIALIAS_BEST.
>
> The image was generated from the following code:
>
> #include "cairo/cairo.h"
> #define M_PI 3.14159265358979323846
> void draw_shape(cairo_t* cr, int x, int y) {
> cairo_arc(cr, 50 + x, 50 + y, 48, -M_PI, -M_PI / 2);
> cairo_stroke(cr);
> cairo_move_to(cr, x + 2, y + 2);
> cairo_line_to(cr, x + 48, y + 48);
> cairo_stroke(cr);}
> int main(int argc, char** argv) {
> int x = 0;
> int y = 0;
> cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 300, 50);
> cairo_t* cr = cairo_create(surface);
>
> /* Draw a white background and a few shapes to overwrite */
> cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
> cairo_paint(cr);
> cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 1.0);
> draw_shape(cr, x, y); x += 50;
> draw_shape(cr, x, y); x += 50;
> draw_shape(cr, x, y); x += 50;
> draw_shape(cr, x, y); x += 50;
> draw_shape(cr, x, y); x += 50;
> draw_shape(cr, x, y); x += 50;
> x = 50;
>
> /* Leftmost shape is left unchanged for reference */
>
> /* Stroke in RGBA opaque white */
> cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
> draw_shape(cr, x, y); x += 50;
>
> /* Stroke in RGB white */
> cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
> draw_shape(cr, x + 0, y); x += 50;
>
> /* Stroke in opaque white without blending */
> cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
> cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
> draw_shape(cr, x, y); x += 50;
>
> /* Stroke in opaque white without blending, with no antialiasing */
> cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
> cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
> cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
> draw_shape(cr, x, y); x += 50;
>
> /* Stroke in opaque white without blending, with best antialiasing */
> cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
> cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
> cairo_set_antialias(cr, CAIRO_ANTIALIAS_BEST);
> draw_shape(cr, x, y); x += 50;
>
> /* Write the results to a file */
> cairo_surface_write_to_png(surface, "output.png");
>
> return 0;}
>
> It doesn't make intuitive sense to me that overwriting the very same shape
> would not overwrite all of its pixels, especially if I force it into
> non-blending CAIRO_OPERATOR_SOURCE mode. The results are the same on the
> framebuffer that constitutes my actual surface, so this is not an issue
> with the backend.
>
> Cairo is usually so good at what it does that I'm very surprised at this.
> Is there no way to overwrite an anti-aliased shape exactly in Cairo?
>
> Josh
>
> --
> cairo mailing list
> cairo at cairographics.org
> https://lists.cairographics.org/mailman/listinfo/cairo
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.cairographics.org/archives/cairo/attachments/20160916/cc892c8d/attachment-0001.html>
More information about the cairo
mailing list