tools: Add more commands to gtk4-path-tool

Add stroking and offsetting.
This commit is contained in:
Matthias Clasen
2023-07-01 20:35:41 -04:00
parent 01889060c5
commit cdb9cb950e
6 changed files with 296 additions and 1 deletions

View File

@@ -12,6 +12,8 @@ SYNOPSIS
--------
| **gtk4-path-tool** <COMMAND> [OPTIONS...] <PATH>
|
| **gtk4-path-tool** stroke [OPTIONS...] <PATH>
| **gtk4-path-tool** offset [OPTIONS...] <PATH>
| **gtk4-path-tool** decompose [OPTIONS...] <PATH>
| **gtk4-path-tool** transform [OPTIONS...] <PATH>
| **gtk4-path-tool** reverse [OPTIONS...] <PATH>
@@ -32,6 +34,70 @@ To read a path from stdin, use '-'.
COMMANDS
--------
Stroking
^^^^^^^^
The ``stroke`` command performs a stroke operation along the path according to
the parameters specified via options.
``--line-width=VALUE``
The line width to use for the stroke. ``VALUE`` must be a positive number.
The default line width is 1.
``--line-cap=VALUE``
The cap style to use at line ends. The possible values are ``butt``, ``round``
or ``square``. See the SVG specification for details on these styles.
The default cap style is ``butt``.
``--line-join=VALUE``
The join style to use at line joins. The possible values are ``miter``,
``miter-clip``, ``round``, ``bevel`` or ``arcs``. See the SVG specification
for details on these styles.
The default join style is ``miter``.
``--miter-limit=VALUE``
The limit at which to clip miters at line joins. The default value is 4.
``--dashes=VALUE``
The dash pattern to use for this stroke. A dash pattern is specified by
a comma-separated list of alternating non-negative numbers. Each number
provides the length of alternate "on" and "off" portions of the stroke.
If the dash pattern is empty, dashing is disabled, which is the default.
See the SVG specification for details on dashing.
``--dash-offset=VALUE``
The offset into the dash pattern where dashing should begin.
The default value is 0.
Offsetting
^^^^^^^^^^
The ``offset`` command applies a lateral offset to the path. Note that this
is different from applying a translation transformation.
``--distance=VALUE``
The distance by which to offset the path. Positive values offset to the right,
negative values to the left (wrt to the direction of the path). The default
value is 0.
``--line-join=VALUE``
The join style to use at line joins. The possible values are ``miter``,
``miter-clip``, ``round``, ``bevel`` or ``arcs``. See the SVG specification
for details on these styles.
The default join style is ``miter``.
``--miter-limit=VALUE``
The limit at which to clip miters at line joins. The default value is 4.
Decomposing
^^^^^^^^^^^
@@ -132,7 +198,7 @@ Info
^^^^
The ``info`` command shows various information about the given path,
such as its bounding box and and its length.
such as the number of contours, its bounding box and and its length.
REFERENCES
----------

View File

@@ -0,0 +1,85 @@
/* Copyright 2023 Red Hat, Inc.
*
* GTK+ is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* GLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GTK+; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gtk-path-tool.h"
#include <glib/gi18n-lib.h>
void
do_offset (int *argc, const char ***argv)
{
GError *error = NULL;
double distance = 0;
const char *join = "miter";
double miter_limit = 4;
char **args = NULL;
GOptionContext *context;
GOptionEntry entries[] = {
{ "distance", 0, 0, G_OPTION_ARG_DOUBLE, &distance, N_("Offset to apply (positive or negative number)"), N_("VALUE") },
{ "line-join", 0, 0, G_OPTION_ARG_STRING, &join, N_("Line join (miter, miter-clip, round, bevel, arcs)"), N_("VALUE") },
{ "miter-limit", 0, 0, G_OPTION_ARG_DOUBLE, &miter_limit, N_("Miter limit (number"), N_("VALUE") },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("PATH") },
{ NULL, },
};
GskPath *path, *result;
GskLineJoin line_join;
g_set_prgname ("gtk4-path-tool offset");
context = g_option_context_new (NULL);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_set_summary (context, _("Offset a path."));
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
{
g_printerr ("%s\n", error->message);
g_error_free (error);
exit (1);
}
g_option_context_free (context);
if (args == NULL)
{
g_printerr ("%s\n", _("No paths given."));
exit (1);
}
path = get_path (args[0]);
line_join = get_enum_value (GSK_TYPE_LINE_JOIN, _("line join"), join);
result = gsk_path_offset (path, distance, line_join, miter_limit);
if (result)
{
char *str = gsk_path_to_string (result);
g_print ("%s\n", str);
g_free (str);
}
else
{
g_printerr ("%s\n", _("That didn't work out."));
exit (1);
}
}

View File

@@ -0,0 +1,134 @@
/* Copyright 2023 Red Hat, Inc.
*
* GTK+ is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* GLib is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GTK+; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gtk-path-tool.h"
#include <glib/gi18n-lib.h>
void
do_stroke (int *argc, const char ***argv)
{
GError *error = NULL;
double line_width = 1;
const char *cap = "butt";
const char *join = "miter";
double miter_limit = 4;
const char *dashes = NULL;
double dash_offset = 0;
char **args = NULL;
GOptionContext *context;
GOptionEntry entries[] = {
{ "line-width", 0, 0, G_OPTION_ARG_DOUBLE, &line_width, N_("Line width (number)"), N_("VALUE") },
{ "line-cap", 0, 0, G_OPTION_ARG_STRING, &cap, N_("Line cap (butt, round, square)"), N_("VALUE") },
{ "line-join", 0, 0, G_OPTION_ARG_STRING, &join, N_("Line join (miter, miter-clip, round, bevel, arcs)"), N_("VALUE") },
{ "miter-limit", 0, 0, G_OPTION_ARG_DOUBLE, &miter_limit, N_("Miter limit (number)"), N_("VALUE") },
{ "dashes", 0, 0, G_OPTION_ARG_STRING, &dashes, N_("Dash pattern (comma-separated numbers)"), N_("VALUE") },
{ "dash-offset", 0, 0, G_OPTION_ARG_DOUBLE, &dash_offset, N_("Dash offset (number)"), N_("VALUE") },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("PATH") },
{ NULL, },
};
GskPath *path, *result;
GskLineCap line_cap;
GskLineJoin line_join;
GskStroke *stroke;
g_set_prgname ("gtk4-path-tool stroke");
context = g_option_context_new (NULL);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_set_summary (context, _("Stroke a path."));
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
{
g_printerr ("%s\n", error->message);
g_error_free (error);
exit (1);
}
g_option_context_free (context);
if (args == NULL)
{
g_printerr (_("No paths given.\n"));
exit (1);
}
path = get_path (args[0]);
line_cap = get_enum_value (GSK_TYPE_LINE_CAP, _("line cap"), cap);
line_join = get_enum_value (GSK_TYPE_LINE_JOIN, _("line join"), join);
stroke = gsk_stroke_new (line_width);
gsk_stroke_set_line_cap (stroke, line_cap);
gsk_stroke_set_line_join (stroke, line_join);
gsk_stroke_set_miter_limit (stroke, miter_limit);
if (dashes != NULL)
{
GArray *d = g_array_new (FALSE, FALSE, sizeof (float));
char **strings;
strings = g_strsplit (dashes, ",", 0);
for (unsigned int i = 0; strings[i]; i++)
{
char *end = NULL;
float f;
f = (float) g_ascii_strtod (strings[i], &end);
if (*end != '\0')
{
char *msg = g_strdup_printf (_("Failed to parse '%s' as number"), strings[i]);
g_printerr ("%s\n", msg);
exit (1);
}
g_array_append_val (d, f);
}
g_strfreev (strings);
gsk_stroke_set_dash (stroke, (const float *)d->data, d->len);
g_array_unref (d);
}
gsk_stroke_set_dash_offset (stroke, dash_offset);
result = gsk_path_stroke (path, stroke);
gsk_stroke_free (stroke);
if (result)
{
char *str = gsk_path_to_string (result);
g_print ("%s\n", str);
g_free (str);
}
else
{
g_printerr ("%s\n", _("That didn't work out."));
exit (1);
}
}

View File

@@ -38,6 +38,8 @@ usage (void)
"Perform various tasks on paths.\n"
"\n"
"Commands:\n"
" stroke Stroke the path\n"
" offset Offset the path\n"
" decompose Decompose the path\n"
" transform Transform the path\n"
" reverse Reverse the path\n"
@@ -131,6 +133,8 @@ main (int argc, const char *argv[])
do_decompose (&argc, &argv);
else if (strcmp (argv[0], "info") == 0)
do_info (&argc, &argv);
else if (strcmp (argv[0], "offset") == 0)
do_offset (&argc, &argv);
else if (strcmp (argv[0], "render") == 0)
do_render (&argc, &argv);
else if (strcmp (argv[0], "restrict") == 0)
@@ -139,6 +143,8 @@ main (int argc, const char *argv[])
do_reverse (&argc, &argv);
else if (strcmp (argv[0], "show") == 0)
do_show (&argc, &argv);
else if (strcmp (argv[0], "stroke") == 0)
do_stroke (&argc, &argv);
else if (strcmp (argv[0], "transform") == 0)
do_transform (&argc, &argv);
else

View File

@@ -1,6 +1,8 @@
#pragma once
void do_info (int *argc, const char ***argv);
void do_stroke (int *argc, const char ***argv);
void do_offset (int *argc, const char ***argv);
void do_decompose (int *argc, const char ***argv);
void do_transform (int *argc, const char ***argv);
void do_reverse (int *argc, const char ***argv);

View File

@@ -26,10 +26,12 @@ gtk_tools = [
['gtk4-path-tool', ['gtk-path-tool.c',
'gtk-path-tool-decompose.c',
'gtk-path-tool-info.c',
'gtk-path-tool-offset.c',
'gtk-path-tool-render.c',
'gtk-path-tool-restrict.c',
'gtk-path-tool-reverse.c',
'gtk-path-tool-show.c',
'gtk-path-tool-stroke.c',
'gtk-path-tool-transform.c',
'gtk-path-tool-utils.c',
'path-view.c'], [libgtk_dep]],