home *** CD-ROM | disk | FTP | other *** search
- /* imgrotate -- rotate an image.
-
- 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 "config.h"
-
- #define CMDLINE_NO_DPI /* It's not in the input filename. */
- #include "cmdline.h"
- #include "getopt.h"
- #include "report.h"
-
- #include "img-input.h"
- #include "img-output.h"
-
- /* Says whether to rotate by 90 degrees clockwise. (-rotate-clockwise) */
- boolean do_clockwise_rotation = false;
-
- /* Says whether to flip the image end for end. (-flip) */
- boolean do_head_over_heels = false;
-
- /* The name of the output file. (-output-file) */
- string output_name = NULL;
-
-
- static void flip (img_header_type, one_byte *);
- static string read_command_line (int, string[]);
- static one_byte reverse_bits (one_byte b);
- static void rotate_clockwise (img_header_type, one_byte *);
-
- /* Imgrotate rotates an image 90 or 180 degrees. It uses an unusually
- stupid and slow algorithm, because it was a quick hack. Some better
- method should be implemented. It would also be nice if this
- functionality was simply put into Imageto, so rotated images could be
- read directly. (Thus saving lots of disk space.) */
-
- int
- main (int argc, string argv[])
- {
- one_byte *image;
- img_header_type img_header_in;
- string input_name;
- string image_name = read_command_line (argc, argv);
-
- input_name = extend_filename (image_name, "img");
- if (!open_img_input_file (input_name))
- FATAL_PERROR (input_name);
-
- if (output_name == NULL)
- output_name = remove_suffix (basename (input_name));
-
- output_name = extend_filename (output_name, "img");
-
- /* If the input and output files would be the same, we name the output
- file something different. */
- if (same_file_p (output_name, input_name))
- output_name = make_prefix ("x", output_name);
-
- if (!open_img_output_file (output_name))
- FATAL_PERROR (output_name);
-
- /* Read the image header. */
- img_header_in = get_img_header ();
-
- /* Read the entire image into memory. */
- image = read_data ();
-
- if (do_clockwise_rotation)
- rotate_clockwise (img_header_in, image);
-
- else if (do_head_over_heels)
- flip (img_header_in, image);
-
- close_img_input_file ();
- close_img_output_file ();
-
- return 0;
- }
-
- /* Flip the image end for end and left for right. For example,
- * *
- * *
- * *
- ***
- *
- *
- * (that's an `h') turns upright. */
-
- static void
- flip (img_header_type header, one_byte *image)
- {
- int this_col, this_row;
- unsigned width_in_bits, width_in_bytes, width_in_shorts;
- unsigned count = 0;
- unsigned padding = 16 - header.width % 16;
-
- put_img_header (header);
-
- /* We have to get a byte at a time. */
- width_in_bits = header.width;
- width_in_shorts = width_in_bits / 16 + (width_in_bits % 16 != 0);
- width_in_bytes = width_in_shorts * 2;
-
- for (this_row = header.height - 1; this_row >= 0; this_row--)
- {
- one_byte *row = image + this_row * width_in_bytes;
-
- /* Because we are reversing left and right, we must make sure that
- the padding bits don't get put into the image. The scanner
- software pads bytes that are partially data with 1's (i.e.,
- white), so the only case we have to worry about is when the
- padding is more than one byte -- the byte that is entirely
- padding is output as zero. */
- one_byte first_byte = (padding >= 8) ? 0xff : row[width_in_bytes - 1];
-
- img_put_byte (reverse_bits (first_byte));
-
- for (this_col = width_in_bytes - 2; this_col >= 0; this_col--)
- {
- one_byte byte = row[this_col];
- img_put_byte (reverse_bits (byte));
- }
-
- if (verbose)
- {
- putc ('.', stderr);
- if ((header.height - this_row) % 8 == 0)
- fprintf (stderr, "%2.0f%c",
- 100.0 * (header.height - this_row) / header.height,
- (++count % 4 == 0) ? '\n' : ' ');
- fflush (stderr);
- }
- }
-
- if (verbose)
- putc ('\n', stderr);
- }
-
-
- /* Reverse the bits in the byte B; e.g., 0x88 becomes 0x11. */
-
- static one_byte
- reverse_bits (one_byte b)
- {
- one_byte mask;
- unsigned this_bit;
- one_byte answer = 0;
-
- if (b != 0 && b != 0xff)
- for (this_bit = 0, mask = 0x80; this_bit < 8; this_bit++, mask >>= 1)
- answer |= ((b & mask) != 0) << this_bit;
- else
- answer = b;
-
- return answer;
- }
-
- /* Rotate IMAGE by 90 degrees clockwise. This turns, for example,
- ******
- *** *
- * *
- *** *
- ****** upright. */
-
-
- static void
- rotate_clockwise (img_header_type header_in, one_byte *image)
- {
- one_byte byte;
- one_byte mask;
- unsigned this_col, this_row, this_bit;
- unsigned width_in_bits, width_in_bytes, width_in_shorts;
-
- /* Figure out how many bits of padding we are going to need. */
- unsigned padding = 16 - header_in.height % 16;
- unsigned total_height = header_in.height + padding;
- one_byte *column = xmalloc (total_height);
-
- img_header_type header_out = header_in;
-
- /* Exchange the width and height. */
- unsigned temp = header_out.width;
- header_out.width = header_out.height;
- header_out.height = temp;
-
- /* Put in the white pixels (which are 1 bits). */
- for (this_row = 0; this_row < padding; this_row++)
- column[header_in.height + this_row] = 0xff;
-
- /* We have to get a byte at a time. */
- width_in_bits = header_in.width;
- width_in_shorts = width_in_bits / 16 + (width_in_bits % 16 != 0);
- width_in_bytes = width_in_shorts * 2;
-
- /* That means that we are going to output the padding columns at the
- right of the original image as the last rows. So we have to change
- the header to conform. */
- header_out.height = width_in_bytes * 8;
- put_img_header (header_out);
-
- for (this_col = 0; this_col < width_in_bytes; this_col++)
- {
- for (this_row = 0; this_row < header_in.height; this_row++)
- /* The image starts down at the bottom, so adjust. */
- column[header_in.height - 1 - this_row]
- = image[this_row * width_in_bytes + this_col];
-
- /* We can now output eight scanlines, one for each bit in the
- column array. */
- for (byte = 0, mask = 0x80, this_bit = 0;
- this_bit < 8;
- mask >>= 1, this_bit++)
- {
- /* For each bit, go down the column, constructing the
- scanline. */
- for (this_row = 0; this_row < total_height; this_row++)
- {
- one_byte new_bit
- = ((column[this_row] & mask) != 0) << (7 - this_row % 8);
- byte |= new_bit;
- if ((this_row + 1) % 8 == 0)
- {
- img_put_byte (byte);
- byte = 0;
- }
- }
- }
-
- if (verbose)
- {
- putc ('.', stderr);
-
- if ((this_col + 1) % 8 == 0)
- fprintf (stderr, "%2.0f%c", 100.0 * this_col / width_in_bytes,
- (this_col + 1) % 56 == 0 ? '\n' : ' ');
- fflush (stderr);
- }
- }
-
- if (verbose)
- putc ('\n', stderr);
- }
-
- /* Reading the options. */
-
- /* This is defined in version.c. */
- extern string version_string;
-
- #define USAGE "Options:
- <font_name> should be a base filename, e.g., `gmr'. It is extended
- with `.img'." \
- GETOPT_USAGE \
- "flip: rotate the image 180 degrees.
- help: print this message.
- output-file <filename>: write the output to <filename>, extended with
- `.img' if <filename> does not have a suffix. The default is the input
- filename, prepended with `x' if that would overwrite the input file.
- rotate-clockwise: rotate the image 90 degrees clockwise.
- verbose: output progress reports to stdout.
- version: print the version number of this program.
- "
-
- static string
- read_command_line (int argc, string argv[])
- {
- int g; /* `getopt' return code. */
- int option_index;
- boolean printed_version = false;
- struct option long_options[]
- = { { "flip", 0, (int *) &do_head_over_heels, 1 },
- { "help", 0, 0, 0 },
- { "output-file", 1, 0, 0 },
- { "rotate-clockwise", 0, (int *) &do_clockwise_rotation, 1 },
- { "verbose", 0, (int *) &verbose, 1 },
- { "version", 0, (int *) &printed_version, 1 },
- { 0, 0, 0, 0 } };
-
- while (true)
- {
- g = getopt_long_only (argc, argv, "", long_options, &option_index);
-
- if (g == EOF)
- break;
-
- if (g == '?')
- exit (1); /* Unknown option. */
-
- assert (g == 0); /* We have no short option names. */
-
- if (ARGUMENT_IS ("help"))
- {
- fprintf (stderr, "Usage: %s [options] <font_name>.\n", argv[0]);
- fprintf (stderr, USAGE);
- exit (0);
- }
-
- else if (ARGUMENT_IS ("output-file"))
- output_name = optarg;
-
- else if (ARGUMENT_IS ("version"))
- printf ("%s.\n", version_string);
-
- /* Else it was a flag; getopt has already done the assignment. */
- }
-
- /* Check that they asked to do exactly one thing. */
- if (!(do_head_over_heels || do_clockwise_rotation))
- {
- fprintf (stderr, "No operation specified.\n");
- fprintf (stderr, "For more information, use ``-help''.\n");
- exit (1);
- }
- else if (do_head_over_heels && do_clockwise_rotation)
- {
- fprintf (stderr, "Too many operations specified (sorry).\n");
- fprintf (stderr, "For more information, use ``-help''.\n");
- exit (1);
- }
-
- FINISH_COMMAND_LINE ();
- }
-