Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gimp/app/path/   (Gimp Bildeditor Version 3.2.0©)  Datei vom 14.2.2026 mit Größe 10 kB image not shown  

Quelle  gimppath-export.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */


#include "config.h"

#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>

#include "libgimpbase/gimpbase.h"

#include "path-types.h"

#include "core/gimpimage.h"
#include "core/gimpitem.h"

#include "gimpanchor.h"
#include "gimpbezierstroke.h"
#include "gimppath.h"
#include "gimppath-export.h"
#include "gimpstroke.h"

#include "gimp-intl.h"


static GString * gimp_path_export            (GimpImage   *image,
                                              GList       *paths);
static void      gimp_path_export_image_size (GimpImage   *image,
                                              GString     *str);
static void      gimp_path_export_path       (GimpPath    *paths,
                                              GString     *str,
                                              gint         path_id);
static gchar   * gimp_path_export_path_data  (GimpPath    *paths);


/**
 * gimp_path_export_file:
 * @image: the #GimpImage from which to export
 * @path_list: a #GList of #GimpPath objects or %NULL to export all paths in @image
 * @file: the file to write
 * @error: return location for errors
 *
 * Exports one or more paths to an SVG file aka XML doc.
 *
 * When @path_list is %NULL aka empty list, exports all paths in image.
 *
 * When @path_list is empty and image has no paths,
 * this still writes a non-empty file containing an XML doc.
 *
 * Will overwrite any existing file.
 *
 * Returns: %TRUE on success,
 *          %FALSE when there was an error writing the file
 **/

gboolean
gimp_path_export_file (GimpImage    *image,
                          GList     *path_list,
                          GFile     *file,
                          GError   **error)
{
  GOutputStream *output;
  GString       *string;
  GError        *my_error = NULL;

  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
  g_return_val_if_fail (G_IS_FILE (file), FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  output = G_OUTPUT_STREAM (g_file_replace (file,
                                            NULL, FALSE, G_FILE_CREATE_NONE,
                                            NULL, error));
  if (! output)
    return FALSE;

  string = gimp_path_export (image, path_list);

  if (! g_output_stream_write_all (output, string->str, string->len,
                                   NULL, NULL, &my_error))
    {
      GCancellable *cancellable = g_cancellable_new ();

      g_set_error (error, my_error->domain, my_error->code,
                   _("Writing SVG file '%s' failed: %s"),
                   gimp_file_get_utf8_name (file), my_error->message);
      g_clear_error (&my_error);
      g_string_free (string, TRUE);

      /* Cancel the overwrite initiated by g_file_replace(). */
      g_cancellable_cancel (cancellable);
      g_output_stream_close (output, cancellable, NULL);
      g_object_unref (cancellable);
      g_object_unref (output);

      return FALSE;
    }

  g_string_free (string, TRUE);
  g_object_unref (output);

  return TRUE;
}

/**
 * gimp_path_export_string:
 * @image: the #GimpImage from which to export
 * @path_list: a #GList of #GimpPath objects, or %NULL to export all paths in @image
 *
 * Exports one or more paths to a SVG string.
 *
 * When @path_list is %NULL aka empty list, exports all paths in image.
 *
 * When @path_list is empty and image has no paths,
 * this still returns a string for an empty XML doc.
 *
 * Returns: a NULL-terminated string that holds a complete XML document
 **/

gchar *
gimp_path_export_string (GimpImage *image,
                         GList     *path_list)
{
  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);

  return g_string_free (gimp_path_export (image, path_list), FALSE);
}

static GString *
gimp_path_export (GimpImage *image,
                  GList     *path)
{
  GString *str     = g_string_new (NULL);
  gint     path_id = 1;
  GList   *list;

  g_string_append_printf (str,
                          "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
                          "<svg xmlns=\"http://www.w3.org/2000/svg\"\n"
                          "     xmlns:svg=\"http://www.w3.org/2000/svg\"\n"
                          "     version=\"1.1\"\n");

  g_string_append (str, "     ");
  gimp_path_export_image_size (image, str);
  g_string_append_c (str, '\n');

  g_string_append_printf (str,
                          "     viewBox=\"0 0 %d %d\">\n",
                          gimp_image_get_width  (image),
                          gimp_image_get_height (image));

  if (! path)
    path = gimp_image_get_path_iter (image);

  for (list = path; list; list = list->next)
    gimp_path_export_path (GIMP_PATH (list->data), str, path_id++);

  g_string_append (str, "</svg>\n");

  return str;
}

static void
gimp_path_export_image_size (GimpImage *image,
                             GString   *str)
{
  GimpUnit    *unit;
  const gchar *abbrev;
  gchar        wbuf[G_ASCII_DTOSTR_BUF_SIZE];
  gchar        hbuf[G_ASCII_DTOSTR_BUF_SIZE];
  gdouble      xres;
  gdouble      yres;
  gdouble      w, h;

  gimp_image_get_resolution (image, &xres, &yres);

  w = (gdouble) gimp_image_get_width  (image) / xres;
  h = (gdouble) gimp_image_get_height (image) / yres;

  /*  FIXME: should probably use the display unit here  */
  unit = gimp_image_get_unit (image);
  switch (gimp_unit_get_id (unit))
    {
    case GIMP_UNIT_INCH:  abbrev = "in";  break;
    case GIMP_UNIT_MM:    abbrev = "mm";  break;
    case GIMP_UNIT_POINT: abbrev = "pt";  break;
    case GIMP_UNIT_PICA:  abbrev = "pc";  break;
    default:              abbrev = "cm";
      unit = gimp_unit_mm ();
      w /= 10.0;
      h /= 10.0;
      break;
    }

  g_ascii_formatd (wbuf, sizeof (wbuf), "%g", w * gimp_unit_get_factor (unit));
  g_ascii_formatd (hbuf, sizeof (hbuf), "%g", h * gimp_unit_get_factor (unit));

  g_string_append_printf (str,
                          "width=\"%s%s\" height=\"%s%s\"",
                          wbuf, abbrev, hbuf, abbrev);
}

static void
gimp_path_export_path (GimpPath *path,
                       GString  *str,
                       gint      path_id)
{
  const gchar *name = gimp_object_get_name (path);
  gchar       *data = gimp_path_export_path_data (path);
  gchar       *id;
  gchar       *esc_name;

  /* SVG specification states the id attribute must not contain whitespace.
   * Rather than filter user names, we'll just define a generic,
   * auto-incrementing id. */

  id       = g_strdup_printf ("path%d", path_id);
  esc_name = g_markup_escape_text (name, strlen (name));

  g_string_append_printf (str,
                          "  <path id=\"%s\"\n"
                          "        fill=\"none\" stroke=\"black\" stroke-width=\"1\"\n"
                          "        d=\"%s\">\n"
                          "        <title>%s</title>\n"
                          "  </path>\n",
                          id, data, esc_name);

  g_free (id);
  g_free (esc_name);
  g_free (data);
}


#define NEWLINE "\n           "

static gchar *
gimp_path_export_path_data (GimpPath *path)
{
  GString  *str;
  GList    *strokes;
  gchar     x_string[G_ASCII_DTOSTR_BUF_SIZE];
  gchar     y_string[G_ASCII_DTOSTR_BUF_SIZE];
  gboolean  closed = FALSE;

  str = g_string_new (NULL);

  for (strokes = path->strokes->head;
       strokes;
       strokes = strokes->next)
    {
      GimpStroke *stroke = strokes->data;
      GArray     *control_points;
      GimpAnchor *anchor;
      gint        i;

      if (closed)
        g_string_append_printf (str, NEWLINE);

      control_points = gimp_stroke_control_points_get (stroke, &closed);

      if (GIMP_IS_BEZIER_STROKE (stroke))
        {
          if (control_points->len >= 3)
            {
              anchor = &g_array_index (control_points, GimpAnchor, 1);
              g_ascii_formatd (x_string, G_ASCII_DTOSTR_BUF_SIZE,
                               "%.2f", anchor->position.x);
              g_ascii_formatd (y_string, G_ASCII_DTOSTR_BUF_SIZE,
                               "%.2f", anchor->position.y);
              g_string_append_printf (str, "M %s,%s", x_string, y_string);
            }

          if (control_points->len > 3)
            {
              g_string_append_printf (str, NEWLINE "C");
            }

          for (i = 2; i < (control_points->len + (closed ? 2 : - 1)); i++)
            {
              if (i > 2 && i % 3 == 2)
                g_string_append_printf (str, NEWLINE " ");

              anchor = &g_array_index (control_points, GimpAnchor,
                                       i % control_points->len);
              g_ascii_formatd (x_string, G_ASCII_DTOSTR_BUF_SIZE,
                               "%.2f", anchor->position.x);
              g_ascii_formatd (y_string, G_ASCII_DTOSTR_BUF_SIZE,
                               "%.2f", anchor->position.y);
              g_string_append_printf (str, " %s,%s", x_string, y_string);
            }

          if (closed && control_points->len > 3)
            g_string_append_printf (str, " Z");
        }
      else
        {
          g_printerr ("Unknown stroke type\n");

          if (control_points->len >= 1)
            {
              anchor = &g_array_index (control_points, GimpAnchor, 0);
              g_ascii_formatd (x_string, G_ASCII_DTOSTR_BUF_SIZE,
                               ".2f", anchor->position.x);
              g_ascii_formatd (y_string, G_ASCII_DTOSTR_BUF_SIZE,
                               ".2f", anchor->position.y);
              g_string_append_printf (str, "M %s,%s", x_string, y_string);
            }

          if (control_points->len > 1)
            {
              g_string_append_printf (str, NEWLINE "L");
            }

          for (i = 1; i < control_points->len; i++)
            {
              if (i > 1 && i % 3 == 1)
                g_string_append_printf (str, NEWLINE " ");

              anchor = &g_array_index (control_points, GimpAnchor, i);
              g_ascii_formatd (x_string, G_ASCII_DTOSTR_BUF_SIZE,
                               "%.2f", anchor->position.x);
              g_ascii_formatd (y_string, G_ASCII_DTOSTR_BUF_SIZE,
                               "%.2f", anchor->position.y);
              g_string_append_printf (str, " %s,%s", x_string, y_string);
            }

          if (closed && control_points->len > 1)
            g_string_append_printf (str, " Z");
        }

      g_array_free (control_points, TRUE);
    }

  return g_strchomp (g_string_free (str, FALSE));
}

Messung
CHZG
859710094

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.