home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / fontutils-0.6-base.tgz / fontutils-0.6-base.tar / fsf / fontutils / lib / bitmap.c < prev    next >
C/C++ Source or Header  |  1992-09-22  |  8KB  |  259 lines

  1. /* bitmap.c: operations on bitmaps.
  2.  
  3. Copyright (C) 1992 Free Software Foundation, Inc.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.
  9.  
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include "bitmap.h"
  22. #include "bounding-box.h"
  23.  
  24. static void bb_ensure_bounds (bounding_box_type *, bitmap_type, string);
  25.  
  26. /* Make sure the bitmap is entirely white to begin with.  */
  27.  
  28. bitmap_type
  29. new_bitmap (dimensions_type d)
  30. {
  31.   bitmap_type answer;
  32.   unsigned size = DIMENSIONS_WIDTH (d) * DIMENSIONS_HEIGHT (d);
  33.  
  34.   BITMAP_DIMENSIONS (answer) = d;
  35.   BITMAP_BITS (answer) = size > 0 ? xcalloc (size, 1) : NULL;
  36.  
  37.   return answer;
  38. }
  39.  
  40.  
  41. /* Free the storage that is allocated for a bitmap.  On the other hand,
  42.    the bitmap might not have any storage allocated for it if it is zero
  43.    in either dimension; in that case, don't free it.  */
  44.  
  45. void
  46. free_bitmap (bitmap_type *b)
  47. {
  48.   if (BITMAP_BITS (*b) != NULL)
  49.     safe_free ((address *) &BITMAP_BITS (*b));
  50. }
  51.  
  52.  
  53. /* Copy an existing bitmap into new memory.  We don't want to use
  54.    `new_bitmap' here, since that routine clears the bitmap's bits, and
  55.    we are going to set all the bits ourselves, anyway.  */
  56.  
  57. bitmap_type
  58. copy_bitmap (bitmap_type bitmap)
  59. {
  60.   bitmap_type answer;
  61.   unsigned size = BITMAP_WIDTH (bitmap) * BITMAP_HEIGHT (bitmap);
  62.  
  63.   BITMAP_DIMENSIONS (answer) = BITMAP_DIMENSIONS (bitmap);
  64.   BITMAP_BITS (answer) = size > 0 ? xmalloc (size) : NULL;
  65.   
  66.   if (size > 0)
  67.     memcpy (BITMAP_BITS (answer), BITMAP_BITS (bitmap), size);
  68.     
  69.   return answer;
  70. }
  71.  
  72.  
  73. /* Return the part of the bitmap SOURCE enclosed by the bounding box BB.
  74.    BB is interpreted in bitmap coordinates, with y increasing downwards;
  75.    for example, if MIN_ROW (BB) == 10, the subimage will start in the
  76.    tenth row from the top of SOURCE.  */
  77.  
  78. bitmap_type
  79. extract_subbitmap (bitmap_type source, bounding_box_type bb)
  80. {
  81.   unsigned this_row;
  82.   bitmap_type sub = new_bitmap (bb_to_dimensions (bb));
  83.   
  84.   /* Move to the bit at which we want to start copying.  */
  85.   BITMAP_BITS (source) += MIN_ROW (bb) * BITMAP_WIDTH (source) + MIN_COL (bb);
  86.   
  87.   bb_ensure_bounds (&bb, source, "extract_subbitmap");
  88.  
  89.   for (this_row = MIN_ROW (bb); this_row <= MAX_ROW (bb); this_row++)
  90.     {
  91.       one_byte *target = BITMAP_ROW (sub, this_row - MIN_ROW (bb));
  92.  
  93.       memcpy (target, BITMAP_BITS (source), BITMAP_WIDTH (sub));
  94.       BITMAP_BITS (source) += BITMAP_WIDTH (source);
  95.     }
  96.  
  97.   return sub;
  98. }
  99.  
  100.  
  101. /* If any of the elements of BB (taken to be in bitmap coordinates) are
  102.    outside the bounds of the bitmap SOURCE, give a warning (using NAME)
  103.    and update them.  */
  104.  
  105. static void
  106. bb_ensure_bounds (bounding_box_type *bb, bitmap_type source, string name)
  107. {
  108.   if (MIN_COL (*bb) < 0)
  109.     {
  110.       WARNING2 ("%s: min col=%d outside source image", name, MIN_COL (*bb));
  111.       MIN_COL (*bb) = 0;
  112.     }
  113.  
  114.   if (MIN_ROW (*bb) < 0)
  115.     {
  116.       WARNING2 ("%s: min row=%d outside source image", name, MIN_ROW (*bb));
  117.       MIN_COL (*bb) = 0;
  118.     }
  119.  
  120.   /* See comments at `get_character_bitmap' in gf_input.c for why the
  121.      width and height are treated asymetrically.  */
  122.   if (MAX_COL (*bb) > BITMAP_WIDTH (source))
  123.     {
  124.       WARNING2 ("%s: max col=%d outside source image", name, MAX_COL (*bb));
  125.       MAX_COL (*bb) = BITMAP_WIDTH (source) - 1;
  126.     }
  127.  
  128.   if (MAX_ROW (*bb) >= BITMAP_HEIGHT (source))
  129.     {
  130.       WARNING2 ("%s: max row=%d outside source image", name, MAX_ROW (*bb));
  131.       MAX_COL (*bb) = BITMAP_HEIGHT (source) - 1;
  132.     }
  133. }
  134.  
  135. /* The bounding boxes that we make in this routine are unlike the
  136.    bounding boxes used elsewhere.  These are in bitmap coordinates, not
  137.    Cartesian, and they refer to pixels, not edges.  So we have to adjust
  138.    the maximum column by one.  */
  139.  
  140. const bounding_box_type
  141. bitmap_to_bb (const bitmap_type b)
  142. {
  143.   bounding_box_type bb = dimensions_to_bb (BITMAP_DIMENSIONS (b));
  144.   if (MAX_COL (bb) != 0) MAX_COL (bb)--;
  145.   
  146.   return bb;
  147. }
  148.  
  149. /* Return the (zero-based) column numbers in which ROW changes from
  150.    black to white or white to black.  The first element marks a
  151.    white-to-black transition, and the last element marks a
  152.    black-to-white transition, imagining that ROW is surrounded by white.
  153.    (In other words, there is always an even number of transitions.)  We
  154.    mark the end of the vector with an element WIDTH + 1.  */
  155.  
  156. /* We use `length - 2' because we need to save one element at the end
  157.    for our sentinel.  */
  158. #define INSERT_TRANSITION(e)                        \
  159.   do {                                    \
  160.     XRETALLOC (vector, ++length, unsigned);                \
  161.     vector[length - 2] = e;                        \
  162.   } while (0)
  163.  
  164. unsigned *
  165. bitmap_find_transitions (const one_byte *row, unsigned width)
  166. {
  167.   unsigned col;
  168.   unsigned start;
  169.   one_byte color = BLACK;
  170.   unsigned length = 1;
  171.   
  172.   /* We want to make sure we start at a column with some black.  */
  173.   char *start_ptr = memchr (row, BLACK, width);
  174.   
  175.   /* Save the last element for the sentinel.  */
  176.   unsigned *vector =  XTALLOC1 (unsigned);
  177.  
  178.   if (start_ptr == NULL)
  179.     start = width; /* Don't go through the loop.  */
  180.   else
  181.     {
  182.       INSERT_TRANSITION (start_ptr - (char *) row);
  183.       start = vector[0] + 1; /* Don't look at this pixel again.  */
  184.     }
  185.  
  186.   for (col = start; col < width - 1; col++)
  187.     {
  188.       if (row[col] != color)
  189.         {
  190.           INSERT_TRANSITION (col);
  191.           color = row[col];
  192.         }
  193.     }
  194.   
  195.   /* We have to treat the last pixel in ROW specially.  There are
  196.      several cases:
  197.        1) if it's white, and the previous pixel is white, or the row is
  198.           one pixel long, do nothing;
  199.        2) if it's white, and the previous pixel is black,
  200.           insert one element in `vector' (marking the end of a run);
  201.        3) if it's black, and either the previous pixel is black or this was the
  202.           first black pixel in the row, insert one element (marking the
  203.           end of a run because we're at the end of the row);
  204.        4) if it's black, and the previous pixel is white and there was a
  205.           previous black pixel, or the row was one pixel long, insert
  206.           two elements (marking the start and end of this one-pixel run).
  207.   */
  208.   if (row[width - 1] == WHITE)
  209.     {
  210.       if (width > 1 && row[width - 2] == BLACK)
  211.         INSERT_TRANSITION (width - 1);
  212.     }
  213.   else
  214.     { /* Last pixel is black.  If previous pixel was also black, just
  215.          finish off the run.  */
  216.       if (width > 1 && row[width - 2] == BLACK)
  217.         INSERT_TRANSITION (width);
  218.       else
  219.         { /* Last pixel is black, previous pixel was white.  If this was
  220.              the only black pixel in the row, we've already inserted the
  221.              start of the run via `start' above, so just insert the end of
  222.              the run.  Otherwise, insert both the start and end of this
  223.              one-pixel run.  */
  224.           if (start != width)
  225.             INSERT_TRANSITION (width - 1);
  226.           INSERT_TRANSITION (width);
  227.         }
  228.     }
  229.   
  230.   vector[length - 1] = width + 1;  /* Sentinel for the end of the vector.  */
  231.   return vector;
  232. }
  233.  
  234. /* Print a part of the bitmap in human-readable form.  */
  235.  
  236. void
  237. print_bounded_bitmap (FILE *f, bitmap_type bitmap, bounding_box_type bb)
  238. {
  239.   unsigned this_row, this_col;
  240.  
  241.   fprintf (f, "Printing bitmap between (%u,%u) and (%u,%u):\n",
  242.        MIN_COL (bb), MIN_ROW (bb),
  243.        MAX_COL (bb), MAX_ROW (bb));
  244.   for (this_row = MIN_ROW (bb); this_row <= MAX_ROW (bb); this_row++)
  245.     {
  246.       for (this_col = MIN_COL (bb); this_col <= MAX_COL (bb); this_col++)
  247.         putc (BITMAP_PIXEL (bitmap, this_row, this_col) ? '*' : ' ', f);
  248.         
  249.       fprintf (f, "%u\n", this_row);
  250.     }
  251. }
  252.  
  253.  
  254. void
  255. print_bitmap (FILE *f, bitmap_type b)
  256. {
  257.   print_bounded_bitmap (f, b, bitmap_to_bb (b));
  258. }
  259.