From 741f8b92c9980065532cfd866b87d0f494c1a38f Mon Sep 17 00:00:00 2001 From: Doug Felt Date: Fri, 7 Oct 2016 14:17:09 -0700 Subject: [PATCH 1/2] Update waveflag.c to upstream version. Also updates LDFLAGS to match upstream. --- Makefile | 2 +- waveflag.c | 692 +++++++++++++++++++++++++++++------------------------ 2 files changed, 382 insertions(+), 312 deletions(-) diff --git a/Makefile b/Makefile index 3d1e3529c..1f0a66507 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ EMOJI = NotoColorEmoji font: $(EMOJI).ttf CFLAGS = -std=c99 -Wall -Wextra `pkg-config --cflags --libs cairo` -LDFLAGS = `pkg-config --libs cairo` +LDFLAGS = -lm `pkg-config --libs cairo` PNGQUANTDIR := third_party/pngquant PNGQUANT := $(PNGQUANTDIR)/pngquant PNGQUANTFLAGS = --speed 1 --skip-if-larger --force diff --git a/waveflag.c b/waveflag.c index ce997d8b5..8e0cb07b3 100644 --- a/waveflag.c +++ b/waveflag.c @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Google contributors: Behdad Esfahbod, Roozbeh Pournader + * Google contributors: Behdad Esfahbod */ #include @@ -26,352 +26,422 @@ #define SCALE 8 #define SIZE 128 -#define MARGIN (debug ? 24 : 0) +#define MARGIN (debug ? 4 : 0) static unsigned int debug; -static cairo_path_t *wave_path_create(void) { - cairo_surface_t *surface = cairo_image_surface_create( - CAIRO_FORMAT_ARGB32, 0, 0); - cairo_t *cr = cairo_create(surface); - cairo_path_t *path; - - cairo_scale(cr, SIZE/128.*SCALE, SIZE/128.*SCALE); - - cairo_move_to(cr, 127.15, 81.52); - cairo_rel_line_to(cr, -20.51, -66.94); - cairo_rel_curve_to(cr, -0.61, -2, -2.22, -3.53, -4.25, -4.03); - cairo_rel_curve_to(cr, -0.48, -0.12, -0.96, -0.18, -1.44, -0.18); - cairo_rel_curve_to(cr, -1.56, 0, -3.07, 0.61, -4.2, 1.74); - cairo_rel_curve_to(cr, -9.56, 9.56, -17.94, 11.38, -30.07, 11.38); - cairo_rel_curve_to(cr, -3.68, 0, -7.72, -0.18, -11.99, -0.38); - cairo_rel_curve_to(cr, -3.37, -0.15, -6.85, -0.31, -10.62, -0.4); - cairo_rel_curve_to(cr, -0.66, -0.02, -1.31, -0.02, -1.95, -0.02); - cairo_rel_curve_to(cr, -30.67, 0, -40.49, 18.56, -40.89, 19.35); - cairo_rel_curve_to(cr, -0.52, 1.01, -0.73, 2.16, -0.62, 3.29); - cairo_rel_line_to(cr, 6.72, 66.95); - cairo_rel_curve_to(cr, 0.22, 2.22, 1.67, 4.13, 3.75, 4.95); - cairo_rel_curve_to(cr, 0.7, 0.27, 1.43, 0.4, 2.16, 0.4); - cairo_rel_curve_to(cr, 1.43, 0, 2.84, -0.52, 3.95, -1.5); - cairo_rel_curve_to(cr, 0.1, -0.09, 12.42, -10.63, 32.13, -10.63); - cairo_rel_curve_to(cr, 2.52, 0, 5.09, 0.17, 7.64, 0.51); - cairo_rel_curve_to(cr, 9.27, 1.23, 16.03, 1.78, 21.95, 1.78); - cairo_rel_curve_to(cr, 18.93, 0, 32.93, -6.1, 46.82, -20.38); - cairo_curve_to(cr, 127.24, 85.85, 127.79, 83.59, 127.15, 81.52); - cairo_close_path(cr); - - cairo_identity_matrix(cr); - path = cairo_copy_path(cr); - cairo_destroy(cr); - cairo_surface_destroy(surface); - - return path; -} - -static struct { double x, y; } mesh_points[] = { - { -1, 43}, - { 30, -3}, - { 77, 47}, - {104, 1}, - {130, 84}, - {100, 138}, - { 45, 80}, - { 7, 127}, +#define std_aspect (5./3.) +#define top 21 +#define bot 128-top +#define B 27 +static struct { double x, y; } mesh_points[] = +{ + { 1, top}, + { 43, top-B}, + { 85, top+B}, + {127, top}, + {127, bot}, + { 85, bot+B}, + { 43, bot-B}, + { 1, bot}, }; -#define M(i) mesh_points[i].x, mesh_points[i].y +#define M(i) \ + x_aspect (mesh_points[i].x, aspect), \ + y_aspect (mesh_points[i].y, aspect) -static cairo_pattern_t *wave_mesh_create(void) { - cairo_pattern_t *pattern = cairo_pattern_create_mesh(); - cairo_matrix_t scale_matrix = {128./SIZE/SCALE, 0, 0, 128./SIZE/SCALE, 0, 0}; - cairo_pattern_set_matrix(pattern, &scale_matrix); - cairo_mesh_pattern_begin_patch(pattern); - - cairo_mesh_pattern_line_to(pattern, M(0)); - cairo_mesh_pattern_curve_to(pattern, M(1), M(2), M(3)); - cairo_mesh_pattern_line_to(pattern, M(4)); - cairo_mesh_pattern_curve_to(pattern, M(5), M(6), M(7)); - - cairo_mesh_pattern_set_corner_color_rgb(pattern, 0, 0, 0, .5); - cairo_mesh_pattern_set_corner_color_rgb(pattern, 1, 1, 0, .5); - cairo_mesh_pattern_set_corner_color_rgb(pattern, 2, 1, 1, .5); - cairo_mesh_pattern_set_corner_color_rgb(pattern, 3, 0, 1, .5); - - cairo_mesh_pattern_end_patch(pattern); - - return pattern; +static inline double x_aspect (double v, double aspect) +{ + return aspect >= 1. ? v : (v - 64) * aspect + 64; +} +static inline double y_aspect (double v, double aspect) +{ + return aspect <= 1. ? v : (v - 64) / aspect + 64; } -static cairo_surface_t *scale_flag(cairo_surface_t *flag) { - unsigned int w = cairo_image_surface_get_width(flag); - unsigned int h = cairo_image_surface_get_height(flag); - cairo_surface_t *scaled = cairo_image_surface_create( - CAIRO_FORMAT_ARGB32, 256, 256); - cairo_t *cr = cairo_create(scaled); +static cairo_path_t * +wave_path_create (double aspect) +{ + cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0,0); + cairo_t *cr = cairo_create (surface); + cairo_path_t *path; - cairo_scale(cr, 256./w, 256./h); + cairo_scale (cr, SIZE/128.*SCALE, SIZE/128.*SCALE); - cairo_set_source_surface(cr, flag, 0, 0); - cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BEST); - cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_PAD); - cairo_paint(cr); + cairo_line_to(cr, M(0)); + cairo_curve_to(cr, M(1), M(2), M(3)); + cairo_line_to(cr, M(4)); + cairo_curve_to(cr, M(5), M(6), M(7)); + cairo_close_path (cr); - cairo_destroy(cr); - return scaled; + cairo_identity_matrix (cr); + path = cairo_copy_path (cr); + cairo_destroy (cr); + cairo_surface_destroy (surface); + + return path; } -static cairo_surface_t *load_scaled_flag(const char *filename) { - cairo_surface_t *flag = cairo_image_surface_create_from_png(filename); - cairo_surface_t *scaled = scale_flag(flag); - cairo_surface_destroy(flag); - return scaled; +static cairo_pattern_t * +wave_mesh_create (double aspect, int alpha) +{ + cairo_pattern_t *pattern = cairo_pattern_create_mesh(); + cairo_matrix_t scale_matrix = {128./SIZE/SCALE, 0, 0, 128./SIZE/SCALE, 0, 0}; + cairo_pattern_set_matrix (pattern, &scale_matrix); + cairo_mesh_pattern_begin_patch(pattern); + + cairo_mesh_pattern_line_to(pattern, M(0)); + cairo_mesh_pattern_curve_to(pattern, M(1), M(2), M(3)); + cairo_mesh_pattern_line_to(pattern, M(4)); + cairo_mesh_pattern_curve_to(pattern, M(5), M(6), M(7)); + + if (alpha) + { + cairo_mesh_pattern_set_corner_color_rgba(pattern, 0, 0, 0, 0, 0); + cairo_mesh_pattern_set_corner_color_rgba(pattern, 1, 0, 0, 0, .5); + cairo_mesh_pattern_set_corner_color_rgba(pattern, 2, 0, 0, 0, 1); + cairo_mesh_pattern_set_corner_color_rgba(pattern, 3, 0, 0, 0, .5); + } + else + { + cairo_mesh_pattern_set_corner_color_rgb(pattern, 0, 0, 0, .5); + cairo_mesh_pattern_set_corner_color_rgb(pattern, 1, 1, 0, .5); + cairo_mesh_pattern_set_corner_color_rgb(pattern, 2, 1, 1, .5); + cairo_mesh_pattern_set_corner_color_rgb(pattern, 3, 0, 1, .5); + } + + cairo_mesh_pattern_end_patch(pattern); + + return pattern; } -/* Returns 65536 for luminosoty of 1.0. */ -static int luminosity(uint32_t pix) { - unsigned int sr = (pix >> 16) & 0xFF; - unsigned int sg = (pix >> 8) & 0xFF; - unsigned int sb = pix & 0xFF; +static cairo_surface_t * +scale_flag (cairo_surface_t *flag) +{ + unsigned int w = cairo_image_surface_get_width (flag); + unsigned int h = cairo_image_surface_get_height (flag); + cairo_surface_t *scaled = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 256,256); + cairo_t *cr = cairo_create (scaled); - /* Apply gamma of 2.0 */ - sr = sr * sr; - sg = sg * sg; - sb = sb * sb; + cairo_scale (cr, 256./w, 256./h); - return (sr * 13933u /* 0.2126 * 65536 */ + - sg * 46871u /* 0.7152 * 65536 */ + - sb * 4731u /* 0.0722 * 65536 */) / (255*255); + cairo_set_source_surface (cr, flag, 0, 0); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_BEST); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD); + cairo_paint (cr); + + cairo_destroy (cr); + return scaled; } -/* Returns luminosity. Only miningul if pixel is opaque. - * If pixel is not opaque, sets *transparent to 1. */ -static int luminosity_and_transparency(uint32_t pix, int *transparent) { - if ((pix>>24) < 0xff) { - *transparent = 1; - return 0; - } - return luminosity(pix); +static cairo_surface_t * +load_scaled_flag (const char *filename, double *aspect) +{ + cairo_surface_t *flag = cairo_image_surface_create_from_png (filename); + *aspect = (double) cairo_image_surface_get_width (flag) / + (double) cairo_image_surface_get_height (flag); + cairo_surface_t *scaled = scale_flag (flag); + cairo_surface_destroy (flag); + return scaled; } -static double calculate_border_luminosity_and_transparency( - cairo_surface_t *scaled_flag, - int *transparent) { - /* Some flags might have a border already. As such, skip - * a few pixels on each side... */ - const unsigned int skip = 5; - uint32_t *s = (uint32_t *) cairo_image_surface_get_data(scaled_flag); - unsigned int width = cairo_image_surface_get_width(scaled_flag); - unsigned int height = cairo_image_surface_get_height(scaled_flag); - unsigned int sstride = cairo_image_surface_get_stride(scaled_flag) / 4; - - unsigned int luma = 0; - unsigned int perimeter = (2 * ((width-2*skip) + (height-2*skip) - 2)); - - assert(width > 2 * skip && height > 2 * skip); - - *transparent = 0; - - for (unsigned int x = skip; x < width - skip; x++) - luma += luminosity_and_transparency(s[x], transparent); - s += sstride; - for (unsigned int y = 1 + skip; y < height - 1 - skip; y++) { - luma += luminosity_and_transparency(s[skip], transparent); - luma += luminosity_and_transparency(s[width - 1 - skip], transparent); - s += sstride; - } - for (unsigned int x = skip; x < width - skip; x++) - luma += luminosity_and_transparency(s[x], transparent); - - if (*transparent) { - /* Flag is non-rectangular; eg. Nepal. - * Don't draw a border. */ - return 0; - } - - return luma / (65536. * perimeter); +static int +is_transparent (uint32_t pix) +{ + return ((pix>>24) < 0xff); } -static cairo_t *create_image(void) { - cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - (SIZE+2*MARGIN)*SCALE, - (SIZE+2*MARGIN)*SCALE); - cairo_t *cr = cairo_create(surface); - cairo_surface_destroy(surface); - return cr; +static int +border_is_transparent (cairo_surface_t *scaled_flag) +{ + /* Some flags might have a border already. As such, skip + * a few pixels on each side... */ + const unsigned int skip = 5; + uint32_t *s = (uint32_t *) cairo_image_surface_get_data (scaled_flag); + unsigned int width = cairo_image_surface_get_width (scaled_flag); + unsigned int height = cairo_image_surface_get_height (scaled_flag); + unsigned int sstride = cairo_image_surface_get_stride (scaled_flag) / 4; + + int transparent = 0; + + assert (width > 2 * skip && height > 2 * skip); + + + for (unsigned int x = skip; x < width - skip; x++) + transparent |= is_transparent (s[x]); + s += sstride; + for (unsigned int y = 1 + skip; y < height - 1 - skip; y++) + { + transparent |= is_transparent (s[skip]); + transparent |= is_transparent (s[width - 1 - skip]); + s += sstride; + } + for (unsigned int x = skip; x < width - skip; x++) + transparent |= is_transparent (s[x]); + + return transparent; } -static cairo_surface_t *wave_surface_create(void) { - cairo_t *cr = create_image(); - cairo_surface_t *surface = cairo_surface_reference(cairo_get_target(cr)); - cairo_pattern_t *mesh = wave_mesh_create(); - cairo_set_source(cr, mesh); - cairo_paint(cr); - cairo_pattern_destroy(mesh); - cairo_destroy(cr); - return surface; +static cairo_t * +create_image (void) +{ + cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + (SIZE+2*MARGIN)*SCALE, + (SIZE+2*MARGIN)*SCALE); + cairo_t *cr = cairo_create (surface); + cairo_surface_destroy (surface); + return cr; } -static cairo_surface_t *texture_map(cairo_surface_t *src, - cairo_surface_t *tex) { - uint32_t *s = (uint32_t *) cairo_image_surface_get_data(src); - unsigned int width = cairo_image_surface_get_width(src); - unsigned int height = cairo_image_surface_get_height(src); - unsigned int sstride = cairo_image_surface_get_stride(src) / 4; - - cairo_surface_t *dst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - width, height); - uint32_t *d = (uint32_t *) cairo_image_surface_get_data(dst); - unsigned int dstride = cairo_image_surface_get_stride(dst) / 4; - - uint32_t *t = (uint32_t *) cairo_image_surface_get_data(tex); - unsigned int twidth = cairo_image_surface_get_width(tex); - unsigned int theight = cairo_image_surface_get_height(tex); - unsigned int tstride = cairo_image_surface_get_stride(tex) / 4; - - assert(twidth == 256 && theight == 256); - - for (unsigned int y = 0; y < height; y++) { - for (unsigned int x = 0; x < width; x++) { - unsigned int pix = s[x]; - unsigned int sa = pix >> 24; - unsigned int sr = (pix >> 16) & 0xFF; - unsigned int sg = (pix >> 8) & 0xFF; - unsigned int sb = pix & 0xFF; - if (sa == 0) { - d[x] = 0; - continue; - } - if (sa != 255) { - sr = sr * 255 / sa; - sg = sg * 255 / sa; - sb = sb * 255 / sa; - } - assert(sb >= 127 && sb <= 129); - d[x] = t[tstride * sg + sr]; - } - s += sstride; - d += dstride; - } - cairo_surface_mark_dirty(dst); - - return dst; +static cairo_surface_t * +wave_surface_create (double aspect) +{ + cairo_t *cr = create_image (); + cairo_surface_t *surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_pattern_t *mesh = wave_mesh_create (aspect, 0); + cairo_set_source (cr, mesh); + cairo_paint (cr); + cairo_pattern_destroy (mesh); + cairo_destroy (cr); + return surface; } -static void wave_flag(const char *input_filename, const char *output_filename) { - static cairo_path_t *wave_path; - static cairo_surface_t *wave_surface; - double border_luminosity; - int border_transparent; +static cairo_surface_t * +texture_map (cairo_surface_t *src, cairo_surface_t *tex) +{ + uint32_t *s = (uint32_t *) cairo_image_surface_get_data (src); + unsigned int width = cairo_image_surface_get_width (src); + unsigned int height = cairo_image_surface_get_height (src); + unsigned int sstride = cairo_image_surface_get_stride (src) / 4; - cairo_surface_t *scaled_flag, *waved_flag; - cairo_t *cr; + cairo_surface_t *dst = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + uint32_t *d = (uint32_t *) cairo_image_surface_get_data (dst); + unsigned int dstride = cairo_image_surface_get_stride (dst) / 4; - if (!wave_path) - wave_path = wave_path_create(); - if (!wave_surface) - wave_surface = wave_surface_create(); + uint32_t *t = (uint32_t *) cairo_image_surface_get_data (tex); + unsigned int twidth = cairo_image_surface_get_width (tex); + unsigned int theight = cairo_image_surface_get_height (tex); + unsigned int tstride = cairo_image_surface_get_stride (tex) / 4; - printf("Processing %s\n", input_filename); + assert (twidth == 256 && theight == 256); - scaled_flag = load_scaled_flag(input_filename); - border_luminosity = calculate_border_luminosity_and_transparency( - scaled_flag, - &border_transparent); - waved_flag = texture_map(wave_surface, scaled_flag); - cairo_surface_destroy(scaled_flag); + for (unsigned int y = 0; y < height; y++) + { + for (unsigned int x = 0; x < width; x++) + { + unsigned int pix = s[x]; + unsigned int sa = pix >> 24; + unsigned int sr = (pix >> 16) & 0xFF; + unsigned int sg = (pix >> 8) & 0xFF; + unsigned int sb = (pix ) & 0xFF; + if (sa == 0) + { + d[x] = 0; + continue; + } + if (sa != 255) + { + sr = sr * 255 / sa; + sg = sg * 255 / sa; + sb = sb * 255 / sa; + } + assert (sb >= 127 && sb <= 129); + d[x] = t[tstride * sg + sr]; + } + s += sstride; + d += dstride; + } + cairo_surface_mark_dirty (dst); - cr = create_image(); - cairo_translate(cr, SCALE * MARGIN, SCALE * MARGIN); - - cairo_set_source_surface(cr, waved_flag, 0, 0); - cairo_append_path(cr, wave_path); - if (!debug) - cairo_clip_preserve(cr); - cairo_paint(cr); - if (!border_transparent) { - double border_alpha = .5 + fabs(.5 - border_luminosity); - double border_width = 3 * SCALE; - double border_gray = (1 - border_luminosity) * border_alpha; - if (debug) - printf("Border: alpha %g width %g gray %g\n", - border_alpha, border_width/SCALE, border_gray); - - cairo_save(cr); - cairo_set_source_rgba(cr, - border_gray, border_gray, border_gray, border_alpha); - cairo_set_line_width(cr, border_width); - if (!debug) - cairo_set_operator(cr, CAIRO_OPERATOR_HSL_LUMINOSITY); - cairo_stroke(cr); - cairo_restore(cr); - } else { - printf("Transparent border\n"); - cairo_new_path(cr); - } - - if (debug) { - /* Draw mesh points. */ - cairo_save(cr); - cairo_scale(cr, SIZE/128.*SCALE, SIZE/128.*SCALE); - cairo_set_source_rgba(cr, .5, .0, .0, .9); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - for (unsigned int i = 0; - i < sizeof(mesh_points) / sizeof(mesh_points[0]); - i++) { - cairo_move_to(cr, M(i)); - cairo_rel_line_to(cr, 0, 0); - } - cairo_set_line_width(cr, 2); - cairo_stroke(cr); - for (unsigned int i = 0; i < 4; i++) { - cairo_move_to(cr, M(2*i)); - cairo_line_to(cr, M(2*i+1)); - cairo_move_to(cr, M(2*i)); - cairo_line_to(cr, M(7 - 2*i)); - } - cairo_set_line_width(cr, .5); - cairo_stroke(cr); - cairo_restore(cr); - } - - if (!debug) { - /* Scale down, 2x at a time, to get best downscaling, because cairo's - * downscaling is crap... :( */ - unsigned int scale = SCALE; - while (scale > 1) { - cairo_surface_t *old_surface, *new_surface; - - old_surface = cairo_surface_reference(cairo_get_target(cr)); - assert(scale % 2 == 0); - scale /= 2; - cairo_destroy(cr); - new_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - (SIZE+2*MARGIN)*scale, - (SIZE+2*MARGIN)*scale); - cr = cairo_create(new_surface); - cairo_scale(cr, .5, .5); - cairo_set_source_surface(cr, old_surface, 0, 0); - cairo_paint(cr); - cairo_surface_destroy(old_surface); - cairo_surface_destroy(new_surface); - } - } - - cairo_surface_write_to_png(cairo_get_target(cr), output_filename); - cairo_destroy(cr); + return dst; } -int main(int argc, char **argv) { - if (argc != 3) { - fprintf(stderr, "Usage: waveflag [-debug] in.png out.png\n"); - return 1; - } +static void +wave_flag (const char *filename, const char *out_prefix) +{ + static cairo_path_t *standard_wave_path; + static cairo_surface_t *standard_wave_surface; + cairo_path_t *wave_path; + cairo_surface_t *wave_surface; + int border_transparent; + char out[1000]; + double aspect = 0; - if (!strcmp(argv[1], "-debug")) { - debug = 1; - argc--, argv++; - } + cairo_surface_t *scaled_flag, *waved_flag; + cairo_t *cr; - wave_flag(argv[1], argv[2]); + printf ("Processing %s\n", filename); - return 0; + scaled_flag = load_scaled_flag (filename, &aspect); + + aspect /= std_aspect; + aspect = sqrt (aspect); // Discount the effect + if (.9 <= aspect && aspect <= 1.1) + { + printf ("Standard aspect ratio\n"); + aspect = 1.; + } + + if (aspect == 1.) + { + if (!standard_wave_path) + standard_wave_path = wave_path_create (aspect); + if (!standard_wave_surface) + standard_wave_surface = wave_surface_create (aspect); + wave_path = standard_wave_path; + wave_surface = standard_wave_surface; + } + else + { + wave_path = wave_path_create (aspect); + wave_surface = wave_surface_create (aspect); + } + + + border_transparent = border_is_transparent (scaled_flag); + waved_flag = texture_map (wave_surface, scaled_flag); + cairo_surface_destroy (scaled_flag); + + cr = create_image (); + cairo_translate (cr, SCALE * MARGIN, SCALE * MARGIN); + + // Paint waved flag + cairo_set_source_surface (cr, waved_flag, 0, 0); + cairo_append_path (cr, wave_path); + if (!debug) + cairo_clip_preserve (cr); + cairo_paint (cr); + + // Paint border + if (!border_transparent) + { + double border_alpha = .2; + double border_width = 4 * SCALE; + double border_gray = 0x42/255.; + if (debug) + printf ("Border: alpha %g width %g gray %g\n", + border_alpha, border_width/SCALE, border_gray); + + cairo_save (cr); + cairo_set_source_rgba (cr, + border_gray * border_alpha, + border_gray * border_alpha, + border_gray * border_alpha, + border_alpha); + cairo_set_line_width (cr, 2*border_width); + if (!debug) + cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY); + cairo_stroke (cr); + cairo_restore (cr); + } + else + { + printf ("Transparent border\n"); + cairo_new_path (cr); + } + + // Paint shade gradient + { + cairo_save (cr); + cairo_pattern_t *gradient = wave_mesh_create (aspect, 1); + cairo_set_source (cr, gradient); + + if (border_transparent) + { + cairo_set_operator (cr, CAIRO_OPERATOR_ATOP); + cairo_paint_with_alpha (cr, .3); + } + else + { + cairo_set_operator (cr, CAIRO_OPERATOR_SOFT_LIGHT); + cairo_paint (cr); + } + + cairo_restore (cr); + } + + if (debug) + { + /* Draw mesh points. */ + cairo_save (cr); + cairo_scale (cr, SIZE/128.*SCALE, SIZE/128.*SCALE); + cairo_set_source_rgba (cr, .5,.0,.0,.9); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + for (unsigned int i = 0; i < sizeof (mesh_points) / sizeof (mesh_points[0]); i++) + { + cairo_move_to (cr, M(i)); + cairo_rel_line_to (cr, 0, 0); + } + cairo_set_line_width (cr, 2); + cairo_stroke (cr); + for (unsigned int i = 0; i < 4; i++) + { + cairo_move_to (cr, M(2*i)); + cairo_line_to (cr, M(2*i+1)); + cairo_move_to (cr, M(2*i)); + cairo_line_to (cr, M(7 - 2*i)); + } + cairo_set_line_width (cr, .5); + cairo_stroke (cr); + cairo_restore (cr); + } + + if (!debug) + { + /* Scale down, 2x at a time, to get best downscaling, because cairo's + * downscaling is crap... :( */ + unsigned int scale = SCALE; + while (scale > 1) + { + cairo_surface_t *old_surface, *new_surface; + + old_surface = cairo_surface_reference (cairo_get_target (cr)); + assert (scale % 2 == 0); + scale /= 2; + cairo_destroy (cr); + new_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, (SIZE+2*MARGIN)*scale, (SIZE+2*MARGIN)*scale); + cr = cairo_create (new_surface); + cairo_scale (cr, .5, .5); + cairo_set_source_surface (cr, old_surface, 0, 0); + cairo_paint (cr); + cairo_surface_destroy (old_surface); + cairo_surface_destroy (new_surface); + } + } + + *out = '\0'; + strcat (out, out_prefix); + strcat (out, filename); + + cairo_surface_write_to_png (cairo_get_target (cr), out); + cairo_destroy (cr); + if (wave_path != standard_wave_path) + cairo_path_destroy (wave_path); + if (wave_surface != standard_wave_surface) + cairo_surface_destroy (wave_surface); +} + +int +main (int argc, char **argv) +{ + const char *out_prefix; + + if (argc < 3) + { + fprintf (stderr, "Usage: waveflag [-debug] out-prefix [in.png]...\n"); + return 1; + } + + if (!strcmp (argv[1], "-debug")) + { + debug = 1; + argc--, argv++; + } + + out_prefix = argv[1]; + argc--, argv++; + + for (argc--, argv++; argc; argc--, argv++) + wave_flag (*argv, out_prefix); + + return 0; } From 41fa8181f588767839f368f6b64371e73d0b1a11 Mon Sep 17 00:00:00 2001 From: Doug Felt Date: Fri, 7 Oct 2016 14:22:30 -0700 Subject: [PATCH 2/2] Update for new waveflag semantics. Previously our copy of waveflag took just an input and output filename. Upstream takes a prefix and one or more input filenames, and concatenates the prefix to the input filename as the output. The makefile is changed to pass a prefix and the input filename, instead of the input filename and the output filename as it formerly did. Unfortunately for us, our inputs have a directory prefix since they're not in the current directory, and we don't want this prefix in the output file path. So we tweak our copy of waveflag.c to call basename on the input file path before we append it to the prefix. We also make the tool a little less noisy by putting more printfs under the debug flag. --- Makefile | 2 +- waveflag.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 1f0a66507..847051df7 100644 --- a/Makefile +++ b/Makefile @@ -152,7 +152,7 @@ $(EMOJI_DIR)/%.png: $(EMOJI_SRC_DIR)/%.png | $(EMOJI_DIR) @convert -extent 136x128 -gravity center -background none "$<" "$@" $(FLAGS_DIR)/%.png: $(FLAGS_SRC_DIR)/%.png ./waveflag $(PNGQUANT) | $(FLAGS_DIR) - @./waveflag "$<" "$@" + @./waveflag $(FLAGS_DIR)/ "$<" $(RESIZED_FLAGS_DIR)/%.png: $(FLAGS_DIR)/%.png | $(RESIZED_FLAGS_DIR) @convert -extent 136x128 -gravity center -background none "$<" "$@" diff --git a/waveflag.c b/waveflag.c index 8e0cb07b3..6a9459a24 100644 --- a/waveflag.c +++ b/waveflag.c @@ -17,6 +17,7 @@ */ #include +#include // basename #include #include #include @@ -269,7 +270,7 @@ wave_flag (const char *filename, const char *out_prefix) cairo_surface_t *scaled_flag, *waved_flag; cairo_t *cr; - printf ("Processing %s\n", filename); + if (debug) printf ("Processing %s\n", filename); scaled_flag = load_scaled_flag (filename, &aspect); @@ -277,7 +278,7 @@ wave_flag (const char *filename, const char *out_prefix) aspect = sqrt (aspect); // Discount the effect if (.9 <= aspect && aspect <= 1.1) { - printf ("Standard aspect ratio\n"); + if (debug) printf ("Standard aspect ratio\n"); aspect = 1.; } @@ -335,7 +336,7 @@ wave_flag (const char *filename, const char *out_prefix) } else { - printf ("Transparent border\n"); + if (debug) printf ("Transparent border\n"); cairo_new_path (cr); } @@ -410,7 +411,7 @@ wave_flag (const char *filename, const char *out_prefix) *out = '\0'; strcat (out, out_prefix); - strcat (out, filename); + strcat (out, basename(filename)); cairo_surface_write_to_png (cairo_get_target (cr), out); cairo_destroy (cr);