/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * pikavectors-compat.c * Copyright (C) 2003 Michael Natterer * * 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 . */ #include "config.h" #include #include #include "vectors-types.h" #include "core/pikaimage.h" #include "pikaanchor.h" #include "pikabezierstroke.h" #include "pikavectors.h" #include "pikavectors-compat.h" enum { PIKA_VECTORS_COMPAT_ANCHOR = 1, PIKA_VECTORS_COMPAT_CONTROL = 2, PIKA_VECTORS_COMPAT_NEW_STROKE = 3 }; static const PikaCoords default_coords = PIKA_COORDS_DEFAULT_VALUES; PikaVectors * pika_vectors_compat_new (PikaImage *image, const gchar *name, PikaVectorsCompatPoint *points, gint n_points, gboolean closed) { PikaVectors *vectors; PikaStroke *stroke; PikaCoords *coords; PikaCoords *curr_stroke; PikaCoords *curr_coord; gint i; g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL); g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (points != NULL || n_points == 0, NULL); g_return_val_if_fail (n_points >= 0, NULL); vectors = pika_vectors_new (image, name); coords = g_new0 (PikaCoords, n_points + 1); curr_stroke = curr_coord = coords; /* skip the first control point, will set it later */ curr_coord++; for (i = 0; i < n_points; i++) { *curr_coord = default_coords; curr_coord->x = points[i].x; curr_coord->y = points[i].y; /* copy the first anchor to be the first control point */ if (curr_coord == curr_stroke + 1) *curr_stroke = *curr_coord; /* found new stroke start */ if (points[i].type == PIKA_VECTORS_COMPAT_NEW_STROKE) { /* copy the last control point to the beginning of the stroke */ *curr_stroke = *(curr_coord - 1); stroke = pika_bezier_stroke_new_from_coords (curr_stroke, curr_coord - curr_stroke - 1, TRUE); pika_vectors_stroke_add (vectors, stroke); g_object_unref (stroke); /* start a new stroke */ curr_stroke = curr_coord - 1; /* copy the first anchor to be the first control point */ *curr_stroke = *curr_coord; } curr_coord++; } if (closed) { /* copy the last control point to the beginning of the stroke */ curr_coord--; *curr_stroke = *curr_coord; } stroke = pika_bezier_stroke_new_from_coords (curr_stroke, curr_coord - curr_stroke, closed); pika_vectors_stroke_add (vectors, stroke); g_object_unref (stroke); g_free (coords); return vectors; } gboolean pika_vectors_compat_is_compatible (PikaImage *image) { GList *list; g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE); for (list = pika_image_get_vectors_iter (image); list; list = g_list_next (list)) { PikaVectors *vectors = PIKA_VECTORS (list->data); GList *strokes; gint open_count = 0; if (pika_item_get_visible (PIKA_ITEM (vectors))) return FALSE; for (strokes = vectors->strokes->head; strokes; strokes = g_list_next (strokes)) { PikaStroke *stroke = PIKA_STROKE (strokes->data); if (! PIKA_IS_BEZIER_STROKE (stroke)) return FALSE; if (!stroke->closed) open_count++; } if (open_count >= 2) return FALSE; } return TRUE; } PikaVectorsCompatPoint * pika_vectors_compat_get_points (PikaVectors *vectors, gint32 *n_points, gint32 *closed) { PikaVectorsCompatPoint *points; GList *strokes; gint i; GList *postponed = NULL; /* for the one open stroke... */ gint open_count; gboolean first_stroke = TRUE; g_return_val_if_fail (PIKA_IS_VECTORS (vectors), NULL); g_return_val_if_fail (n_points != NULL, NULL); g_return_val_if_fail (closed != NULL, NULL); *n_points = 0; *closed = TRUE; open_count = 0; for (strokes = vectors->strokes->head; strokes; strokes = g_list_next (strokes)) { PikaStroke *stroke = strokes->data; gint n_anchors; if (! stroke->closed) { open_count++; postponed = strokes; *closed = FALSE; if (open_count >= 2) { g_warning ("pika_vectors_compat_get_points(): convert failed"); *n_points = 0; return NULL; } } n_anchors = g_queue_get_length (stroke->anchors); if (! stroke->closed) n_anchors--; *n_points += n_anchors; } points = g_new0 (PikaVectorsCompatPoint, *n_points); i = 0; for (strokes = vectors->strokes->head; strokes || postponed; strokes = g_list_next (strokes)) { PikaStroke *stroke; GList *anchors; if (strokes) { if (postponed && strokes == postponed) /* we need to visit the open stroke last... */ continue; else stroke = PIKA_STROKE (strokes->data); } else { stroke = PIKA_STROKE (postponed->data); postponed = NULL; } for (anchors = stroke->anchors->head; anchors; anchors = g_list_next (anchors)) { PikaAnchor *anchor = anchors->data; /* skip the first anchor, will add it at the end if needed */ if (! anchors->prev) continue; switch (anchor->type) { case PIKA_ANCHOR_ANCHOR: if (anchors->prev == stroke->anchors->head && ! first_stroke) points[i].type = PIKA_VECTORS_COMPAT_NEW_STROKE; else points[i].type = PIKA_VECTORS_COMPAT_ANCHOR; break; case PIKA_ANCHOR_CONTROL: points[i].type = PIKA_VECTORS_COMPAT_CONTROL; break; } points[i].x = anchor->position.x; points[i].y = anchor->position.y; i++; /* write the skipped control point */ if (! anchors->next && stroke->closed) { anchor = g_queue_peek_head (stroke->anchors); points[i].type = PIKA_VECTORS_COMPAT_CONTROL; points[i].x = anchor->position.x; points[i].y = anchor->position.y; i++; } } first_stroke = FALSE; } return points; }