Merge pull request #4045 from harfbuzz/custom-palette-cairo

Custom palette cairo
This commit is contained in:
Matthias Clasen 2023-01-21 02:20:39 -05:00 committed by GitHub
commit 32f9b467d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 185 additions and 58 deletions

View File

@ -225,8 +225,6 @@ hb_draw_state_t
<SECTION> <SECTION>
<FILE>hb-paint</FILE> <FILE>hb-paint</FILE>
HB_PAINT_PALETTE_INDEX_CUSTOM
hb_paint_funcs_t hb_paint_funcs_t
hb_paint_funcs_create hb_paint_funcs_create
hb_paint_funcs_get_empty hb_paint_funcs_get_empty

View File

@ -213,6 +213,7 @@ if cairo_dep.found()
conf.set('HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC', 1) conf.set('HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC', 1)
else else
check_funcs += [['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}]] check_funcs += [['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}]]
check_funcs += [['cairo_font_options_get_custom_palette_color', {'deps': cairo_dep}]]
endif endif
endif endif

View File

@ -97,15 +97,13 @@ public:
if (color_index != 0xffff) if (color_index != 0xffff)
{ {
if (palette_index != HB_PAINT_PALETTE_INDEX_CUSTOM) if (!funcs->custom_palette_color (data, color_index, &color))
{ {
unsigned int clen = 1; unsigned int clen = 1;
hb_face_t *face = hb_font_get_face (font); hb_face_t *face = hb_font_get_face (font);
hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color); hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color);
} }
else
color = funcs->custom_palette_color (data, color_index);
*is_foreground = false; *is_foreground = false;
} }

View File

@ -306,6 +306,68 @@ hb_cairo_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
_hb_cairo_paint_sweep_gradient (cr, color_line, x0, y0, start_angle, end_angle); _hb_cairo_paint_sweep_gradient (cr, color_line, x0, y0, start_angle, end_angle);
} }
static const cairo_user_data_key_t color_cache_key = {0};
static void
_hb_cairo_destroy_map (void *p)
{
hb_map_destroy ((hb_map_t *) p);
}
static hb_bool_t
hb_cairo_paint_custom_palette_color (hb_paint_funcs_t *funcs,
void *paint_data,
unsigned int color_index,
hb_color_t *color,
void *user_data HB_UNUSED)
{
#ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR
cairo_t *cr = (cairo_t *) paint_data;
#define HB_DEADBEEF HB_TAG(0xDE,0xAD,0xBE,0xEF)
hb_map_t *color_cache = (hb_map_t *) cairo_get_user_data (cr, &color_cache_key);
hb_codepoint_t *c;
if (likely (color_cache && color_cache->has (color_index, &c)))
{
if (*c == HB_DEADBEEF)
return false;
*color = *c;
return true;
}
cairo_font_options_t *options;
double red, green, blue, alpha;
options = cairo_font_options_create ();
cairo_get_font_options (cr, options);
if (CAIRO_STATUS_SUCCESS ==
cairo_font_options_get_custom_palette_color (options, color_index,
&red, &green, &blue, &alpha))
{
cairo_font_options_destroy (options);
*color = HB_COLOR (round (255 * blue),
round (255 * green),
round (255 * red),
round (255 * alpha));
if (likely (color_cache && *color != HB_DEADBEEF))
color_cache->set (color_index, *color);
return true;
}
cairo_font_options_destroy (options);
if (likely (color_cache))
color_cache->set (color_index, HB_DEADBEEF);
#undef HB_DEADBEEF
#endif
return false;
}
static inline void free_static_cairo_paint_funcs (); static inline void free_static_cairo_paint_funcs ();
static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<hb_cairo_paint_funcs_lazy_loader_t> static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<hb_cairo_paint_funcs_lazy_loader_t>
@ -326,6 +388,7 @@ static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<
hb_paint_funcs_set_linear_gradient_func (funcs, hb_cairo_paint_linear_gradient, nullptr, nullptr); hb_paint_funcs_set_linear_gradient_func (funcs, hb_cairo_paint_linear_gradient, nullptr, nullptr);
hb_paint_funcs_set_radial_gradient_func (funcs, hb_cairo_paint_radial_gradient, nullptr, nullptr); hb_paint_funcs_set_radial_gradient_func (funcs, hb_cairo_paint_radial_gradient, nullptr, nullptr);
hb_paint_funcs_set_sweep_gradient_func (funcs, hb_cairo_paint_sweep_gradient, nullptr, nullptr); hb_paint_funcs_set_sweep_gradient_func (funcs, hb_cairo_paint_sweep_gradient, nullptr, nullptr);
hb_paint_funcs_set_custom_palette_color_func (funcs, hb_cairo_paint_custom_palette_color, nullptr, nullptr);
hb_paint_funcs_make_immutable (funcs); hb_paint_funcs_make_immutable (funcs);
@ -346,12 +409,6 @@ hb_cairo_paint_get_funcs ()
{ {
return static_cairo_paint_funcs.get_unconst (); return static_cairo_paint_funcs.get_unconst ();
} }
static cairo_status_t
hb_cairo_render_color_glyph (cairo_scaled_font_t *scaled_font,
unsigned long glyph,
cairo_t *cr,
cairo_text_extents_t *extents);
#endif #endif
static const cairo_user_data_key_t hb_cairo_face_user_data_key = {0}; static const cairo_user_data_key_t hb_cairo_face_user_data_key = {0};
@ -439,6 +496,11 @@ hb_cairo_init_scaled_font (cairo_scaled_font_t *scaled_font,
extents->descent = (double) -hb_extents.descender / y_scale; extents->descent = (double) -hb_extents.descender / y_scale;
extents->height = extents->ascent + extents->descent; extents->height = extents->ascent + extents->descent;
#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
hb_map_t *color_cache = hb_map_create ();
cairo_scaled_font_set_user_data (scaled_font, &color_cache_key, color_cache, _hb_cairo_destroy_map);
#endif
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }
@ -515,19 +577,21 @@ hb_cairo_render_color_glyph (cairo_scaled_font_t *scaled_font,
hb_color_t color = HB_COLOR (0, 0, 0, 255); hb_color_t color = HB_COLOR (0, 0, 0, 255);
cairo_pattern_t *pattern = cairo_get_source (cr); cairo_pattern_t *pattern = cairo_get_source (cr);
if (cairo_pattern_get_type (pattern) == CAIRO_PATTERN_TYPE_SOLID) double r, g, b, a;
{ if (cairo_pattern_get_rgba (pattern, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS)
double r, g, b, a; color = HB_COLOR (round (b * 255.), round (g * 255.), round (r * 255.), round (a * 255.));
cairo_pattern_get_rgba (pattern, &r, &g, &b, &a);
color = HB_COLOR ((int)(b * 255.), (int)(g * 255.), (int) (r * 255.), (int)(a * 255.));
}
hb_position_t x_scale, y_scale; hb_position_t x_scale, y_scale;
hb_font_get_scale (font, &x_scale, &y_scale); hb_font_get_scale (font, &x_scale, &y_scale);
cairo_scale (cr, +1./x_scale, -1./y_scale); cairo_scale (cr, +1./x_scale, -1./y_scale);
void *color_cache = cairo_scaled_font_get_user_data (scaled_font, &color_cache_key);
cairo_set_user_data (cr, &color_cache_key, color_cache, nullptr);
hb_font_paint_glyph (font, glyph, hb_cairo_paint_get_funcs (), cr, palette, color); hb_font_paint_glyph (font, glyph, hb_cairo_paint_get_funcs (), cr, palette, color);
cairo_set_user_data (cr, &color_cache_key, nullptr, nullptr);
return CAIRO_STATUS_SUCCESS; return CAIRO_STATUS_SUCCESS;
} }

View File

@ -1440,8 +1440,7 @@ hb_font_draw_glyph (hb_font_t *font,
* *
* If the font has color palettes (see hb_ot_color_has_palettes()), * If the font has color palettes (see hb_ot_color_has_palettes()),
* then @palette_index selects the palette to use. If the font only * then @palette_index selects the palette to use. If the font only
* has one palette, this will be 0. Use %HB_PAINT_PALETTE_INDEX_CUSTOM * has one palette, this will be 0.
* for custom palette.
* *
* Since: REPLACEME * Since: REPLACEME
*/ */

View File

@ -156,9 +156,9 @@ _hb_ft_color_line_get_color_stops (hb_color_line_t *color_line,
(hb_color_get_alpha (c->foreground) * stop.color.alpha) >> 14); (hb_color_get_alpha (c->foreground) * stop.color.alpha) >> 14);
else else
{ {
if (c->palette_index == HB_PAINT_PALETTE_INDEX_CUSTOM) hb_color_t color;
if (c->funcs->custom_palette_color (c->data, stop.color.palette_index, &color))
{ {
hb_color_t color = c->funcs->custom_palette_color (c->data, stop.color.palette_index);
color_stops->color = HB_COLOR (hb_color_get_blue (color), color_stops->color = HB_COLOR (hb_color_get_blue (color),
hb_color_get_green (color), hb_color_get_green (color),
hb_color_get_red (color), hb_color_get_red (color),
@ -237,9 +237,8 @@ _hb_ft_paint (hb_ft_paint_context_t *c,
(hb_color_get_alpha (c->foreground) * paint.u.solid.color.alpha) >> 14); (hb_color_get_alpha (c->foreground) * paint.u.solid.color.alpha) >> 14);
else else
{ {
if (c->palette_index == HB_PAINT_PALETTE_INDEX_CUSTOM) if (c->funcs->custom_palette_color (c->data, paint.u.solid.color.palette_index, &color))
{ {
color = c->funcs->custom_palette_color (c->data, paint.u.solid.color.palette_index);
color = HB_COLOR (hb_color_get_blue (color), color = HB_COLOR (hb_color_get_blue (color),
hb_color_get_green (color), hb_color_get_green (color),
hb_color_get_red (color), hb_color_get_red (color),

View File

@ -24,7 +24,6 @@
*/ */
#include "hb.hh" #include "hb.hh"
#include "hb-machinery.hh"
#include "hb-number.hh" #include "hb-number.hh"
#include "hb-number-parser.hh" #include "hb-number-parser.hh"

View File

@ -117,10 +117,11 @@ hb_paint_pop_group_nil (hb_paint_funcs_t *funcs, void *paint_data,
hb_paint_composite_mode_t mode, hb_paint_composite_mode_t mode,
void *user_data) {} void *user_data) {}
static hb_color_t static hb_bool_t
hb_paint_custom_palette_color_nil (hb_paint_funcs_t *funcs, void *paint_data, hb_paint_custom_palette_color_nil (hb_paint_funcs_t *funcs, void *paint_data,
unsigned int color_index, unsigned int color_index,
void *user_data) { return HB_COLOR(0,0,0,0); } hb_color_t *color,
void *user_data) { return false; }
static bool static bool
_hb_paint_funcs_set_preamble (hb_paint_funcs_t *funcs, _hb_paint_funcs_set_preamble (hb_paint_funcs_t *funcs,
@ -683,18 +684,20 @@ hb_paint_pop_group (hb_paint_funcs_t *funcs, void *paint_data,
* @funcs: paint functions * @funcs: paint functions
* @paint_data: associated data passed by the caller * @paint_data: associated data passed by the caller
* @color_index: color index * @color_index: color index
* @color: (out): fetched color
* *
* Gets the custom palette color for @color_index. * Gets the custom palette color for @color_index.
* *
* Return value: the custom color * Return value: `true` if found, `false` otherwise
* *
* Since: REPLACEME * Since: REPLACEME
*/ */
hb_color_t hb_bool_t
hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data, hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data,
unsigned int color_index) unsigned int color_index,
hb_color_t *color)
{ {
return funcs->custom_palette_color (paint_data, color_index); return funcs->custom_palette_color (paint_data, color_index, color);
} }
#endif #endif

View File

@ -34,17 +34,6 @@
HB_BEGIN_DECLS HB_BEGIN_DECLS
/**
* HB_PAINT_PALETTE_INDEX_CUSTOM
*
* A palette index signifying that custom colors are in use.
* Such colors are fetched from the client using the
* custom-palette-color callback of the paint functions.
*
* Since: REPLACEME
**/
#define HB_PAINT_PALETTE_INDEX_CUSTOM 0xFFFFFFFF
/** /**
* hb_paint_funcs_t: * hb_paint_funcs_t:
* *
@ -672,18 +661,21 @@ typedef void (*hb_paint_pop_group_func_t) (hb_paint_funcs_t *funcs,
* @funcs: paint functions object * @funcs: paint functions object
* @paint_data: The data accompanying the paint functions in hb_font_paint_glyph() * @paint_data: The data accompanying the paint functions in hb_font_paint_glyph()
* @color_index: the color index * @color_index: the color index
* @color: (out): fetched color
* @user_data: User data pointer passed to hb_paint_funcs_set_pop_group_func() * @user_data: User data pointer passed to hb_paint_funcs_set_pop_group_func()
* *
* A virtual method for the #hb_paint_funcs_t to fetch a color from the custom * A virtual method for the #hb_paint_funcs_t to fetch a color from the custom
* color palette. * color palette.
* *
* Return value: the color * Return value: `true` if found, `false` otherwise
*
* Since: REPLACEME * Since: REPLACEME
*/ */
typedef hb_color_t (*hb_paint_custom_palette_color_func_t) (hb_paint_funcs_t *funcs, typedef hb_bool_t (*hb_paint_custom_palette_color_func_t) (hb_paint_funcs_t *funcs,
void *paint_data, void *paint_data,
unsigned int color_index, unsigned int color_index,
void *user_data); hb_color_t *color,
void *user_data);
/** /**
@ -974,9 +966,10 @@ HB_EXTERN void
hb_paint_pop_group (hb_paint_funcs_t *funcs, void *paint_data, hb_paint_pop_group (hb_paint_funcs_t *funcs, void *paint_data,
hb_paint_composite_mode_t mode); hb_paint_composite_mode_t mode);
HB_EXTERN hb_color_t HB_EXTERN hb_bool_t
hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data, hb_paint_custom_palette_color (hb_paint_funcs_t *funcs, void *paint_data,
unsigned int color_index); unsigned int color_index,
hb_color_t *color);
HB_END_DECLS HB_END_DECLS

View File

@ -138,10 +138,12 @@ struct hb_paint_funcs_t
{ func.pop_group (this, paint_data, { func.pop_group (this, paint_data,
mode, mode,
!user_data ? nullptr : user_data->pop_group); } !user_data ? nullptr : user_data->pop_group); }
hb_color_t custom_palette_color (void *paint_data, bool custom_palette_color (void *paint_data,
unsigned int color_index) unsigned int color_index,
hb_color_t *color)
{ return func.custom_palette_color (this, paint_data, { return func.custom_palette_color (this, paint_data,
color_index, color_index,
color,
!user_data ? nullptr : user_data->custom_palette_color); } !user_data ? nullptr : user_data->custom_palette_color); }

View File

@ -69,7 +69,6 @@ struct font_options_t : face_options_t
mutable double font_size_y = DEFAULT_FONT_SIZE; mutable double font_size_y = DEFAULT_FONT_SIZE;
char *font_funcs = nullptr; char *font_funcs = nullptr;
int ft_load_flags = 2; int ft_load_flags = 2;
unsigned int palette = 0;
unsigned int named_instance = HB_FONT_NO_VAR_NAMED_INSTANCE; unsigned int named_instance = HB_FONT_NO_VAR_NAMED_INSTANCE;
hb_font_t *font = nullptr; hb_font_t *font = nullptr;
@ -289,7 +288,6 @@ font_options_t::add_options (option_parser_t *parser)
G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"}, G_OPTION_ARG_DOUBLE, &this->ptem, "Set font point-size (default: 0; disabled)", "point-size"},
{"font-slant", 0, 0, {"font-slant", 0, 0,
G_OPTION_ARG_DOUBLE, &this->slant, "Set synthetic slant (default: 0)", "slant ratio; eg. 0.2"}, G_OPTION_ARG_DOUBLE, &this->slant, "Set synthetic slant (default: 0)", "slant ratio; eg. 0.2"},
{"font-palette", 0, 0, G_OPTION_ARG_INT, &this->palette, "Set font palette (default: 0)", "index"},
{"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"}, {"font-funcs", 0, 0, G_OPTION_ARG_STRING, &this->font_funcs, text, "impl"},
{"sub-font", 0, G_OPTION_FLAG_HIDDEN, {"sub-font", 0, G_OPTION_FLAG_HIDDEN,
G_OPTION_ARG_NONE, &this->sub_font, "Create a sub-font (default: false)", "boolean"}, G_OPTION_ARG_NONE, &this->sub_font, "Create a sub-font (default: false)", "boolean"},

View File

@ -88,7 +88,8 @@ helper_cairo_use_hb_draw (const font_options_t *font_opts)
} }
static inline cairo_scaled_font_t * static inline cairo_scaled_font_t *
helper_cairo_create_scaled_font (const font_options_t *font_opts) helper_cairo_create_scaled_font (const font_options_t *font_opts,
const view_options_t *view_opts)
{ {
hb_font_t *font = font_opts->font; hb_font_t *font = font_opts->font;
bool use_hb_draw = true; bool use_hb_draw = true;
@ -123,7 +124,33 @@ helper_cairo_create_scaled_font (const font_options_t *font_opts)
cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE);
cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF); cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF);
#ifdef CAIRO_COLOR_PALETTE_DEFAULT #ifdef CAIRO_COLOR_PALETTE_DEFAULT
cairo_font_options_set_color_palette (font_options, font_opts->palette); cairo_font_options_set_color_palette (font_options, view_opts->palette);
#endif
#ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR
if (view_opts->custom_palette)
{
char **entries = g_strsplit (view_opts->custom_palette, ",", -1);
unsigned idx = 0;
for (unsigned i = 0; entries[i]; i++)
{
const char *p = strchr (entries[i], '=');
if (!p)
p = entries[i];
else
{
sscanf (entries[i], "%u", &idx);
p++;
}
unsigned fr, fg, fb, fa;
fr = fg = fb = fa = 0;
if (parse_color (p, fr, fg,fb, fa))
cairo_font_options_set_custom_palette_color (font_options, idx, fr / 255., fg / 255., fb / 255., fa / 255.);
idx++;
}
g_strfreev (entries);
}
#endif #endif
cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face, cairo_scaled_font_t *scaled_font = cairo_scaled_font_create (cairo_face,
@ -492,12 +519,12 @@ helper_cairo_create_context (double w, double h,
unsigned int fr, fg, fb, fa, br, bg, bb, ba; unsigned int fr, fg, fb, fa, br, bg, bb, ba;
const char *color; const char *color;
br = bg = bb = 0; ba = 255; br = bg = bb = ba = 255;
color = view_opts->back ? view_opts->back : DEFAULT_BACK; color = view_opts->back ? view_opts->back : DEFAULT_BACK;
sscanf (color + (*color=='#'), "%2x%2x%2x%2x", &br, &bg, &bb, &ba); parse_color (color, br, bg, bb, ba);
fr = fg = fb = 0; fa = 255; fr = fg = fb = 0; fa = 255;
color = view_opts->fore ? view_opts->fore : DEFAULT_FORE; color = view_opts->fore ? view_opts->fore : DEFAULT_FORE;
sscanf (color + (*color=='#'), "%2x%2x%2x%2x", &fr, &fg, &fb, &fa); parse_color (color, fr, fg, fb, fa);
if (content == CAIRO_CONTENT_ALPHA) if (content == CAIRO_CONTENT_ALPHA)
{ {

View File

@ -242,4 +242,44 @@ __inline float scalbnf (float x, int exp)
} }
#endif #endif
static inline bool
parse_color (const char *s,
unsigned &r,
unsigned &g,
unsigned &b,
unsigned &a)
{
bool ret = false;
while (*s == ' ') s++;
if (*s == '#') s++;
unsigned sr, sg, sb, sa;
sa = 255;
if (sscanf (s, "%2x%2x%2x%2x", &sr, &sg, &sb, &sa) <= 2)
{
if (sscanf (s, "%1x%1x%1x%1x", &sr, &sg, &sb, &sa) >= 3)
{
sr *= 17;
sg *= 17;
sb *= 17;
sa *= 17;
ret = true;
}
}
else
ret = true;
if (ret)
{
r = sr;
g = sg;
b = sb;
a = sa;
}
return ret;
}
#endif #endif

View File

@ -131,7 +131,8 @@ view_cairo_t::render (const font_options_t *font_opts)
w = MAX (w, x_sign * x_advance); w = MAX (w, x_sign * x_advance);
} }
cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts); cairo_scaled_font_t *scaled_font = helper_cairo_create_scaled_font (font_opts,
this);
/* See if font needs color. */ /* See if font needs color. */
cairo_content_t content = CAIRO_CONTENT_ALPHA; cairo_content_t content = CAIRO_CONTENT_ALPHA;

View File

@ -39,6 +39,7 @@ struct view_options_t
{ {
g_free (fore); g_free (fore);
g_free (back); g_free (back);
g_free (custom_palette);
} }
void add_options (option_parser_t *parser); void add_options (option_parser_t *parser);
@ -46,6 +47,8 @@ struct view_options_t
hb_bool_t annotate = false; hb_bool_t annotate = false;
char *fore = nullptr; char *fore = nullptr;
char *back = nullptr; char *back = nullptr;
unsigned int palette = 0;
char *custom_palette = nullptr;
double line_space = 0; double line_space = 0;
bool have_font_extents = false; bool have_font_extents = false;
struct font_extents_t { struct font_extents_t {
@ -108,6 +111,8 @@ view_options_t::add_options (option_parser_t *parser)
{"annotate", 0, 0, G_OPTION_ARG_NONE, &this->annotate, "Annotate output rendering", nullptr}, {"annotate", 0, 0, G_OPTION_ARG_NONE, &this->annotate, "Annotate output rendering", nullptr},
{"background", 0, 0, G_OPTION_ARG_STRING, &this->back, "Set background color (default: " DEFAULT_BACK ")", "rrggbb/rrggbbaa"}, {"background", 0, 0, G_OPTION_ARG_STRING, &this->back, "Set background color (default: " DEFAULT_BACK ")", "rrggbb/rrggbbaa"},
{"foreground", 0, 0, G_OPTION_ARG_STRING, &this->fore, "Set foreground color (default: " DEFAULT_FORE ")", "rrggbb/rrggbbaa"}, {"foreground", 0, 0, G_OPTION_ARG_STRING, &this->fore, "Set foreground color (default: " DEFAULT_FORE ")", "rrggbb/rrggbbaa"},
{"font-palette", 0, 0, G_OPTION_ARG_INT, &this->palette, "Set font palette (default: 0)", "index"},
{"custom-palette", 0, 0, G_OPTION_ARG_STRING, &this->custom_palette, "Custom palette", "comma-separated colors"},
{"line-space", 0, 0, G_OPTION_ARG_DOUBLE, &this->line_space, "Set space between lines (default: 0)", "units"}, {"line-space", 0, 0, G_OPTION_ARG_DOUBLE, &this->line_space, "Set space between lines (default: 0)", "units"},
{"font-extents", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_extents, "Set font ascent/descent/line-gap (default: auto)","one to three numbers"}, {"font-extents", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_font_extents, "Set font ascent/descent/line-gap (default: auto)","one to three numbers"},
{"margin", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_margin, "Margin around output (default: " G_STRINGIFY(DEFAULT_MARGIN) ")","one to four numbers"}, {"margin", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_margin, "Margin around output (default: " G_STRINGIFY(DEFAULT_MARGIN) ")","one to four numbers"},