# PIKA - Photo and Image Kooker Application # 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 . sub vectors_new { $blurb = 'Creates a new empty vectors object.'; $help = <<'HELP'; Creates a new empty vectors object. The vectors object needs to be added to the image using pika_image_insert_vectors(). HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'image', type => 'image', desc => 'The image' }, { name => 'name', type => 'string', desc => 'the name of the new vector object.' } ); @outargs = ( { name => 'vectors', type => 'vectors', desc => 'the current vector object, 0 if no vector exists in the image.' } ); %invoke = ( code => <<'CODE' { vectors = pika_vectors_new (image, name); } CODE ); } sub vectors_new_from_text_layer { $blurb = 'Creates a new vectors object from a text layer.'; $help = <<'HELP'; Creates a new vectors object from a text layer. The vectors object needs to be added to the image using pika_image_insert_vectors(). HELP &marcus_pdb_misc('2008', '2.6'); @inargs = ( { name => 'image', type => 'image', desc => 'The image.' }, { name => 'layer', type => 'layer', desc => 'The text layer.' } ); @outargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors of the text layer.' } ); %invoke = ( code => <<'CODE' { if (pika_pdb_layer_is_text_layer (layer, 0, error)) { gint x, y; vectors = pika_text_vectors_new (image, pika_text_layer_get_text (PIKA_TEXT_LAYER (layer))); pika_item_get_offset (PIKA_ITEM (layer), &x, &y); pika_item_translate (PIKA_ITEM (vectors), x, y, FALSE); } else { success = FALSE; } } CODE ); } sub vectors_copy { $blurb = 'Copy a vectors object.'; $help = <<'HELP'; This procedure copies the specified vectors object and returns the copy. HELP barak_pdb_misc('2008', '2.6'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object to copy' } ); @outargs = ( { name => 'vectors_copy', type => 'vectors', desc => 'The newly copied vectors object' } ); %invoke = ( code => <<'CODE' { vectors_copy = PIKA_VECTORS (pika_item_duplicate (PIKA_ITEM (vectors), G_TYPE_FROM_INSTANCE (vectors))); if (! vectors_copy) success = FALSE; } CODE ); } sub vectors_get_strokes { $blurb = 'List the strokes associated with the passed path.'; $help = <<'HELP'; Returns an Array with the stroke-IDs associated with the passed path. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' } ); @outargs = ( { name => 'stroke_ids', type => 'int32array', desc => 'List of the strokes belonging to the path.', array => { name => 'num_strokes', desc => 'The number of strokes returned.' } } ); %invoke = ( code => <<"CODE" { num_strokes = pika_vectors_get_n_strokes (vectors); if (num_strokes) { PikaStroke *cur_stroke; gint i = 0; stroke_ids = g_new (gint32, num_strokes); for (cur_stroke = pika_vectors_stroke_get_next (vectors, NULL); cur_stroke; cur_stroke = pika_vectors_stroke_get_next (vectors, cur_stroke)) { stroke_ids[i] = pika_stroke_get_id (cur_stroke); i++; } } } CODE ); } sub vectors_stroke_get_length { $blurb = 'Measure the length of the given stroke.'; $help = 'Measure the length of the given stroke.'; &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' }, { name => 'precision', type => '0.0 <= float', default => 0.1, desc => 'The precision used for approximating straight portions of the stroke' } ); @outargs = ( { name => 'length', type => 'float', desc => 'The length (in pixels) of the given stroke.' } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, 0, error); if (stroke) length = pika_stroke_get_length (stroke, precision); else success = FALSE; } CODE ); } sub vectors_stroke_get_point_at_dist { $blurb = 'Get point at a specified distance along the stroke.'; $help = <<'HELP'; This will return the x,y position of a point at a given distance along the stroke. The distance will be obtained by first digitizing the curve internally and then walking along the curve. For a closed stroke the start of the path is the first point on the path that was created. This might not be obvious. If the stroke is not long enough, a "valid" flag will be FALSE. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' }, { name => 'dist', type => 'float', desc => 'The given distance.' }, { name => 'precision', type => 'float', desc => 'The precision used for the approximation' } ); @outargs = ( { name => 'x_point', type => 'float', void_ret => 1, desc => 'The x position of the point.' }, { name => 'y_point', type => 'float', desc => 'The y position of the point.' }, { name => 'slope', type => 'float', desc => 'The slope (dy / dx) at the specified point.' }, { name => 'valid', type => 'boolean', desc => 'Indicator for the validity of the returned data.' } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, 0, error); if (stroke) { PikaCoords coord; valid = pika_stroke_get_point_at_dist (stroke, dist, precision, &coord, &slope); x_point = valid ? coord.x : 0; y_point = valid ? coord.y : 0; } else success = FALSE; } CODE ); } sub vectors_remove_stroke { $blurb = 'remove the stroke from a vectors object.'; $help = <<'HELP'; Remove the stroke from a vectors object. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, PIKA_PDB_ITEM_CONTENT, error); if (stroke) { if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Remove path stroke"), vectors); pika_vectors_stroke_remove (vectors, stroke); } else success = FALSE; } CODE ); } sub vectors_stroke_close { $blurb = 'closes the specified stroke.'; $help = <<'HELP'; Closes the specified stroke. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, PIKA_PDB_ITEM_CONTENT, error); if (stroke) { if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Close path stroke"), vectors); pika_vectors_freeze (vectors); pika_stroke_close (stroke); pika_vectors_thaw (vectors); } else success = FALSE; } CODE ); } sub vectors_stroke_reverse { $blurb = 'reverses the specified stroke.'; $help = <<'HELP'; Reverses the specified stroke. HELP &simon_pdb_misc('2020', '3.0'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, PIKA_PDB_ITEM_CONTENT, error); if (stroke) { if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Reverse path stroke"), vectors); pika_vectors_freeze (vectors); pika_stroke_reverse (stroke); pika_vectors_thaw (vectors); } else success = FALSE; } CODE ); } sub vectors_stroke_translate { $blurb = 'translate the given stroke.'; $help = <<'HELP'; Translate the given stroke. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' }, { name => "off_x", type => 'float', desc => "Offset in x direction" }, { name => "off_y", type => 'float', desc => "Offset in y direction" } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, PIKA_PDB_ITEM_CONTENT | PIKA_PDB_ITEM_POSITION, error); if (stroke) { if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Translate path stroke"), vectors); pika_vectors_freeze (vectors); pika_stroke_translate (stroke, off_x, off_y); pika_vectors_thaw (vectors); } else success = FALSE; } CODE ); } sub vectors_stroke_scale { $blurb = 'scales the given stroke.'; $help = <<'HELP'; Scale the given stroke. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' }, { name => "scale_x", type => 'float', desc => "Scale factor in x direction" }, { name => "scale_y", type => 'float', desc => "Scale factor in y direction" } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, PIKA_PDB_ITEM_CONTENT | PIKA_PDB_ITEM_POSITION, error); if (stroke) { if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Scale path stroke"), vectors); pika_vectors_freeze (vectors); pika_stroke_scale (stroke, scale_x, scale_y); pika_vectors_thaw (vectors); } else success = FALSE; } CODE ); } sub vectors_stroke_rotate { $blurb = 'rotates the given stroke.'; $help = <<'HELP'; Rotates the given stroke around given center by angle (in degrees). HELP &joao_pdb_misc('2006', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' }, { name => "center_x", type => 'float', desc => "X coordinate of the rotation center" }, { name => "center_y", type => 'float', desc => "Y coordinate of the rotation center" }, { name => "angle", type => 'float', desc => "angle to rotate about" } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, PIKA_PDB_ITEM_CONTENT | PIKA_PDB_ITEM_POSITION, error); if (stroke) { if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Rotate path stroke"), vectors); pika_vectors_freeze (vectors); pika_stroke_rotate (stroke, center_x, center_y, angle); pika_vectors_thaw (vectors); } else success = FALSE; } CODE ); } sub vectors_stroke_flip { $blurb = 'flips the given stroke.'; $help = <<'HELP'; Rotates the given stroke around given center by angle (in degrees). HELP &joao_pdb_misc('2006', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' }, { name => "flip_type", type => 'enum PikaOrientationType (no PIKA_ORIENTATION_UNKNOWN)', desc => "Flip orientation, either vertical or horizontal" }, { name => "axis", type => 'float', desc => "axis coordinate about which to flip, in pixels" } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, PIKA_PDB_ITEM_CONTENT | PIKA_PDB_ITEM_POSITION, error); if (stroke) { if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Flip path stroke"), vectors); pika_vectors_freeze (vectors); pika_stroke_flip (stroke, flip_type, axis); pika_vectors_thaw (vectors); } else success = FALSE; } CODE ); } sub vectors_stroke_flip_free { $blurb = 'flips the given stroke about an arbitrary axis.'; $help = <<'HELP'; Flips the given stroke about an arbitrary axis. Axis is defined by two coordinates in the image (in pixels), through which the flipping axis passes. HELP &joao_pdb_misc('2006', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' }, { name => "x1", type => 'float', desc => "X coordinate of the first point of the flipping axis" }, { name => "y1", type => 'float', desc => "Y coordinate of the first point of the flipping axis" }, { name => "x2", type => 'float', desc => "X coordinate of the second point of the flipping axis" }, { name => "y2", type => 'float', desc => "Y coordinate of the second point of the flipping axis" }, ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, PIKA_PDB_ITEM_CONTENT | PIKA_PDB_ITEM_POSITION, error); if (stroke) { if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Flip path stroke"), vectors); pika_vectors_freeze (vectors); pika_stroke_flip_free (stroke, x1, y1, x2, y2); pika_vectors_thaw (vectors); } else success = FALSE; } CODE ); } sub vectors_stroke_get_points { $blurb = 'returns the control points of a stroke.'; $help = <<'HELP'; returns the control points of a stroke. The interpretation of the coordinates returned depends on the type of the stroke. For Pika 2.4 this is always a bezier stroke, where the coordinates are the control points. HELP &simon_pdb_misc('2006', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' } ); @outargs = ( { name => 'type', type => 'enum PikaVectorsStrokeType', desc => 'type of the stroke (always PIKA_VECTORS_STROKE_TYPE_BEZIER for now).' }, { name => 'controlpoints', type => 'floatarray', desc => 'List of the control points for the stroke (x0, y0, x1, y1, ...).', array => { name => 'num_points', desc => 'The number of floats returned.' } }, { name => 'closed', type => 'boolean', desc => 'Whether the stroke is closed or not.' } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, 0, error); if (PIKA_IS_BEZIER_STROKE (stroke)) { GArray *points_array; gint i; points_array = pika_stroke_control_points_get (stroke, &closed); if (points_array) { num_points = points_array->len; controlpoints = g_new (gdouble, num_points * 2); type = PIKA_VECTORS_STROKE_TYPE_BEZIER; for (i = 0; i < num_points; i++) { controlpoints[2*i] = g_array_index (points_array, PikaAnchor, i).position.x; controlpoints[2*i+1] = g_array_index (points_array, PikaAnchor, i).position.y; } g_array_free (points_array, TRUE); num_points *= 2; } else success = FALSE; } else success = FALSE; } CODE ); } sub vectors_stroke_interpolate { $blurb = 'returns polygonal approximation of the stroke.'; $help = <<'HELP'; returns polygonal approximation of the stroke. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' }, { name => 'precision', type => 'float', desc => 'The precision used for the approximation' } ); @outargs = ( { name => 'coords', type => 'floatarray', desc => 'List of the coords along the path (x0, y0, x1, y1, ...).', array => { name => 'num_coords', desc => 'The number of floats returned.' } }, { name => 'closed', type => 'boolean', desc => 'Whether the stroke is closed or not.' } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, 0, error); if (stroke) { GArray *coords_array; gint i; coords_array = pika_stroke_interpolate (stroke, precision, &closed); if (coords_array) { num_coords = coords_array->len; coords = g_new (gdouble, num_coords * 2); for (i = 0; i < num_coords; i++) { coords[2*i] = g_array_index (coords_array, PikaCoords, i).x; coords[2*i+1] = g_array_index (coords_array, PikaCoords, i).y; } g_array_free (coords_array, TRUE); num_coords *= 2; } else success = FALSE; } else success = FALSE; } CODE ); } sub vectors_stroke_new_from_points { $blurb = 'Adds a stroke of a given type to the vectors object.'; $help = <<'HELP'; Adds a stroke of a given type to the vectors object. The coordinates of the control points can be specified. For now only strokes of the type PIKA_VECTORS_STROKE_TYPE_BEZIER are supported. The control points are specified as a pair of float values for the x- and y-coordinate. The Bezier stroke type needs a multiple of three control points. Each Bezier segment endpoint (anchor, A) has two additional control points (C) associated. They are specified in the order CACCACCAC... HELP &simon_pdb_misc('2006', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'type', type => 'enum PikaVectorsStrokeType', desc => 'type of the stroke (always PIKA_VECTORS_STROKE_TYPE_BEZIER for now).' }, { name => 'controlpoints', type => 'floatarray', desc => 'List of the x- and y-coordinates of the control points.', array => { name => 'num_points', desc => 'The number of elements in the array, i.e. the number of controlpoints in the stroke * 2 (x- and y-coordinate).' } }, { name => 'closed', type => 'boolean', desc => 'Whether the stroke is to be closed or not.' } ); @outargs = ( { name => 'stroke_id', type => 'int32', desc => 'The stroke ID of the newly created stroke.' } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke; PikaCoords *coords; PikaCoords default_coords = PIKA_COORDS_DEFAULT_VALUES; gint i; success = FALSE; if (type == PIKA_VECTORS_STROKE_TYPE_BEZIER && num_points % 6 == 0) { coords = g_new (PikaCoords, num_points/2); for (i = 0; i < num_points/2; i++) { coords[i] = default_coords; coords[i].x = controlpoints[i*2]; coords[i].y = controlpoints[i*2+1]; } stroke = pika_stroke_new_from_coords (type, coords, num_points/2, closed); if (stroke) { if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Add path stroke"), vectors); pika_vectors_stroke_add (vectors, stroke); g_object_unref (stroke); stroke_id = pika_stroke_get_id (stroke); success = TRUE; } g_free (coords); } } CODE ); } sub vectors_bezier_stroke_new_moveto { $blurb = 'Adds a bezier stroke with a single moveto to the vectors object.'; $help = <<'HELP'; Adds a bezier stroke with a single moveto to the vectors object. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'x0', type => 'float', desc => 'The x-coordinate of the moveto' }, { name => 'y0', type => 'float', desc => 'The y-coordinate of the moveto' } ); @outargs = ( { name => 'stroke_id', type => 'int32', desc => 'The resulting stroke' } ); %invoke = ( code => <<"CODE" { if (pika_pdb_item_is_modifiable (PIKA_ITEM (vectors), PIKA_PDB_ITEM_CONTENT, error) && pika_pdb_item_is_not_group (PIKA_ITEM (vectors), error)) { PikaStroke *stroke; PikaCoords coord0 = PIKA_COORDS_DEFAULT_VALUES; coord0.x = x0; coord0.y = y0; stroke = pika_bezier_stroke_new_moveto (&coord0); if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Add path stroke"), vectors); pika_vectors_stroke_add (vectors, stroke); g_object_unref (stroke); stroke_id = pika_stroke_get_id (stroke); } else success = FALSE; } CODE ); } sub vectors_bezier_stroke_lineto { $blurb = 'Extends a bezier stroke with a lineto.'; $help = <<'HELP'; Extends a bezier stroke with a lineto. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' }, { name => 'x0', type => 'float', desc => 'The x-coordinate of the lineto' }, { name => 'y0', type => 'float', desc => 'The y-coordinate of the lineto' } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, PIKA_PDB_ITEM_CONTENT, error); if (stroke) { PikaCoords coord0 = PIKA_COORDS_DEFAULT_VALUES; coord0.x = x0; coord0.y = y0; if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Extend path stroke"), vectors); pika_vectors_freeze (vectors); pika_bezier_stroke_lineto (stroke, &coord0); pika_vectors_thaw (vectors); } else success = FALSE; } CODE ); } sub vectors_bezier_stroke_conicto { $blurb = 'Extends a bezier stroke with a conic bezier spline.'; $help = <<'HELP'; Extends a bezier stroke with a conic bezier spline. Actually a cubic bezier spline gets added that realizes the shape of a conic bezier spline. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' }, { name => 'x0', type => 'float', desc => 'The x-coordinate of the control point' }, { name => 'y0', type => 'float', desc => 'The y-coordinate of the control point' }, { name => 'x1', type => 'float', desc => 'The x-coordinate of the end point' }, { name => 'y1', type => 'float', desc => 'The y-coordinate of the end point' } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, PIKA_PDB_ITEM_CONTENT, error); if (stroke) { PikaCoords coord0 = PIKA_COORDS_DEFAULT_VALUES; PikaCoords coord1 = PIKA_COORDS_DEFAULT_VALUES; coord0.x = x0; coord0.y = y0; coord1.x = x1; coord1.y = y1; if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Extend path stroke"), vectors); pika_vectors_freeze (vectors); pika_bezier_stroke_conicto (stroke, &coord0, &coord1); pika_vectors_thaw (vectors); } else success = FALSE; } CODE ); } sub vectors_bezier_stroke_cubicto { $blurb = 'Extends a bezier stroke with a cubic bezier spline.'; $help = <<'HELP'; Extends a bezier stroke with a cubic bezier spline. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'stroke_id', type => 'int32', desc => 'The stroke ID' }, { name => 'x0', type => 'float', desc => 'The x-coordinate of the first control point' }, { name => 'y0', type => 'float', desc => 'The y-coordinate of the first control point' }, { name => 'x1', type => 'float', desc => 'The x-coordinate of the second control point' }, { name => 'y1', type => 'float', desc => 'The y-coordinate of the second control point' }, { name => 'x2', type => 'float', desc => 'The x-coordinate of the end point' }, { name => 'y2', type => 'float', desc => 'The y-coordinate of the end point' } ); %invoke = ( code => <<"CODE" { PikaStroke *stroke = pika_pdb_get_vectors_stroke (vectors, stroke_id, PIKA_PDB_ITEM_CONTENT, error); if (stroke) { PikaCoords coord0 = PIKA_COORDS_DEFAULT_VALUES; PikaCoords coord1 = PIKA_COORDS_DEFAULT_VALUES; PikaCoords coord2 = PIKA_COORDS_DEFAULT_VALUES; coord0.x = x0; coord0.y = y0; coord1.x = x1; coord1.y = y1; coord2.x = x2; coord2.y = y2; if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Extend path stroke"), vectors); pika_vectors_freeze (vectors); pika_bezier_stroke_cubicto (stroke, &coord0, &coord1, &coord2); pika_vectors_thaw (vectors); } else success = FALSE; } CODE ); } sub vectors_bezier_stroke_new_ellipse { $blurb = 'Adds a bezier stroke describing an ellipse the vectors object.'; $help = <<'HELP'; Adds a bezier stroke describing an ellipse the vectors object. HELP &simon_pdb_misc('2005', '2.4'); @inargs = ( { name => 'vectors', type => 'vectors', desc => 'The vectors object' }, { name => 'x0', type => 'float', desc => 'The x-coordinate of the center' }, { name => 'y0', type => 'float', desc => 'The y-coordinate of the center' }, { name => 'radius_x', type => 'float', desc => 'The radius in x direction' }, { name => 'radius_y', type => 'float', desc => 'The radius in y direction' }, { name => 'angle', type => 'float', desc => 'The angle the x-axis of the ellipse (radians, counterclockwise)' } ); @outargs = ( { name => 'stroke_id', type => 'int32', desc => 'The resulting stroke' } ); %invoke = ( code => <<"CODE" { if (pika_pdb_item_is_modifiable (PIKA_ITEM (vectors), PIKA_PDB_ITEM_CONTENT, error) && pika_pdb_item_is_not_group (PIKA_ITEM (vectors), error)) { PikaStroke *stroke; PikaCoords coord0 = PIKA_COORDS_DEFAULT_VALUES; coord0.x = x0; coord0.y = y0; stroke = pika_bezier_stroke_new_ellipse (&coord0, radius_x, radius_y, angle); if (pika_item_is_attached (PIKA_ITEM (vectors))) pika_image_undo_push_vectors_mod (pika_item_get_image (PIKA_ITEM (vectors)), _("Add path stroke"), vectors); pika_vectors_stroke_add (vectors, stroke); g_object_unref (stroke); stroke_id = pika_stroke_get_id (stroke); } else success = FALSE; } CODE ); } sub vectors_import_from_file { $blurb = 'Import paths from an SVG file.'; $help = <<'HELP'; This procedure imports paths from an SVG file. SVG elements other than paths and basic shapes are ignored. HELP &simon_pdb_misc('2006', '2.4'); @inargs = ( { name => 'image', type => 'image', desc => 'The image' }, { name => 'file', type => 'file', desc => 'The SVG file to import.' }, { name => 'merge', type => 'boolean', desc => 'Merge paths into a single vectors object.' }, { name => 'scale', type => 'boolean', desc => 'Scale the SVG to image dimensions.' } ); @outargs = ( { name => 'vectors', type => 'vectorarray', void_ret => 1, desc => 'The list of newly created vectors', array => { name => 'num_vectors', desc => 'The number of newly created vectors' } } ); %invoke = ( headers => [ qw("vectors/pikavectors-import.h") ], code => <<'CODE' { GList *vectors_list = NULL; /* FIXME tree */ success = pika_vectors_import_file (image, file, merge, scale, NULL, -1, &vectors_list, error); if (success) { num_vectors = g_list_length (vectors_list); if (num_vectors) { GList *list; gint i; vectors = g_new (PikaVectors *, num_vectors); for (i = 0, list = vectors_list; i < num_vectors; i++, list = g_list_next (list)) { vectors[i] = g_object_ref (list->data); } g_list_free (vectors_list); } } } CODE ); } sub vectors_import_from_string { $blurb = 'Import paths from an SVG string.'; $help = <<'HELP'; This procedure works like pika_vectors_import_from_file() but takes a string rather than reading the SVG from a file. This allows you to write scripts that generate SVG and feed it to PIKA. HELP &simon_pdb_misc('2006', '2.4'); @inargs = ( { name => 'image', type => 'image', desc => 'The image' }, { name => 'string', type => 'string', allow_non_utf8 => 1, desc => 'A string that must be a complete and valid SVG document.' }, { name => 'length', type => 'int32', desc => 'Number of bytes in string or -1 if the string is NULL terminated.' }, { name => 'merge', type => 'boolean', desc => 'Merge paths into a single vectors object.' }, { name => 'scale', type => 'boolean', desc => 'Scale the SVG to image dimensions.' } ); @outargs = ( { name => 'vectors', type => 'vectorarray', void_ret => 1, desc => 'The list of newly created vectors', array => { name => 'num_vectors', desc => 'The number of newly created vectors' } } ); %invoke = ( headers => [ qw("vectors/pikavectors-import.h") ], code => <<'CODE' { GList *vectors_list = NULL; /* FIXME tree */ success = pika_vectors_import_buffer (image, string, length, merge, scale, NULL, -1, &vectors_list, error); if (success) { num_vectors = g_list_length (vectors_list); if (num_vectors) { GList *list; gint i; vectors = g_new (PikaVectors *, num_vectors); for (i = 0, list = vectors_list; i < num_vectors; i++, list = g_list_next (list)) { vectors[i] = g_object_ref (list->data); } g_list_free (vectors_list); } } } CODE ); } sub vectors_export_to_file { $blurb = 'save a path as an SVG file.'; $help = <<'HELP'; This procedure creates an SVG file to save a Vectors object, that is, a path. The resulting file can be edited using a vector graphics application, or later reloaded into PIKA. Pass %NULL as the 'vectors' argument to export all paths in the image. HELP &bill_pdb_misc('2007', '2.6'); @inargs = ( { name => 'image', type => 'image', desc => 'The image' }, { name => 'file', type => 'file', desc => 'The SVG file to create.' }, { name => 'vectors', type => 'vectors', no_validate => 1, desc => 'The vectors object to export, or %NULL for all in the image' } ); %invoke = ( headers => [ qw("vectors/pikavectors-export.h") ], code => <<'CODE' { GList *vectors_list = NULL; if (vectors != NULL) vectors_list = g_list_prepend (vectors_list, vectors); success = pika_vectors_export_file (image, vectors_list, file, error); g_list_free (vectors_list); } CODE ); } sub vectors_export_to_string { $blurb = 'Save a path as an SVG string.'; $help = <<'HELP'; This procedure works like pika_vectors_export_to_file() but creates a string rather than a file. The string is NULL-terminated and holds a complete XML document. Pass %NULL as the 'vectors' argument to export all paths in the image. HELP &bill_pdb_misc('2007', '2.6'); @inargs = ( { name => 'image', type => 'image', desc => 'The image' }, { name => 'vectors', type => 'vectors', no_validate => 1, desc => 'The vectors object to export, or %NULL for all in the image' } ); @outargs = ( { name => 'string', type => 'string', desc => 'A string whose contents are a complete SVG document.' } ); %invoke = ( headers => [ qw("vectors/pikavectors-export.h") ], code => <<'CODE' { GList *vectors_list = NULL; if (vectors != NULL) vectors_list = g_list_prepend (vectors_list, vectors); string = pika_vectors_export_string (image, vectors_list); g_list_free (vectors_list); success = (string != NULL); } CODE ); } @headers = qw( "core/pikalist.h" "core/pikaimage.h" "core/pikaimage-undo-push.h" "text/pikatext-vectors.h" "text/pikatextlayer.h" "vectors/pikaanchor.h" "vectors/pikastroke-new.h" "vectors/pikabezierstroke.h" "vectors/pikavectors.h" "pikapdb-utils.h" "pika-intl.h"); @procs = qw(vectors_new vectors_new_from_text_layer vectors_copy vectors_get_strokes vectors_stroke_get_length vectors_stroke_get_point_at_dist vectors_remove_stroke vectors_stroke_close vectors_stroke_reverse vectors_stroke_translate vectors_stroke_scale vectors_stroke_rotate vectors_stroke_flip vectors_stroke_flip_free vectors_stroke_get_points vectors_stroke_new_from_points vectors_stroke_interpolate vectors_bezier_stroke_new_moveto vectors_bezier_stroke_lineto vectors_bezier_stroke_conicto vectors_bezier_stroke_cubicto vectors_bezier_stroke_new_ellipse vectors_import_from_file vectors_import_from_string vectors_export_to_file vectors_export_to_string); %exports = (app => [@procs], lib => [@procs]); $desc = 'Vectors'; $doc_title = 'pikavectors'; $doc_short_desc = 'Functions for querying and manipulating vectors.'; $doc_long_desc = 'Functions for querying and manipulating vectors.'; 1;