diff options
author | Søren Sandmann <ssp@redhat.com> | 2013-01-09 17:07:06 -0500 |
---|---|---|
committer | Søren Sandmann <ssp@redhat.com> | 2013-01-09 17:07:06 -0500 |
commit | 01c3c09be80d6fcd822ae60b575cd0ff5440a46f (patch) | |
tree | 88e2bb21ab96371f863d9578db2d516811ffd886 | |
parent | 1bc7a8562261aad12957abe838e3c1ad4ae84b47 (diff) |
asdf
-rw-r--r-- | blend.txt | 35 | ||||
-rw-r--r-- | pics.c | 279 |
2 files changed, 268 insertions, 46 deletions
@@ -52,20 +52,31 @@ behavior in the three regions: source, destination and both (the 'destination' or 'blank'. The 'both' region can be either 'blank', 'source', or 'destination'. -Here are all of the Porter/Duff operators: - - [table.png] - The formula for the operators is a linear combination of the contents of the four regions, where the weights are the areas of each region: A_src * { C_s, 0 } + A_dest * { C_d, 0 } + A_both * { C_s, C_d, 0 } -It is important to understand that despite being referred to as "alpha -blending", and despite alpha often being used as a form of -translucency, conceptually Porter/Duff is *not* a way to blend the -source and destination shapes. It is a way to overlay, combine and cut -them as if they were pieces of cardboard. +The areas are given by these formulas: + + A_src = as * (1 - ad) + A_dst = ad * (1 - as) + A_both = as * ad + +The resulting alpha channel is computed in a similar way. There is +full coverage in all regions that are not blank: + + A_src * { 1, 0 } + A_dest * ( 1, 0 } + A_both * { 1, 1, 0 } + +It is important to understand that despite being referred to as alpha +"blending", and despite alpha often being used to model opacity, +conceptually Porter/Duff is *not* a way to blend the source and +destination shapes. It is a way to overlay, combine and cut them as if +they were pieces of cardboard. + +Here are all of the operators: + + [table.png] Blending @@ -73,7 +84,7 @@ Blending Photoshop and the Gimp have the concept of layers which are images stacked on top of each other. In Porter/Duff, stacking things on top of each other is done with the "Over" operator, which is also what -Photoshop/Gimp use by default to composite layers. It looks like this: +Photoshop/Gimp use by default to composite layers: <over> @@ -82,10 +93,10 @@ the other. Neither shape is tailored in any way, and in places where both are present, only the top layer is visible. A layer in these programs also has an associated Blend Mode. The -default blend mode is 'Normal' which corresponds to the regular OVER +default blend mode is 'Normal' which corresponds to the regular Over operator from Porter/Duff. When a blend mode other than Normal is chosen, the behavior in the 'both' region of the Porter/Duff pixel is -modified to be something other than 'source'. For example the +modified to be something other than simply 'source'. For example the 'Color Dodge' blend mode computes a blend of source and destination according to this formula: @@ -3,8 +3,8 @@ #define CHECK_SIZE 16 -#define SOURCE_COLOR 0.8, 0.5, 0.2 -#define DEST_COLOR 0.2, 0.2, 0.4 +#define SOURCE_COLOR 0.8, 0.3, 0.2 +#define DEST_COLOR 0.2, 0.4, 0.6 static cairo_t * get_cairo (int width, int height) @@ -24,7 +24,7 @@ get_cairo (int width, int height) if (light) cairo_set_source_rgb (cr, 0.95, 0.95, 0.95); else - cairo_set_source_rgb (cr, 0.9, 0.9, 0.9); + cairo_set_source_rgb (cr, 0.92, 0.92, 0.92); cairo_rectangle (cr, i, j, CHECK_SIZE, CHECK_SIZE); cairo_fill (cr); @@ -50,7 +50,7 @@ finish (cairo_t *cr, const char *filename) } static void -draw_ampersand (cairo_t *cr) +ampersand_path (cairo_t *cr) { cairo_rel_move_to (cr, 5, 70.0); cairo_select_font_face (cr, "Sans", @@ -58,17 +58,29 @@ draw_ampersand (cairo_t *cr) CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cr, 80); cairo_text_path (cr, "&"); + +} + +static void +draw_ampersand (cairo_t *cr) +{ + ampersand_path (cr); cairo_set_source_rgb (cr, DEST_COLOR); cairo_fill (cr); } static void -draw_polygon (cairo_t *cr) +polygon_path (cairo_t *cr) { cairo_rel_move_to (cr, 10, 10); cairo_rel_line_to (cr, 65, 35); cairo_rel_line_to (cr, -38, 35); - +} + +static void +draw_polygon (cairo_t *cr) +{ + polygon_path (cr); cairo_set_source_rgb (cr, SOURCE_COLOR); cairo_fill (cr); } @@ -95,26 +107,11 @@ create_polygon (void) finish (cr, "polygon.png"); } -static struct { +typedef struct +{ char name[16]; cairo_operator_t op; -} ops[] = - { - "Source", CAIRO_OPERATOR_SOURCE, - "Over", CAIRO_OPERATOR_OVER, - "Atop", CAIRO_OPERATOR_ATOP, - "In", CAIRO_OPERATOR_IN, - "Out", CAIRO_OPERATOR_OUT, - - "Dest", CAIRO_OPERATOR_DEST, - "Dest Over", CAIRO_OPERATOR_DEST_OVER, - "Dest Atop", CAIRO_OPERATOR_DEST_ATOP, - "Dest In", CAIRO_OPERATOR_DEST_IN, - "Dest Out", CAIRO_OPERATOR_DEST_OUT, - - "Clear", CAIRO_OPERATOR_CLEAR, - "Xor", CAIRO_OPERATOR_XOR, - }; +} op_info_t; static void draw_source (cairo_t *cr) @@ -143,7 +140,7 @@ centered_text (cairo_t *cr, double x, double y, const char *text) cairo_text_path (cr, text); cairo_path_extents (cr, &x1, &y1, &x2, &y2); cairo_new_path (cr); - printf ("in x %f %f %s\n", x, x2 - x1, text); + /* printf ("in x %f %f %s\n", x, x2 - x1, text); */ cairo_move_to (cr, x - (x2 - x1) / 2.0, y); cairo_show_text (cr, text); cairo_restore (cr); @@ -162,7 +159,7 @@ draw_cell (cairo_t *cr, { cairo_save (cr); - printf ("move to %f %f for %s\n", x, y, name); + /* printf ("move to %f %f for %s\n", x, y, name); */ cairo_rectangle (cr, x - 10, y, CELL_WIDTH + 20, CELL_HEIGHT); cairo_clip (cr); @@ -194,28 +191,84 @@ draw_cell (cairo_t *cr, cairo_restore (cr); } +#define COLS 4 + static void -create_porter_duff_table (void) +draw_table (cairo_t *cr, const op_info_t *ops, int n_ops, int n_columns) { - cairo_t *cr = get_cairo (CELL_WIDTH * 5 + XPAD, - (CELL_HEIGHT) * 3 + 2 * YPAD); int i; - + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); - for (i = 0; i < 12; ++i) + for (i = 0; i < n_ops; ++i) { - double x = CELL_WIDTH * (i % 5) + XPAD; - double y = CELL_HEIGHT * (i / 5) + YPAD; + double x = CELL_WIDTH * (i % n_columns) + XPAD; + double y = CELL_HEIGHT * (i / n_columns) + YPAD; draw_cell (cr, x, y, ops[i].op, ops[i].name); } - +} + +static void +create_porter_duff_table (void) +{ + static const op_info_t ops[] = + { + "Source", CAIRO_OPERATOR_SOURCE, + "Atop", CAIRO_OPERATOR_ATOP, + "Over", CAIRO_OPERATOR_OVER, + "In", CAIRO_OPERATOR_IN, + "Out", CAIRO_OPERATOR_OUT, + + "Dest", CAIRO_OPERATOR_DEST, + "Dest Atop", CAIRO_OPERATOR_DEST_ATOP, + "Dest Over", CAIRO_OPERATOR_DEST_OVER, + "Dest In", CAIRO_OPERATOR_DEST_IN, + "Dest Out", CAIRO_OPERATOR_DEST_OUT, + + "Clear", CAIRO_OPERATOR_CLEAR, + "Xor", CAIRO_OPERATOR_XOR, + }; + + cairo_t *cr = get_cairo (CELL_WIDTH * 5 + XPAD, + (CELL_HEIGHT) * 3 + 2 * YPAD); + + draw_table (cr, ops, sizeof (ops) / sizeof (ops[0]), 5); + finish (cr, "table.png"); } static void +create_color_dodge_table (void) +{ + static const op_info_t ops[] = + { + "Clear", CAIRO_OPERATOR_CLEAR, + "Out", CAIRO_OPERATOR_OUT, + "Dest Out", CAIRO_OPERATOR_DEST_OUT, + "Xor", CAIRO_OPERATOR_XOR, + + "In", CAIRO_OPERATOR_IN, + "Source", CAIRO_OPERATOR_SOURCE, + "Atop", CAIRO_OPERATOR_ATOP, + "Over", CAIRO_OPERATOR_OVER, + + "Dest In", CAIRO_OPERATOR_DEST_IN, + "Dest Atop", CAIRO_OPERATOR_DEST_ATOP, + "Dest", CAIRO_OPERATOR_DEST, + "Dest Over", CAIRO_OPERATOR_DEST_OVER, + }; + + cairo_t *cr = get_cairo (CELL_WIDTH * 4 + XPAD, + (CELL_HEIGHT) * 4 + 2 * YPAD); + + draw_table (cr, ops, sizeof (ops) / sizeof (ops[0]), 4); + + finish (cr, "colordodge-table.png"); +} + +static void create_op (cairo_operator_t op, const char *name, const char *filename) { cairo_t *cr = get_cairo (CELL_WIDTH + 20, CELL_HEIGHT); @@ -291,11 +344,164 @@ dest_atop_diagram (const char *filename) centered_text (cr, 145, 90, "Dest"); centered_text (cr, 90, 147, "Neither"); + cairo_new_path (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + draw_pixel_box (cr); + + finish (cr, filename); +} + +static void +color_dodge_diagram (const char *filename) +{ + cairo_t *cr = get_cairo (180, 180); + + cairo_move_to (cr, 1, 1); + cairo_line_to (cr, 90, 90); + cairo_line_to (cr, 179, 1); + cairo_set_source_rgb (cr, DEST_COLOR); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, SOURCE_COLOR); + cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_DODGE); + cairo_fill (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + + cairo_set_source_rgb (cr, 1, 1, 1); + centered_text (cr, 90, 45, "Both"); + + cairo_move_to (cr, 1, 1); + cairo_line_to (cr, 90, 90); + cairo_line_to (cr, 1, 179); + cairo_set_source_rgb (cr, SOURCE_COLOR); + cairo_fill (cr); + + cairo_move_to (cr, 179, 1); + cairo_line_to (cr, 90, 90); + cairo_line_to (cr, 179, 179); + cairo_set_source_rgb (cr, DEST_COLOR); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 1, 1, 1); + centered_text (cr, 35, 90, "Source"); + + centered_text (cr, 145, 90, "Dest"); + + cairo_set_source_rgb (cr, 0, 0, 0); + centered_text (cr, 90, 147, "Neither"); + draw_pixel_box (cr); finish (cr, filename); } +static void +color_dodge_atopish (void) +{ + cairo_t *cr = get_cairo (CELL_WIDTH + 20, CELL_HEIGHT); + cairo_pattern_t *pattern; + + cairo_push_group (cr); + + cairo_move_to (cr, 0, 0); + + cairo_push_group (cr); + + cairo_set_source_rgb (cr, SOURCE_COLOR); + cairo_paint (cr); + + cairo_push_group (cr); + cairo_set_source_rgb (cr, DEST_COLOR); + cairo_paint (cr); + cairo_set_source_rgb (cr, SOURCE_COLOR); + cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_DODGE); + cairo_paint (cr); + cairo_pop_group_to_source (cr); + + cairo_move_to (cr, 30, 10); + ampersand_path (cr); + cairo_fill (cr); + + cairo_pop_group_to_source (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_paint (cr); + + cairo_pop_group_to_source (cr); + + cairo_move_to (cr, 30, 10); + polygon_path (cr); + + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + centered_text (cr, + 30 + CELL_WIDTH / 2.0 - 20.0, + 10 + CELL_HEIGHT - 30, "asdfasdf"); + + finish (cr, "colordodge-atopish.png"); +} + +static void +color_dodge_blend_only (void) +{ + cairo_t *cr = get_cairo (CELL_WIDTH + 20, CELL_HEIGHT); + cairo_pattern_t *pattern; + + cairo_push_group (cr); + cairo_push_group (cr); + cairo_set_source_rgb (cr, DEST_COLOR); + cairo_paint (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_DODGE); + cairo_set_source_rgb (cr, SOURCE_COLOR); + cairo_paint (cr); + cairo_pop_group_to_source (cr); + + cairo_move_to (cr, 30, 10); + ampersand_path (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_fill (cr); + + cairo_pop_group_to_source (cr); + + cairo_move_to (cr, 30, 10); + polygon_path (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_fill (cr); + + finish (cr, "colordodge-blendonly.png"); +} + +static void +dest_color_dodge (void) +{ + cairo_t *cr = get_cairo (CELL_WIDTH + 20, CELL_HEIGHT); + cairo_pattern_t *pattern; + + cairo_move_to (cr, 30, 10); + draw_dest (cr); + + cairo_push_group (cr); + cairo_push_group (cr); + cairo_set_source_rgb (cr, DEST_COLOR); + cairo_paint (cr); + cairo_set_source_rgb (cr, SOURCE_COLOR); + cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_DODGE); + cairo_paint (cr); + cairo_pop_group_to_source (cr); + cairo_move_to (cr, 30, 10); + ampersand_path (cr); + cairo_fill (cr); + cairo_pop_group_to_source (cr); + cairo_move_to (cr, 30, 10); + polygon_path (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_fill (cr); + + finish (cr, "asdf.png"); +} + int main (int argc, char *argv) { @@ -307,4 +513,9 @@ main (int argc, char *argv) create_porter_duff_table (); general_pixel_diagram ("diagram.png"); dest_atop_diagram ("destatop-diagram.png"); + color_dodge_diagram ("colordodge-diagram.png"); + color_dodge_atopish (); + dest_color_dodge (); + color_dodge_blend_only (); + create_color_dodge_table (); } |