home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / fontutils-0.6 / imgrotate / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-15  |  9.8 KB  |  335 lines

  1. /* imgrotate -- rotate an image.
  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. #define CMDLINE_NO_DPI /* It's not in the input filename.  */
  22. #include "cmdline.h"
  23. #include "getopt.h"
  24. #include "report.h"
  25.  
  26. #include "img-input.h"
  27. #include "img-output.h"
  28.  
  29. /* Says whether to rotate by 90 degrees clockwise.  (-rotate-clockwise)  */
  30. boolean do_clockwise_rotation = false;
  31.  
  32. /* Says whether to flip the image end for end.  (-flip)  */
  33. boolean do_head_over_heels = false;
  34.  
  35. /* The name of the output file.  (-output-file)  */
  36. string output_name = NULL;
  37.  
  38.  
  39. static void flip (img_header_type, one_byte *);
  40. static string read_command_line (int, string[]);
  41. static one_byte reverse_bits (one_byte b);
  42. static void rotate_clockwise (img_header_type, one_byte *);
  43.  
  44. /* Imgrotate rotates an image 90 or 180 degrees.  It uses an unusually
  45.    stupid and slow algorithm, because it was a quick hack.  Some better
  46.    method should be implemented.  It would also be nice if this
  47.    functionality was simply put into Imageto, so rotated images could be
  48.    read directly.  (Thus saving lots of disk space.)  */
  49.  
  50. int
  51. main (int argc, string argv[])
  52. {
  53.   one_byte *image;
  54.   img_header_type img_header_in;
  55.   string input_name;
  56.   string image_name = read_command_line (argc, argv);
  57.     
  58.   input_name = extend_filename (image_name, "img");
  59.   if (!open_img_input_file (input_name))
  60.     FATAL_PERROR (input_name);
  61.   
  62.   if (output_name == NULL)
  63.     output_name = remove_suffix (basename (input_name));
  64.  
  65.   output_name = extend_filename (output_name, "img");
  66.  
  67.   /* If the input and output files would be the same, we name the output
  68.      file something different.  */
  69.   if (same_file_p (output_name, input_name))
  70.     output_name = make_prefix ("x", output_name);
  71.  
  72.   if (!open_img_output_file (output_name))
  73.     FATAL_PERROR (output_name);
  74.   
  75.   /* Read the image header.  */
  76.   img_header_in = get_img_header ();
  77.   
  78.   /* Read the entire image into memory.  */
  79.   image = read_data ();
  80.   
  81.   if (do_clockwise_rotation)
  82.     rotate_clockwise (img_header_in, image);
  83.  
  84.   else if (do_head_over_heels)
  85.     flip (img_header_in, image);
  86.  
  87.   close_img_input_file ();
  88.   close_img_output_file ();
  89.   
  90.   return 0;
  91. }
  92.  
  93. /* Flip the image end for end and left for right.  For example,
  94.   *  *
  95.   *  *
  96.   *  *
  97.    ***
  98.      *
  99.      *
  100.      *   (that's an `h') turns upright.  */
  101.  
  102. static void
  103. flip (img_header_type header, one_byte *image)
  104. {
  105.   int this_col, this_row;
  106.   unsigned width_in_bits, width_in_bytes, width_in_shorts;
  107.   unsigned count = 0;
  108.   unsigned padding = 16 - header.width % 16;
  109.  
  110.   put_img_header (header);
  111.   
  112.   /* We have to get a byte at a time.  */
  113.   width_in_bits = header.width;
  114.   width_in_shorts = width_in_bits / 16 + (width_in_bits % 16 != 0);
  115.   width_in_bytes = width_in_shorts * 2;
  116.   
  117.   for (this_row = header.height - 1; this_row >= 0; this_row--)
  118.     {
  119.       one_byte *row = image + this_row * width_in_bytes;
  120.  
  121.       /* Because we are reversing left and right, we must make sure that
  122.          the padding bits don't get put into the image.  The scanner
  123.          software pads bytes that are partially data with 1's (i.e.,
  124.          white), so the only case we have to worry about is when the
  125.          padding is more than one byte -- the byte that is entirely
  126.          padding is output as zero.  */
  127.       one_byte first_byte = (padding >= 8) ? 0xff : row[width_in_bytes - 1];
  128.       
  129.       img_put_byte (reverse_bits (first_byte));
  130.       
  131.       for (this_col = width_in_bytes - 2; this_col >= 0; this_col--)
  132.         {
  133.           one_byte byte = row[this_col];
  134.           img_put_byte (reverse_bits (byte));
  135.         }
  136.       
  137.       if (verbose)
  138.         {
  139.           putc ('.', stderr);
  140.           if ((header.height - this_row) % 8 == 0)
  141.             fprintf (stderr, "%2.0f%c",
  142.                      100.0 * (header.height - this_row) / header.height,
  143.                      (++count % 4 == 0) ? '\n' : ' ');
  144.           fflush (stderr);
  145.         }
  146.     }
  147.   
  148.   if (verbose)
  149.     putc ('\n', stderr);
  150. }
  151.  
  152.  
  153. /* Reverse the bits in the byte B; e.g., 0x88 becomes 0x11.  */
  154.  
  155. static one_byte
  156. reverse_bits (one_byte b)
  157. {
  158.   one_byte mask;
  159.   unsigned this_bit;
  160.   one_byte answer = 0;
  161.   
  162.   if (b != 0 && b != 0xff)
  163.     for (this_bit = 0, mask = 0x80; this_bit < 8; this_bit++, mask >>= 1)
  164.       answer |= ((b & mask) != 0) << this_bit;
  165.   else
  166.     answer = b;
  167.   
  168.   return answer;
  169. }
  170.  
  171. /* Rotate IMAGE by 90 degrees clockwise.  This turns, for example,
  172.       ******
  173.    ***  *
  174.   *     *
  175.    ***  *
  176.       ******   upright.  */
  177.  
  178.  
  179. static void
  180. rotate_clockwise (img_header_type header_in, one_byte *image)
  181. {
  182.   one_byte byte;
  183.   one_byte mask;
  184.   unsigned this_col, this_row, this_bit;
  185.   unsigned width_in_bits, width_in_bytes, width_in_shorts;
  186.  
  187.   /* Figure out how many bits of padding we are going to need.  */
  188.   unsigned padding = 16 - header_in.height % 16;
  189.   unsigned total_height = header_in.height + padding;
  190.   one_byte *column = xmalloc (total_height);
  191.  
  192.   img_header_type header_out = header_in;
  193.   
  194.   /* Exchange the width and height.  */
  195.   unsigned temp = header_out.width;
  196.   header_out.width = header_out.height;
  197.   header_out.height = temp;
  198.   
  199.   /* Put in the white pixels (which are 1 bits).  */
  200.   for (this_row = 0; this_row < padding; this_row++)
  201.     column[header_in.height + this_row] = 0xff;
  202.  
  203.   /* We have to get a byte at a time.  */
  204.   width_in_bits = header_in.width;
  205.   width_in_shorts = width_in_bits / 16 + (width_in_bits % 16 != 0);
  206.   width_in_bytes = width_in_shorts * 2;
  207.   
  208.   /* That means that we are going to output the padding columns at the
  209.      right of the original image as the last rows.  So we have to change
  210.      the header to conform.  */
  211.   header_out.height = width_in_bytes * 8;
  212.   put_img_header (header_out);
  213.  
  214.   for (this_col = 0; this_col < width_in_bytes; this_col++)
  215.     {
  216.       for (this_row = 0; this_row < header_in.height; this_row++)
  217.         /* The image starts down at the bottom, so adjust.  */
  218.         column[header_in.height - 1 - this_row]
  219.           = image[this_row * width_in_bytes + this_col];
  220.  
  221.       /* We can now output eight scanlines, one for each bit in the
  222.          column array.  */
  223.       for (byte = 0, mask = 0x80, this_bit = 0;
  224.            this_bit < 8;
  225.            mask >>= 1, this_bit++)
  226.         {
  227.           /* For each bit, go down the column, constructing the
  228.              scanline.  */
  229.           for (this_row = 0; this_row < total_height; this_row++)
  230.             {
  231.               one_byte new_bit
  232.                 = ((column[this_row] & mask) != 0) << (7 - this_row % 8);
  233.               byte |= new_bit;
  234.               if ((this_row + 1) % 8 == 0)
  235.                 {
  236.                   img_put_byte (byte);
  237.                   byte = 0;
  238.                 }
  239.             }
  240.         }
  241.       
  242.       if (verbose)
  243.         {
  244.           putc ('.', stderr);
  245.  
  246.           if ((this_col + 1) % 8 == 0)
  247.             fprintf (stderr, "%2.0f%c", 100.0 * this_col / width_in_bytes,
  248.                      (this_col + 1) % 56 == 0 ? '\n' : ' ');
  249.           fflush (stderr);
  250.         }
  251.     }
  252.  
  253.   if (verbose)
  254.     putc ('\n', stderr);
  255. }
  256.  
  257. /* Reading the options.  */
  258.  
  259. /* This is defined in version.c.  */
  260. extern string version_string;
  261.  
  262. #define USAGE "Options:
  263.   <font_name> should be a base filename, e.g., `gmr'.  It is extended
  264.     with `.img'."                            \
  265.   GETOPT_USAGE                                \
  266. "flip: rotate the image 180 degrees.
  267. help: print this message.
  268. output-file <filename>: write the output to <filename>, extended with
  269.    `.img' if <filename> does not have a suffix.  The default is the input
  270.    filename, prepended with `x' if that would overwrite the input file.
  271. rotate-clockwise: rotate the image 90 degrees clockwise.
  272. verbose: output progress reports to stdout.
  273. version: print the version number of this program.
  274. "
  275.  
  276. static string
  277. read_command_line (int argc, string argv[])
  278. {
  279.   int g;   /* `getopt' return code.  */
  280.   int option_index;
  281.   boolean printed_version = false;
  282.   struct option long_options[]
  283.     = { { "flip",        0, (int *) &do_head_over_heels, 1 },
  284.         { "help",        0, 0, 0 },
  285.         { "output-file",    1, 0, 0 },
  286.         { "rotate-clockwise",    0, (int *) &do_clockwise_rotation, 1 },
  287.         { "verbose",        0, (int *) &verbose, 1 },
  288.         { "version",        0, (int *) &printed_version, 1 },
  289.         { 0, 0, 0, 0 } };
  290.  
  291.   while (true)
  292.     {
  293.       g = getopt_long_only (argc, argv, "", long_options, &option_index);
  294.       
  295.       if (g == EOF)
  296.         break;
  297.  
  298.       if (g == '?')
  299.         exit (1);  /* Unknown option.  */
  300.   
  301.       assert (g == 0); /* We have no short option names.  */
  302.       
  303.       if (ARGUMENT_IS ("help"))
  304.         {
  305.           fprintf (stderr, "Usage: %s [options] <font_name>.\n", argv[0]);
  306.           fprintf (stderr, USAGE);
  307.           exit (0);
  308.         }
  309.  
  310.       else if (ARGUMENT_IS ("output-file"))
  311.         output_name = optarg;
  312.  
  313.       else if (ARGUMENT_IS ("version"))
  314.         printf ("%s.\n", version_string);
  315.  
  316.       /* Else it was a flag; getopt has already done the assignment.  */
  317.     }
  318.   
  319.   /* Check that they asked to do exactly one thing.  */
  320.   if (!(do_head_over_heels || do_clockwise_rotation))
  321.     {
  322.       fprintf (stderr, "No operation specified.\n");
  323.       fprintf (stderr, "For more information, use ``-help''.\n");
  324.       exit (1);
  325.     }
  326.   else if (do_head_over_heels && do_clockwise_rotation)
  327.     {
  328.       fprintf (stderr, "Too many operations specified (sorry).\n");
  329.       fprintf (stderr, "For more information, use ``-help''.\n");
  330.       exit (1);
  331.     }
  332.  
  333.   FINISH_COMMAND_LINE ();
  334. }
  335.