home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / sel2path / pxl-outline.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-06  |  7.2 KB  |  255 lines

  1. /* pxl-outline.c: find the edges of the bitmap image; we call each such
  2.    edge an ``outline''; each outline is made up of one or more pixels;
  3.    and each pixel participates via one or more edges.
  4.  
  5. Copyright (C) 1992 Free Software Foundation, Inc.
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. #include <stdlib.h>
  22. #include "global.h"
  23. #include "sel2path.h"
  24. #include "bitmap.h"
  25. #include "edge.h"
  26. #include "pxl-outline.h"
  27.  
  28. static pixel_outline_type find_one_outline (edge_type,
  29.                           unsigned, unsigned, bitmap_type *);
  30. static void append_pixel_outline (pixel_outline_list_type *, 
  31.                                   pixel_outline_type);
  32. static pixel_outline_type new_pixel_outline (void);
  33. static void append_outline_pixel (pixel_outline_type *, coordinate_type);
  34. static void append_coordinate (pixel_outline_type *, int, int, edge_type);
  35.  
  36.  
  37. static bitmap_type
  38. local_new_bitmap (unsigned width,unsigned height)
  39. {
  40.   bitmap_type answer;
  41.   unsigned size = width * height;
  42.  
  43.  
  44.   BITMAP_HEIGHT(answer) = height;
  45.   BITMAP_WIDTH(answer) = width;
  46.  
  47.   BITMAP_BITS (answer) = g_new0 (one_byte, size);  /* g_new returns NULL if size == 0 */
  48.  
  49. /*   printf("local_new_bitmap size = %d @[%p]\n",size,BITMAP_BITS (answer)); */
  50.  
  51.   return answer;
  52. }
  53.  
  54. static void
  55. local_free_bitmap (bitmap_type *b)
  56. {
  57.   if (BITMAP_BITS (*b) != NULL)
  58.     safe_free ((address *) &BITMAP_BITS (*b));
  59. }
  60.  
  61. /* A character is made up of a list of one or more outlines.  Here, we
  62.    go through a character's bitmap top to bottom, left to right, looking
  63.    for the next pixel with an unmarked edge also on the character's outline.
  64.    Each one of these we find is the starting place for one outline.  We
  65.    find these outlines and put them in a list to return.  */
  66.  
  67. pixel_outline_list_type
  68. find_outline_pixels ()
  69. {
  70.   pixel_outline_list_type outline_list;
  71.   unsigned row, col;
  72.   gint height;
  73.   gint width;
  74.   bitmap_type marked = local_new_bitmap (sel_get_width(),sel_get_height());
  75.  
  76. /*   printf("width = %d, height = %d\n",BITMAP_WIDTH(marked),BITMAP_HEIGHT(marked)); */
  77.  
  78.   gimp_progress_init ("Selection to path...");
  79.  
  80.   O_LIST_LENGTH (outline_list) = 0;
  81.   outline_list.data = NULL;
  82.  
  83.   height = sel_get_height ();
  84.   width  = sel_get_width ();
  85.  
  86.   for (row = 0; row < height; row++)
  87.   {
  88.     for (col = 0; col < width; col++)
  89.       {
  90.     edge_type edge;
  91.  
  92.         if (sel_pixel_is_white(row, col))
  93.           continue;
  94.  
  95.         edge = next_unmarked_outline_edge (row, col, START_EDGE,marked);
  96.  
  97.     if (edge != no_edge)
  98.       {
  99.             pixel_outline_type outline;
  100.             boolean clockwise = edge == bottom;
  101.             
  102.             outline = find_one_outline (edge, row, col, &marked);
  103.             
  104.             /* Outside outlines will start at a top edge, and move
  105.                counterclockwise, and inside outlines will start at a
  106.                bottom edge, and move clockwise.  This happens because of
  107.                the order in which we look at the edges.  */
  108.             O_CLOCKWISE (outline) = clockwise;
  109.         append_pixel_outline (&outline_list, outline);
  110.  
  111.       }
  112.       }
  113.  
  114.     if ((row & 0xf) == 0)
  115.     gimp_progress_update (((gdouble)row) / height);
  116.   }
  117.  
  118.   local_free_bitmap (&marked); 
  119.   
  120.   return outline_list;
  121. }
  122.  
  123.  
  124. /* Here we find one of a character C's outlines.  We're passed the
  125.    position (ORIGINAL_ROW and ORIGINAL_COL) of a starting pixel and one
  126.    of its unmarked edges, ORIGINAL_EDGE.  We traverse the adjacent edges
  127.    of the outline pixels, appending to the coordinate list.  We keep
  128.    track of the marked edges in MARKED, so it should be initialized to
  129.    zeros when we first get it.  */
  130.  
  131. static pixel_outline_type
  132. find_one_outline (edge_type original_edge,
  133.           unsigned original_row, unsigned original_col,
  134.           bitmap_type *marked)
  135. {
  136.   pixel_outline_type outline = new_pixel_outline ();
  137.   unsigned row = original_row, col = original_col;
  138.   edge_type edge = original_edge;
  139.  
  140.   do
  141.     {
  142.       /* Put this edge on to the output list, changing to Cartesian, and
  143.          taking account of the side bearings.  */
  144.       append_coordinate (&outline, col, 
  145.                          sel_get_height() - row, edge);
  146.  
  147.       mark_edge (edge, row, col, marked);
  148.       next_outline_edge (&edge, &row, &col);
  149.     }
  150.   while (row != original_row || col != original_col || edge != original_edge);
  151.  
  152.   return outline;
  153. }
  154.  
  155.  
  156. /* Append an outline to an outline list.  This is called when we have
  157.    completed an entire pixel outline.  */
  158.  
  159. static void
  160. append_pixel_outline (pixel_outline_list_type *outline_list,
  161.               pixel_outline_type outline)
  162. {
  163.   O_LIST_LENGTH (*outline_list)++;
  164.   outline_list->data = (pixel_outline_type *)g_realloc(outline_list->data,outline_list->length *sizeof(pixel_outline_type));
  165.   O_LIST_OUTLINE (*outline_list, O_LIST_LENGTH (*outline_list) - 1) = outline;
  166. }
  167.  
  168.  
  169. /* Here is a routine that frees a list of such lists.  */
  170.  
  171. void
  172. free_pixel_outline_list (pixel_outline_list_type *outline_list)
  173. {
  174.   unsigned this_outline;
  175.  
  176.   for (this_outline = 0; this_outline < outline_list->length; this_outline++)
  177.     {
  178.       pixel_outline_type o = outline_list->data[this_outline];
  179.       safe_free ((address *) &(o.data));
  180.     }
  181.  
  182.   if (outline_list->data != NULL)
  183.     safe_free ((address *) &(outline_list->data));
  184. }
  185.  
  186.  
  187. /* Return an empty list of pixels.  */
  188.    
  189.  
  190. pixel_outline_type
  191. new_pixel_outline ()
  192. {
  193.   pixel_outline_type pixel_outline;
  194.  
  195.   O_LENGTH (pixel_outline) = 0;
  196.   pixel_outline.data = NULL;
  197.  
  198.   return pixel_outline;
  199. }
  200.  
  201.  
  202. /* Add the coordinate C to the pixel list O.  */
  203.  
  204. static void
  205. append_outline_pixel (pixel_outline_type *o, coordinate_type c)
  206. {
  207.   O_LENGTH (*o)++;
  208.   o->data = (coordinate_type *)g_realloc(o->data, O_LENGTH (*o)*sizeof(coordinate_type));
  209.   O_COORDINATE (*o, O_LENGTH (*o) - 1) = c;
  210. }
  211.  
  212.  
  213. /* We are given an (X,Y) in Cartesian coordinates, and the edge of the pixel
  214.    we're on.  We append a corner of that pixel as our coordinate.
  215.    If we're on a top edge, we use the upper-left hand corner; right edge
  216.    => upper right; bottom edge => lower right; left edge => lower left.  */
  217.  
  218. void
  219. append_coordinate (pixel_outline_type *o, int x, int y, edge_type edge)
  220. {
  221.   coordinate_type c;
  222.   char * str;
  223.  
  224.   c.x = x;
  225.   c.y = y;
  226.  
  227.   switch (edge)
  228.     {
  229.     case top:
  230.       c.y++;
  231.       str = "top";
  232.       break;
  233.     
  234.     case right:
  235.       c.x++;
  236.       c.y++;
  237.       str = "right";
  238.       break;
  239.     
  240.     case bottom:
  241.       c.x++;
  242.       str = "bottom";
  243.       break;
  244.     
  245.     case left:
  246.       str = "left";
  247.       break;
  248.     
  249.     default:
  250.       printf ("append_coordinate: Bad edge (%d)", edge);
  251.     }
  252.  
  253.   append_outline_pixel (o, c);
  254. }
  255.