Update waveflag.c to upstream version.

Also updates LDFLAGS to match upstream.
This commit is contained in:
Doug Felt 2016-10-07 14:17:09 -07:00
parent a4ab161af7
commit 741f8b92c9
2 changed files with 382 additions and 312 deletions

View file

@ -16,7 +16,7 @@ EMOJI = NotoColorEmoji
font: $(EMOJI).ttf font: $(EMOJI).ttf
CFLAGS = -std=c99 -Wall -Wextra `pkg-config --cflags --libs cairo` 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 PNGQUANTDIR := third_party/pngquant
PNGQUANT := $(PNGQUANTDIR)/pngquant PNGQUANT := $(PNGQUANTDIR)/pngquant
PNGQUANTFLAGS = --speed 1 --skip-if-larger --force PNGQUANTFLAGS = --speed 1 --skip-if-larger --force

View file

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* *
* Google contributors: Behdad Esfahbod, Roozbeh Pournader * Google contributors: Behdad Esfahbod
*/ */
#include <cairo.h> #include <cairo.h>
@ -26,64 +26,67 @@
#define SCALE 8 #define SCALE 8
#define SIZE 128 #define SIZE 128
#define MARGIN (debug ? 24 : 0) #define MARGIN (debug ? 4 : 0)
static unsigned int debug; static unsigned int debug;
static cairo_path_t *wave_path_create(void) { #define std_aspect (5./3.)
cairo_surface_t *surface = cairo_image_surface_create( #define top 21
CAIRO_FORMAT_ARGB32, 0, 0); #define bot 128-top
cairo_t *cr = cairo_create(surface); #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) \
x_aspect (mesh_points[i].x, aspect), \
y_aspect (mesh_points[i].y, aspect)
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_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_path_t *path;
cairo_scale(cr, SIZE/128.*SCALE, SIZE/128.*SCALE); cairo_scale (cr, SIZE/128.*SCALE, SIZE/128.*SCALE);
cairo_move_to(cr, 127.15, 81.52); cairo_line_to(cr, M(0));
cairo_rel_line_to(cr, -20.51, -66.94); cairo_curve_to(cr, M(1), M(2), M(3));
cairo_rel_curve_to(cr, -0.61, -2, -2.22, -3.53, -4.25, -4.03); cairo_line_to(cr, M(4));
cairo_rel_curve_to(cr, -0.48, -0.12, -0.96, -0.18, -1.44, -0.18); cairo_curve_to(cr, M(5), M(6), M(7));
cairo_rel_curve_to(cr, -1.56, 0, -3.07, 0.61, -4.2, 1.74); cairo_close_path (cr);
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); cairo_identity_matrix (cr);
path = cairo_copy_path(cr); path = cairo_copy_path (cr);
cairo_destroy(cr); cairo_destroy (cr);
cairo_surface_destroy(surface); cairo_surface_destroy (surface);
return path; return path;
} }
static struct { double x, y; } mesh_points[] = { static cairo_pattern_t *
{ -1, 43}, wave_mesh_create (double aspect, int alpha)
{ 30, -3}, {
{ 77, 47},
{104, 1},
{130, 84},
{100, 138},
{ 45, 80},
{ 7, 127},
};
#define M(i) mesh_points[i].x, mesh_points[i].y
static cairo_pattern_t *wave_mesh_create(void) {
cairo_pattern_t *pattern = cairo_pattern_create_mesh(); cairo_pattern_t *pattern = cairo_pattern_create_mesh();
cairo_matrix_t scale_matrix = {128./SIZE/SCALE, 0, 0, 128./SIZE/SCALE, 0, 0}; cairo_matrix_t scale_matrix = {128./SIZE/SCALE, 0, 0, 128./SIZE/SCALE, 0, 0};
cairo_pattern_set_matrix(pattern, &scale_matrix); cairo_pattern_set_matrix (pattern, &scale_matrix);
cairo_mesh_pattern_begin_patch(pattern); cairo_mesh_pattern_begin_patch(pattern);
cairo_mesh_pattern_line_to(pattern, M(0)); cairo_mesh_pattern_line_to(pattern, M(0));
@ -91,287 +94,354 @@ static cairo_pattern_t *wave_mesh_create(void) {
cairo_mesh_pattern_line_to(pattern, M(4)); cairo_mesh_pattern_line_to(pattern, M(4));
cairo_mesh_pattern_curve_to(pattern, M(5), M(6), M(7)); 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, 0, 0, 0, .5);
cairo_mesh_pattern_set_corner_color_rgb(pattern, 1, 1, 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, 2, 1, 1, .5);
cairo_mesh_pattern_set_corner_color_rgb(pattern, 3, 0, 1, .5); cairo_mesh_pattern_set_corner_color_rgb(pattern, 3, 0, 1, .5);
}
cairo_mesh_pattern_end_patch(pattern); cairo_mesh_pattern_end_patch(pattern);
return pattern; return pattern;
} }
static cairo_surface_t *scale_flag(cairo_surface_t *flag) { static cairo_surface_t *
unsigned int w = cairo_image_surface_get_width(flag); scale_flag (cairo_surface_t *flag)
unsigned int h = cairo_image_surface_get_height(flag); {
cairo_surface_t *scaled = cairo_image_surface_create( unsigned int w = cairo_image_surface_get_width (flag);
CAIRO_FORMAT_ARGB32, 256, 256); unsigned int h = cairo_image_surface_get_height (flag);
cairo_t *cr = cairo_create(scaled); cairo_surface_t *scaled = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 256,256);
cairo_t *cr = cairo_create (scaled);
cairo_scale(cr, 256./w, 256./h); cairo_scale (cr, 256./w, 256./h);
cairo_set_source_surface(cr, flag, 0, 0); cairo_set_source_surface (cr, flag, 0, 0);
cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BEST); cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_BEST);
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_PAD); cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD);
cairo_paint(cr); cairo_paint (cr);
cairo_destroy(cr); cairo_destroy (cr);
return scaled; return scaled;
} }
static cairo_surface_t *load_scaled_flag(const char *filename) { static cairo_surface_t *
cairo_surface_t *flag = cairo_image_surface_create_from_png(filename); load_scaled_flag (const char *filename, double *aspect)
cairo_surface_t *scaled = scale_flag(flag); {
cairo_surface_destroy(flag); 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; return scaled;
} }
/* Returns 65536 for luminosoty of 1.0. */ static int
static int luminosity(uint32_t pix) { is_transparent (uint32_t pix)
unsigned int sr = (pix >> 16) & 0xFF; {
unsigned int sg = (pix >> 8) & 0xFF; return ((pix>>24) < 0xff);
unsigned int sb = pix & 0xFF;
/* Apply gamma of 2.0 */
sr = sr * sr;
sg = sg * sg;
sb = sb * sb;
return (sr * 13933u /* 0.2126 * 65536 */ +
sg * 46871u /* 0.7152 * 65536 */ +
sb * 4731u /* 0.0722 * 65536 */) / (255*255);
} }
/* Returns luminosity. Only miningul if pixel is opaque. static int
* If pixel is not opaque, sets *transparent to 1. */ border_is_transparent (cairo_surface_t *scaled_flag)
static int luminosity_and_transparency(uint32_t pix, int *transparent) { {
if ((pix>>24) < 0xff) {
*transparent = 1;
return 0;
}
return luminosity(pix);
}
static double calculate_border_luminosity_and_transparency(
cairo_surface_t *scaled_flag,
int *transparent) {
/* Some flags might have a border already. As such, skip /* Some flags might have a border already. As such, skip
* a few pixels on each side... */ * a few pixels on each side... */
const unsigned int skip = 5; const unsigned int skip = 5;
uint32_t *s = (uint32_t *) cairo_image_surface_get_data(scaled_flag); uint32_t *s = (uint32_t *) cairo_image_surface_get_data (scaled_flag);
unsigned int width = cairo_image_surface_get_width(scaled_flag); unsigned int width = cairo_image_surface_get_width (scaled_flag);
unsigned int height = cairo_image_surface_get_height(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 sstride = cairo_image_surface_get_stride (scaled_flag) / 4;
unsigned int luma = 0; int transparent = 0;
unsigned int perimeter = (2 * ((width-2*skip) + (height-2*skip) - 2));
assert(width > 2 * skip && height > 2 * skip); assert (width > 2 * skip && height > 2 * skip);
*transparent = 0;
for (unsigned int x = skip; x < width - skip; x++) for (unsigned int x = skip; x < width - skip; x++)
luma += luminosity_and_transparency(s[x], transparent); transparent |= is_transparent (s[x]);
s += sstride; s += sstride;
for (unsigned int y = 1 + skip; y < height - 1 - skip; y++) { 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); transparent |= is_transparent (s[skip]);
transparent |= is_transparent (s[width - 1 - skip]);
s += sstride; s += sstride;
} }
for (unsigned int x = skip; x < width - skip; x++) for (unsigned int x = skip; x < width - skip; x++)
luma += luminosity_and_transparency(s[x], transparent); transparent |= is_transparent (s[x]);
if (*transparent) { return transparent;
/* Flag is non-rectangular; eg. Nepal.
* Don't draw a border. */
return 0;
}
return luma / (65536. * perimeter);
} }
static cairo_t *create_image(void) { static cairo_t *
cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, create_image (void)
{
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
(SIZE+2*MARGIN)*SCALE, (SIZE+2*MARGIN)*SCALE,
(SIZE+2*MARGIN)*SCALE); (SIZE+2*MARGIN)*SCALE);
cairo_t *cr = cairo_create(surface); cairo_t *cr = cairo_create (surface);
cairo_surface_destroy(surface); cairo_surface_destroy (surface);
return cr; return cr;
} }
static cairo_surface_t *wave_surface_create(void) { static cairo_surface_t *
cairo_t *cr = create_image(); wave_surface_create (double aspect)
cairo_surface_t *surface = cairo_surface_reference(cairo_get_target(cr)); {
cairo_pattern_t *mesh = wave_mesh_create(); cairo_t *cr = create_image ();
cairo_set_source(cr, mesh); cairo_surface_t *surface = cairo_surface_reference (cairo_get_target (cr));
cairo_paint(cr); cairo_pattern_t *mesh = wave_mesh_create (aspect, 0);
cairo_pattern_destroy(mesh); cairo_set_source (cr, mesh);
cairo_destroy(cr); cairo_paint (cr);
cairo_pattern_destroy (mesh);
cairo_destroy (cr);
return surface; return surface;
} }
static cairo_surface_t *texture_map(cairo_surface_t *src, static cairo_surface_t *
cairo_surface_t *tex) { 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); uint32_t *s = (uint32_t *) cairo_image_surface_get_data (src);
unsigned int height = cairo_image_surface_get_height(src); unsigned int width = cairo_image_surface_get_width (src);
unsigned int sstride = cairo_image_surface_get_stride(src) / 4; 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, cairo_surface_t *dst = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
width, height); uint32_t *d = (uint32_t *) cairo_image_surface_get_data (dst);
uint32_t *d = (uint32_t *) cairo_image_surface_get_data(dst); unsigned int dstride = cairo_image_surface_get_stride (dst) / 4;
unsigned int dstride = cairo_image_surface_get_stride(dst) / 4;
uint32_t *t = (uint32_t *) cairo_image_surface_get_data(tex); uint32_t *t = (uint32_t *) cairo_image_surface_get_data (tex);
unsigned int twidth = cairo_image_surface_get_width(tex); unsigned int twidth = cairo_image_surface_get_width (tex);
unsigned int theight = cairo_image_surface_get_height(tex); unsigned int theight = cairo_image_surface_get_height (tex);
unsigned int tstride = cairo_image_surface_get_stride(tex) / 4; unsigned int tstride = cairo_image_surface_get_stride (tex) / 4;
assert(twidth == 256 && theight == 256); assert (twidth == 256 && theight == 256);
for (unsigned int y = 0; y < height; y++) { for (unsigned int y = 0; y < height; y++)
for (unsigned int x = 0; x < width; x++) { {
for (unsigned int x = 0; x < width; x++)
{
unsigned int pix = s[x]; unsigned int pix = s[x];
unsigned int sa = pix >> 24; unsigned int sa = pix >> 24;
unsigned int sr = (pix >> 16) & 0xFF; unsigned int sr = (pix >> 16) & 0xFF;
unsigned int sg = (pix >> 8) & 0xFF; unsigned int sg = (pix >> 8) & 0xFF;
unsigned int sb = pix & 0xFF; unsigned int sb = (pix ) & 0xFF;
if (sa == 0) { if (sa == 0)
{
d[x] = 0; d[x] = 0;
continue; continue;
} }
if (sa != 255) { if (sa != 255)
{
sr = sr * 255 / sa; sr = sr * 255 / sa;
sg = sg * 255 / sa; sg = sg * 255 / sa;
sb = sb * 255 / sa; sb = sb * 255 / sa;
} }
assert(sb >= 127 && sb <= 129); assert (sb >= 127 && sb <= 129);
d[x] = t[tstride * sg + sr]; d[x] = t[tstride * sg + sr];
} }
s += sstride; s += sstride;
d += dstride; d += dstride;
} }
cairo_surface_mark_dirty(dst); cairo_surface_mark_dirty (dst);
return dst; return dst;
} }
static void wave_flag(const char *input_filename, const char *output_filename) { static void
static cairo_path_t *wave_path; wave_flag (const char *filename, const char *out_prefix)
static cairo_surface_t *wave_surface; {
double border_luminosity; 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; int border_transparent;
char out[1000];
double aspect = 0;
cairo_surface_t *scaled_flag, *waved_flag; cairo_surface_t *scaled_flag, *waved_flag;
cairo_t *cr; cairo_t *cr;
if (!wave_path) printf ("Processing %s\n", filename);
wave_path = wave_path_create();
if (!wave_surface)
wave_surface = wave_surface_create();
printf("Processing %s\n", input_filename); scaled_flag = load_scaled_flag (filename, &aspect);
scaled_flag = load_scaled_flag(input_filename); aspect /= std_aspect;
border_luminosity = calculate_border_luminosity_and_transparency( aspect = sqrt (aspect); // Discount the effect
scaled_flag, if (.9 <= aspect && aspect <= 1.1)
&border_transparent); {
waved_flag = texture_map(wave_surface, scaled_flag); printf ("Standard aspect ratio\n");
cairo_surface_destroy(scaled_flag); aspect = 1.;
}
cr = create_image(); if (aspect == 1.)
cairo_translate(cr, SCALE * MARGIN, SCALE * MARGIN); {
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);
}
cairo_set_source_surface(cr, waved_flag, 0, 0);
cairo_append_path(cr, wave_path); 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) if (!debug)
cairo_clip_preserve(cr); cairo_clip_preserve (cr);
cairo_paint(cr); cairo_paint (cr);
if (!border_transparent) {
double border_alpha = .5 + fabs(.5 - border_luminosity); // Paint border
double border_width = 3 * SCALE; if (!border_transparent)
double border_gray = (1 - border_luminosity) * border_alpha; {
double border_alpha = .2;
double border_width = 4 * SCALE;
double border_gray = 0x42/255.;
if (debug) if (debug)
printf("Border: alpha %g width %g gray %g\n", printf ("Border: alpha %g width %g gray %g\n",
border_alpha, border_width/SCALE, border_gray); border_alpha, border_width/SCALE, border_gray);
cairo_save(cr); cairo_save (cr);
cairo_set_source_rgba(cr, cairo_set_source_rgba (cr,
border_gray, border_gray, border_gray, border_alpha); border_gray * border_alpha,
cairo_set_line_width(cr, border_width); border_gray * border_alpha,
border_gray * border_alpha,
border_alpha);
cairo_set_line_width (cr, 2*border_width);
if (!debug) if (!debug)
cairo_set_operator(cr, CAIRO_OPERATOR_HSL_LUMINOSITY); cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY);
cairo_stroke(cr); cairo_stroke (cr);
cairo_restore(cr); cairo_restore (cr);
} else { }
printf("Transparent border\n"); else
cairo_new_path(cr); {
printf ("Transparent border\n");
cairo_new_path (cr);
} }
if (debug) { // 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. */ /* Draw mesh points. */
cairo_save(cr); cairo_save (cr);
cairo_scale(cr, SIZE/128.*SCALE, SIZE/128.*SCALE); cairo_scale (cr, SIZE/128.*SCALE, SIZE/128.*SCALE);
cairo_set_source_rgba(cr, .5, .0, .0, .9); cairo_set_source_rgba (cr, .5,.0,.0,.9);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
for (unsigned int i = 0; for (unsigned int i = 0; i < sizeof (mesh_points) / sizeof (mesh_points[0]); i++)
i < sizeof(mesh_points) / sizeof(mesh_points[0]); {
i++) { cairo_move_to (cr, M(i));
cairo_move_to(cr, M(i)); cairo_rel_line_to (cr, 0, 0);
cairo_rel_line_to(cr, 0, 0);
} }
cairo_set_line_width(cr, 2); cairo_set_line_width (cr, 2);
cairo_stroke(cr); cairo_stroke (cr);
for (unsigned int i = 0; i < 4; i++) { 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_move_to(cr, M(2*i)); cairo_line_to (cr, M(2*i+1));
cairo_line_to(cr, M(7 - 2*i)); cairo_move_to (cr, M(2*i));
cairo_line_to (cr, M(7 - 2*i));
} }
cairo_set_line_width(cr, .5); cairo_set_line_width (cr, .5);
cairo_stroke(cr); cairo_stroke (cr);
cairo_restore(cr); cairo_restore (cr);
} }
if (!debug) { if (!debug)
{
/* Scale down, 2x at a time, to get best downscaling, because cairo's /* Scale down, 2x at a time, to get best downscaling, because cairo's
* downscaling is crap... :( */ * downscaling is crap... :( */
unsigned int scale = SCALE; unsigned int scale = SCALE;
while (scale > 1) { while (scale > 1)
{
cairo_surface_t *old_surface, *new_surface; cairo_surface_t *old_surface, *new_surface;
old_surface = cairo_surface_reference(cairo_get_target(cr)); old_surface = cairo_surface_reference (cairo_get_target (cr));
assert(scale % 2 == 0); assert (scale % 2 == 0);
scale /= 2; scale /= 2;
cairo_destroy(cr); cairo_destroy (cr);
new_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, new_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, (SIZE+2*MARGIN)*scale, (SIZE+2*MARGIN)*scale);
(SIZE+2*MARGIN)*scale, cr = cairo_create (new_surface);
(SIZE+2*MARGIN)*scale); cairo_scale (cr, .5, .5);
cr = cairo_create(new_surface); cairo_set_source_surface (cr, old_surface, 0, 0);
cairo_scale(cr, .5, .5); cairo_paint (cr);
cairo_set_source_surface(cr, old_surface, 0, 0); cairo_surface_destroy (old_surface);
cairo_paint(cr); cairo_surface_destroy (new_surface);
cairo_surface_destroy(old_surface);
cairo_surface_destroy(new_surface);
} }
} }
cairo_surface_write_to_png(cairo_get_target(cr), output_filename); *out = '\0';
cairo_destroy(cr); 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) { int
if (argc != 3) { main (int argc, char **argv)
fprintf(stderr, "Usage: waveflag [-debug] in.png out.png\n"); {
const char *out_prefix;
if (argc < 3)
{
fprintf (stderr, "Usage: waveflag [-debug] out-prefix [in.png]...\n");
return 1; return 1;
} }
if (!strcmp(argv[1], "-debug")) { if (!strcmp (argv[1], "-debug"))
{
debug = 1; debug = 1;
argc--, argv++; argc--, argv++;
} }
wave_flag(argv[1], argv[2]); out_prefix = argv[1];
argc--, argv++;
for (argc--, argv++; argc; argc--, argv++)
wave_flag (*argv, out_prefix);
return 0; return 0;
} }