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 / gf / gf_output.c < prev    next >
C/C++ Source or Header  |  1992-09-21  |  12KB  |  438 lines

  1. /* gf_output.c: write objects to one GF file.
  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 "file-output.h"
  22. #include "gf.h"
  23. #include "scaled-num.h"
  24.  
  25. #include "gf_opcodes.h"
  26.  
  27.  
  28. /* The file we are writing to.  */
  29. static FILE *gf_output_file = NULL;
  30. static string gf_output_filename;
  31.  
  32.  
  33. /* The bounding box of all the characters we have written.  The values
  34.    here should be the largest and smallest possible integers.  */
  35. static bounding_box_type font_bb
  36.   = { INT_MAX, INT_MIN, INT_MAX, INT_MIN };
  37.  
  38.  
  39. /* We keep track of the character locator information as we output
  40.    characters, to save the caller from doing the bookkeeping.  */
  41. static gf_char_locator_type char_loc[MAX_CHARCODE + 1];
  42.  
  43. static void init_locators (void);
  44. static void put_locators (void);
  45.  
  46.  
  47. /* Other parts of the GF file that deserve their own routines.  */
  48. static void put_boc (gf_char_type);
  49. static void put_bitmap (bitmap_type);
  50.  
  51.  
  52. /* Subroutines for writing the bitmap.  */
  53. static void put_paint (unsigned);
  54. static void put_skip (unsigned);
  55. static void put_new_row (unsigned);
  56.  
  57. /* Low-level output.  These macros call the corresponding routines in
  58.    kbase, using the static variables for the input file and filename.  */
  59.  
  60. #define GF_FTELL() xftell (gf_output_file, gf_output_filename)
  61. #define GF_PUT_BYTE(b) put_byte (b, gf_output_file, gf_output_filename)
  62. #define GF_PUT_TWO(b) put_two (b, gf_output_file, gf_output_filename)
  63. #define GF_PUT_THREE(n) put_three (n, gf_output_file, gf_output_filename)
  64. #define GF_PUT_FOUR(n) put_four (n, gf_output_file, gf_output_filename)
  65. #define GF_PUT_SIGNED_FOUR(n) \
  66.   put_signed_four (n, gf_output_file, gf_output_filename);
  67.  
  68. /* Routines to start and end writing a file.  (For the user to call.)
  69.    We make sure the caller can't have two output files open
  70.    simultaneously. */
  71.  
  72. boolean
  73. gf_open_output_file (string filename)
  74. {
  75.   assert (gf_output_file == NULL);
  76.  
  77.   gf_output_filename = filename;
  78.   gf_output_file = fopen (filename, "w");
  79.  
  80.   if (gf_output_file != NULL)
  81.     {
  82.       init_locators ();
  83.       return true;
  84.     }
  85.   else
  86.     return false;
  87. }
  88.  
  89.  
  90. void
  91. gf_close_output_file ()
  92. {
  93.   assert (gf_output_file != NULL);
  94.  
  95.   xfclose (gf_output_file, gf_output_filename);
  96.  
  97.   gf_output_filename = NULL;
  98.   gf_output_file = NULL;
  99. }
  100.  
  101. /* Write the preamble.  */
  102.  
  103. void
  104. gf_put_preamble (string comment)
  105. {
  106.   unsigned comment_length, c;
  107.  
  108.   assert (gf_output_file != NULL);
  109.  
  110.   GF_PUT_BYTE (PRE);
  111.   GF_PUT_BYTE (GF_ID);
  112.  
  113.   comment_length = strlen (comment);
  114.  
  115.   if (comment_length > 255)
  116.     comment_length = 255;
  117.  
  118.   GF_PUT_BYTE (comment_length);
  119.   /* We can't just output all the characters in the string, since the
  120.      string might have been too long.  */
  121.   for (c = 0; c < comment_length; c++)
  122.     GF_PUT_BYTE (*(comment + c));
  123. }
  124.  
  125. /* Write the postamble.  */
  126.  
  127. void
  128. gf_put_postamble (fix_word design_size, real h_resolution, real v_resolution)
  129. {
  130.   byte_count_type post_ptr;
  131.   unsigned i;
  132.  
  133.   assert (gf_output_file != NULL);
  134.  
  135.   fflush (gf_output_file);
  136.   post_ptr = GF_FTELL ();
  137.   GF_PUT_BYTE (POST);
  138.   GF_PUT_FOUR (post_ptr);   /* No specials before the postamble.  */
  139.   GF_PUT_FOUR (design_size);
  140.   GF_PUT_FOUR (0);        /* Don't bother with a checksum.  */
  141.  
  142.   /* The resolution values are given to us in pixels per inch, but we
  143.      must write them in pixels per point (as well as scaling them).  */
  144.   GF_PUT_FOUR (real_to_scaled (h_resolution / POINTS_PER_INCH));
  145.   GF_PUT_FOUR (real_to_scaled (h_resolution / POINTS_PER_INCH));
  146.  
  147.   GF_PUT_SIGNED_FOUR (MIN_COL (font_bb));
  148.   GF_PUT_SIGNED_FOUR (MAX_COL (font_bb));
  149.   GF_PUT_SIGNED_FOUR (MIN_ROW (font_bb));
  150.   GF_PUT_SIGNED_FOUR (MAX_ROW (font_bb));
  151.  
  152.   put_locators ();
  153.  
  154.   GF_PUT_BYTE (POST_POST);
  155.   GF_PUT_FOUR (post_ptr);
  156.   GF_PUT_BYTE (GF_ID);
  157.  
  158.   for (i = 0; i < 4; i++)
  159.     GF_PUT_BYTE (GF_SIGNATURE);
  160. }
  161.  
  162.  
  163. /* Here we output the information we have accumulated in the `char_loc'
  164.    array.  GF format allows for two different `char_loc' commands, one
  165.    more efficient (but less general) than the other.  We use the
  166.    appropriate one.  */
  167.  
  168. static void
  169. put_locators ()
  170. {
  171.   unsigned this_char;
  172.  
  173.   for (this_char = 0; this_char <= MAX_CHARCODE; this_char++)
  174.     {
  175.       gf_char_locator_type this_char_loc = char_loc[this_char];
  176.  
  177.       if (this_char_loc.char_pointer != NULL_BYTE_PTR)
  178.     {
  179.       int h_escapement = this_char_loc.h_escapement;
  180.  
  181.       /* Decide if we can use CHAR_LOC0.  */
  182.       if (h_escapement >= 0 && h_escapement < ONE_BYTE_BIG)
  183.         {
  184.           GF_PUT_BYTE (CHAR_LOC0);
  185.           GF_PUT_BYTE (this_char);
  186.           GF_PUT_BYTE (h_escapement);
  187.         }
  188.       else
  189.         {
  190.           GF_PUT_BYTE (CHAR_LOC);
  191.           GF_PUT_BYTE (this_char);
  192.           GF_PUT_FOUR (real_to_scaled ((real) h_escapement));
  193.           GF_PUT_FOUR (0);    /* No vertical escapement.  */
  194.         }
  195.  
  196.       GF_PUT_FOUR (this_char_loc.tfm_width);
  197.       GF_PUT_SIGNED_FOUR (this_char_loc.char_pointer);
  198.     }
  199.     }
  200. }
  201.  
  202.  
  203. /* We must initialize the character locators to all null values.  */
  204.  
  205. static void
  206. init_locators ()
  207. {
  208.   unsigned this_char;
  209.  
  210.   for (this_char = 0; this_char <= MAX_CHARCODE; this_char++)
  211.     char_loc[this_char].char_pointer = NULL_BYTE_PTR;
  212. }
  213.  
  214. /* Do what's necessary to prepare for outputting a character.  */
  215.  
  216. static void
  217. start_put_char (charcode_type charcode, unsigned h_escapement,
  218.                 fix_word tfm_width, bounding_box_type char_bb)
  219. {
  220.   gf_char_locator_type *this_char_loc = &(char_loc[charcode]);
  221.  
  222.   assert (gf_output_file != NULL);
  223.  
  224.   if (this_char_loc->char_pointer != NULL_BYTE_PTR)
  225.     {
  226.       WARNING1 ("gf_put_char: Character %u already output", charcode);
  227.       return;
  228.     }
  229.  
  230.   /* Update the character locator information (part of the postamble).  */
  231.   this_char_loc->char_pointer = GF_FTELL ();
  232.   this_char_loc->h_escapement = h_escapement;
  233.   this_char_loc->tfm_width = tfm_width;
  234.   this_char_loc->charcode = charcode;
  235.  
  236.   /* Update the font bounding box.  */
  237.   if (MIN_COL (char_bb) < MIN_COL (font_bb))
  238.     MIN_COL (font_bb) = MIN_COL (char_bb);
  239.   if (MAX_COL (char_bb) > MAX_COL (font_bb))
  240.     MAX_COL (font_bb) = MAX_COL (char_bb);
  241.   if (MIN_ROW (char_bb) < MIN_ROW (font_bb))
  242.     MIN_ROW (font_bb) = MIN_ROW (char_bb);
  243.   if (MAX_ROW (char_bb) > MAX_ROW (font_bb))
  244.     MAX_ROW (font_bb) = MAX_ROW (char_bb);
  245. }
  246.  
  247.  
  248. /* Output the character GF_CHAR.  */
  249.  
  250. void
  251. gf_put_char (gf_char_type gf_char)
  252. {
  253.   start_put_char (GF_CHARCODE (gf_char), GF_H_ESCAPEMENT (gf_char),
  254.                   GF_TFM_WIDTH (gf_char), GF_CHAR_BB (gf_char));
  255.   put_boc (gf_char);
  256.   put_bitmap (GF_BITMAP (gf_char));
  257.   GF_PUT_BYTE (EOC);
  258. }
  259.  
  260.  
  261. /* Output the BOC command that begins each character.  BOC commands come
  262.    in two flavors, one of which takes less space but is less general.  */
  263.  
  264. static void
  265. put_boc (gf_char_type gf_char)
  266. {
  267.   signed_4_bytes row_delta = (GF_CHAR_MAX_ROW (gf_char)
  268.                               - GF_CHAR_MIN_ROW (gf_char));
  269.   signed_4_bytes col_delta = (GF_CHAR_MAX_COL (gf_char)
  270.                               - GF_CHAR_MIN_COL (gf_char));
  271.  
  272.   /* Decide if we can use BOC1, the abbreviated form.  */
  273.   if (row_delta < ONE_BYTE_BIG && row_delta >= 0
  274.       && col_delta < ONE_BYTE_BIG && col_delta >= 0
  275.       && GF_CHAR_MAX_ROW (gf_char) < ONE_BYTE_BIG
  276.       && GF_CHAR_MAX_ROW (gf_char) >= 0
  277.       && GF_CHAR_MAX_COL (gf_char) < ONE_BYTE_BIG
  278.       && GF_CHAR_MAX_COL (gf_char) >= 0)
  279.     {
  280.       GF_PUT_BYTE (BOC1);
  281.       GF_PUT_BYTE (GF_CHARCODE (gf_char));
  282.       GF_PUT_BYTE (col_delta);
  283.       GF_PUT_BYTE (GF_CHAR_MAX_COL (gf_char));
  284.       GF_PUT_BYTE (row_delta);
  285.       GF_PUT_BYTE (GF_CHAR_MAX_ROW (gf_char));
  286.     }
  287.   else
  288.     {
  289.       GF_PUT_BYTE (BOC);
  290.       GF_PUT_FOUR (GF_CHARCODE (gf_char));
  291.       GF_PUT_SIGNED_FOUR (NULL_BYTE_PTR);   /* We never have a backpointer.  */
  292.       GF_PUT_SIGNED_FOUR (GF_CHAR_MIN_COL (gf_char));
  293.       GF_PUT_SIGNED_FOUR (GF_CHAR_MAX_COL (gf_char));
  294.       GF_PUT_SIGNED_FOUR (GF_CHAR_MIN_ROW (gf_char));
  295.       GF_PUT_SIGNED_FOUR (GF_CHAR_MAX_ROW (gf_char));
  296.     }
  297. }
  298.  
  299.  
  300. /* Bitmaps in GF format are run-encoded.  There are three commands:
  301.    `paint', which writes a run of pixels (either black or white);
  302.    `skip', which leaves entirely blank rows; and `new_row', which begins
  303.    a new row with the first black pixel some number of pixels from the
  304.    left edge.  */
  305.  
  306. static void
  307. put_bitmap (bitmap_type b)
  308. {
  309.   unsigned run = 0;        /* Length of the current run.  */
  310.   one_byte current_color = WHITE;
  311.   boolean recent_eol = false;    /* Have we seen only white since eol?  */
  312.   unsigned all_white = 0;    /* Count of entirely blank rows.  */
  313.   unsigned this_row, this_col;
  314.  
  315.   for (this_row = 0; this_row < BITMAP_HEIGHT (b); this_row++)
  316.     {
  317.       for (this_col = 0; this_col < BITMAP_WIDTH (b); this_col++)
  318.     {
  319.       one_byte p = BITMAP_PIXEL (b, this_row, this_col);
  320.  
  321.       if (p == current_color)
  322.             run++;
  323.       else
  324.         {
  325.           if (recent_eol)
  326.         {        /* First transition to black on new row?  */
  327.           recent_eol = false;
  328.           put_skip (all_white);
  329.           all_white = 0;
  330.           /* We've seen only white up to now, since
  331.                      `current_color' is zero after each row.  */
  332.           put_new_row (run);
  333.         }
  334.           else
  335.                put_paint (run);
  336.  
  337.           current_color = p;
  338.           run = 1;
  339.         }
  340.     }
  341.  
  342.       if (current_color == BLACK)
  343.     {
  344.       put_paint (run);    /* The row ended with black.  */
  345.       current_color = WHITE;
  346.     }
  347.  
  348.       else if (recent_eol)
  349.         all_white++;        /* The row was entirely white.  */
  350.  
  351.       recent_eol = true;
  352.       run = 0;
  353.     }
  354. }
  355.  
  356.  
  357. /* Routines to output the actual GF commands that describe the bitmap. 
  358.    We use the shortest possible command.  */
  359.  
  360. static void
  361. put_paint (unsigned run)
  362. {
  363.    if (run < 64)
  364.      GF_PUT_BYTE (run);
  365.    else if (run < ONE_BYTE_BIG)
  366.      {
  367.        GF_PUT_BYTE (PAINT1);
  368.        GF_PUT_BYTE (run);
  369.      }
  370.    else if (run < TWO_BYTES_BIG)
  371.      {
  372.        GF_PUT_BYTE (PAINT2);
  373.        GF_PUT_TWO (run);
  374.      }
  375.    else if (run < THREE_BYTES_BIG)
  376.      {
  377.        GF_PUT_BYTE (PAINT3);
  378.        GF_PUT_THREE (run);
  379.      }
  380.    else
  381.      FATAL1 ("put_paint: Run of %u pixels too long for GF format", run);
  382. }
  383.  
  384.  
  385. static void
  386. put_skip (unsigned all_white)
  387. {
  388.   if (all_white == 0)
  389.     ; /* Do nothing.  */
  390.   else if (all_white == 1)
  391.     GF_PUT_BYTE (SKIP0);
  392.   else if (all_white < ONE_BYTE_BIG)
  393.     {
  394.       GF_PUT_BYTE (SKIP1);
  395.       GF_PUT_BYTE (all_white - 1);
  396.     }
  397.   else if (all_white < TWO_BYTES_BIG)
  398.     {
  399.       GF_PUT_BYTE (SKIP2);
  400.       GF_PUT_TWO (all_white - 1);
  401.     }
  402.   else if (all_white < THREE_BYTES_BIG)
  403.     {
  404.       GF_PUT_BYTE (SKIP3);
  405.       GF_PUT_THREE (all_white - 1);
  406.     }
  407.   else
  408.     FATAL1 ("put_skip: %u rows is too many for GF format", all_white);
  409. }
  410.  
  411.  
  412. static void
  413. put_new_row (unsigned indent)
  414. {
  415.   if (indent <= 164)
  416.     GF_PUT_BYTE (NEW_ROW_0 + indent);
  417.   else
  418.     {
  419.       /* Too large for a new_row command; have to skip and then paint.  */
  420.       GF_PUT_BYTE (SKIP0);
  421.       put_paint (indent);
  422.     }
  423. }
  424.  
  425.  
  426. /* Output a raw character.  */
  427.  
  428. void
  429. gf_put_raw_char (raw_char_type raw_char)
  430. {
  431.   one_byte charcode = GF_CHARCODE (raw_char);
  432.   
  433.   start_put_char (charcode, GF_H_ESCAPEMENT (raw_char),
  434.                   GF_TFM_WIDTH (raw_char), GF_CHAR_BB (raw_char));
  435.   put_n_bytes (RAW_CHAR_USED (raw_char), RAW_CHAR_BYTES (raw_char),
  436.                gf_output_file, gf_output_filename);
  437. }
  438.