home *** CD-ROM | disk | FTP | other *** search
- /* pxl-outline.c: find the edges of the bitmap image; we call each such
- edge an ``outline''; each outline is made up of one or more pixels;
- and each pixel participates via one or more edges.
-
- Copyright (C) 1992 Free Software Foundation, Inc.
-
- 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 2, 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include <stdlib.h>
- #include "global.h"
- #include "sel2path.h"
- #include "bitmap.h"
- #include "edge.h"
- #include "pxl-outline.h"
-
- static pixel_outline_type find_one_outline (edge_type,
- unsigned, unsigned, bitmap_type *);
- static void append_pixel_outline (pixel_outline_list_type *,
- pixel_outline_type);
- static pixel_outline_type new_pixel_outline (void);
- static void append_outline_pixel (pixel_outline_type *, coordinate_type);
- static void append_coordinate (pixel_outline_type *, int, int, edge_type);
-
-
- static bitmap_type
- local_new_bitmap (unsigned width,unsigned height)
- {
- bitmap_type answer;
- unsigned size = width * height;
-
-
- BITMAP_HEIGHT(answer) = height;
- BITMAP_WIDTH(answer) = width;
-
- BITMAP_BITS (answer) = g_new0 (one_byte, size); /* g_new returns NULL if size == 0 */
-
- /* printf("local_new_bitmap size = %d @[%p]\n",size,BITMAP_BITS (answer)); */
-
- return answer;
- }
-
- static void
- local_free_bitmap (bitmap_type *b)
- {
- if (BITMAP_BITS (*b) != NULL)
- safe_free ((address *) &BITMAP_BITS (*b));
- }
-
- /* A character is made up of a list of one or more outlines. Here, we
- go through a character's bitmap top to bottom, left to right, looking
- for the next pixel with an unmarked edge also on the character's outline.
- Each one of these we find is the starting place for one outline. We
- find these outlines and put them in a list to return. */
-
- pixel_outline_list_type
- find_outline_pixels ()
- {
- pixel_outline_list_type outline_list;
- unsigned row, col;
- gint height;
- gint width;
- bitmap_type marked = local_new_bitmap (sel_get_width(),sel_get_height());
-
- /* printf("width = %d, height = %d\n",BITMAP_WIDTH(marked),BITMAP_HEIGHT(marked)); */
-
- gimp_progress_init ("Selection to path...");
-
- O_LIST_LENGTH (outline_list) = 0;
- outline_list.data = NULL;
-
- height = sel_get_height ();
- width = sel_get_width ();
-
- for (row = 0; row < height; row++)
- {
- for (col = 0; col < width; col++)
- {
- edge_type edge;
-
- if (sel_pixel_is_white(row, col))
- continue;
-
- edge = next_unmarked_outline_edge (row, col, START_EDGE,marked);
-
- if (edge != no_edge)
- {
- pixel_outline_type outline;
- boolean clockwise = edge == bottom;
-
- outline = find_one_outline (edge, row, col, &marked);
-
- /* Outside outlines will start at a top edge, and move
- counterclockwise, and inside outlines will start at a
- bottom edge, and move clockwise. This happens because of
- the order in which we look at the edges. */
- O_CLOCKWISE (outline) = clockwise;
- append_pixel_outline (&outline_list, outline);
-
- }
- }
-
- if ((row & 0xf) == 0)
- gimp_progress_update (((gdouble)row) / height);
- }
-
- local_free_bitmap (&marked);
-
- return outline_list;
- }
-
-
- /* Here we find one of a character C's outlines. We're passed the
- position (ORIGINAL_ROW and ORIGINAL_COL) of a starting pixel and one
- of its unmarked edges, ORIGINAL_EDGE. We traverse the adjacent edges
- of the outline pixels, appending to the coordinate list. We keep
- track of the marked edges in MARKED, so it should be initialized to
- zeros when we first get it. */
-
- static pixel_outline_type
- find_one_outline (edge_type original_edge,
- unsigned original_row, unsigned original_col,
- bitmap_type *marked)
- {
- pixel_outline_type outline = new_pixel_outline ();
- unsigned row = original_row, col = original_col;
- edge_type edge = original_edge;
-
- do
- {
- /* Put this edge on to the output list, changing to Cartesian, and
- taking account of the side bearings. */
- append_coordinate (&outline, col,
- sel_get_height() - row, edge);
-
- mark_edge (edge, row, col, marked);
- next_outline_edge (&edge, &row, &col);
- }
- while (row != original_row || col != original_col || edge != original_edge);
-
- return outline;
- }
-
-
- /* Append an outline to an outline list. This is called when we have
- completed an entire pixel outline. */
-
- static void
- append_pixel_outline (pixel_outline_list_type *outline_list,
- pixel_outline_type outline)
- {
- O_LIST_LENGTH (*outline_list)++;
- outline_list->data = (pixel_outline_type *)g_realloc(outline_list->data,outline_list->length *sizeof(pixel_outline_type));
- O_LIST_OUTLINE (*outline_list, O_LIST_LENGTH (*outline_list) - 1) = outline;
- }
-
-
- /* Here is a routine that frees a list of such lists. */
-
- void
- free_pixel_outline_list (pixel_outline_list_type *outline_list)
- {
- unsigned this_outline;
-
- for (this_outline = 0; this_outline < outline_list->length; this_outline++)
- {
- pixel_outline_type o = outline_list->data[this_outline];
- safe_free ((address *) &(o.data));
- }
-
- if (outline_list->data != NULL)
- safe_free ((address *) &(outline_list->data));
- }
-
-
- /* Return an empty list of pixels. */
-
-
- pixel_outline_type
- new_pixel_outline ()
- {
- pixel_outline_type pixel_outline;
-
- O_LENGTH (pixel_outline) = 0;
- pixel_outline.data = NULL;
-
- return pixel_outline;
- }
-
-
- /* Add the coordinate C to the pixel list O. */
-
- static void
- append_outline_pixel (pixel_outline_type *o, coordinate_type c)
- {
- O_LENGTH (*o)++;
- o->data = (coordinate_type *)g_realloc(o->data, O_LENGTH (*o)*sizeof(coordinate_type));
- O_COORDINATE (*o, O_LENGTH (*o) - 1) = c;
- }
-
-
- /* We are given an (X,Y) in Cartesian coordinates, and the edge of the pixel
- we're on. We append a corner of that pixel as our coordinate.
- If we're on a top edge, we use the upper-left hand corner; right edge
- => upper right; bottom edge => lower right; left edge => lower left. */
-
- void
- append_coordinate (pixel_outline_type *o, int x, int y, edge_type edge)
- {
- coordinate_type c;
- char * str;
-
- c.x = x;
- c.y = y;
-
- switch (edge)
- {
- case top:
- c.y++;
- str = "top";
- break;
-
- case right:
- c.x++;
- c.y++;
- str = "right";
- break;
-
- case bottom:
- c.x++;
- str = "bottom";
- break;
-
- case left:
- str = "left";
- break;
-
- default:
- printf ("append_coordinate: Bad edge (%d)", edge);
- }
-
- append_outline_pixel (o, c);
- }
-