
/*
**
**  TARGA File 'AntiAlias' program
**
**  Written by Brian Reed  Copyright 1989
**  This file is provided as a sample for reading TARGA 'type 2' images.
**
**  This program runs only from the CLI, and requires two parameters.
**  The parameters are the file names for the input and output files.
**  They MUST not be the same file.  This works on only 'uncompressed RGB
**  (type 2)' 24-bit TARGA files.
**
**  -  Error checking (file i/o) could stand to be improved.
**
*/
/*  You must compile this using the 32 bit mode and libraries  */


/*  include files  */
#include <stdio.h>

FILE *fopen(), *infile=0, *outfile=0;
char output[82], input[82];
int  pixels_x_in, pixels_y_in, pixels_x_out, pixels_y_out;
int  header_len, bpl, bpl2, file_id_len, offset_x_in, offset_y_in;
unsigned char header_buffer_in[20], header_buffer_out[20];
unsigned char file_id_buffer[256];

unsigned char *pixel_line_1=NULL, *pixel_line_2=NULL, *pixel_line_3=NULL;

/*  This is it...  */
main(argc, argv)
int argc;
char *argv[];
{
int i;

  if (argc != 3 || (!strcmp(argv[1], "?")) ) {
    printf("Usage:  Aa input output\n");
    exit(0);
  }
  if ( (!strcmp(argv[1], argv[2])) ) {
    printf("Filenames must be different.\n");
    exit(0);
  }

  read_targa_header(argv[1]);

  /*  Allocate memory  */
  if ( (pixel_line_1 = malloc((int)(pixels_x_in*3+4))) == NULL)
    done("Couldn't allocate buffer 1");
  if ( (pixel_line_2 = malloc((int)(pixels_x_in*3+4))) == NULL)
    done("Couldn't allocate buffer 2");
  if ( (pixel_line_3 = malloc((int)(pixels_x_out*3+4))) == NULL)
    done("Couldn't allocate buffer 3");

 write_targa_header(argv[2]);

  for (i=0; i<pixels_y_out; i++) {
    if (read_targa_lines()) {
      anti_alias_targa_line();
      write_targa_line();
    }
  }

  done("Done!");
}

read_targa_header(name)
char *name;
{
int size=1;

  /*  Open file  */
   if ((infile = fopen(name, "r")) == NULL)
     done("Couldn't open infile for reading.");

  /*************  Fields 1 thru 5:                *********/
    size = 18;
    fread(header_buffer_in, (int)size, (int)1, infile);

    if (header_buffer_in[2] != 2)
      done("Not a 24 bit/pixel file.");
    if (header_buffer_in[16] != 24)
      done("Not a 24 bit/pixel file.");

  /*************  Field 6:  Image ID field    *************/
    file_id_len = header_buffer_in[0];
    header_len = file_id_len + 18;
    fread(file_id_buffer, (int)file_id_len, (int)1, infile);
    file_id_buffer[file_id_len] = 0;

  /*************  Set image stats  ***************/
    offset_x_in = header_buffer_in[9] * 256 + header_buffer_in[8];
    offset_y_in = header_buffer_in[11] * 256 + header_buffer_in[10];
    pixels_x_in = header_buffer_in[13] * 256 + header_buffer_in[12];
    pixels_y_in = header_buffer_in[15] * 256 + header_buffer_in[14];
    bpl = pixels_x_in * 3;   /*  BytesPerLine  */
    bpl2 = bpl / 2;
    pixels_x_out = pixels_x_in / 2;
    pixels_y_out = pixels_y_in / 2;
    printf("Picture size is %d x %d\n", pixels_x_in, pixels_y_in);
    printf("Picture offset is %d x %d\n", offset_x_in, offset_y_in);
}

read_targa_lines()
{
  if (fread(pixel_line_1, (int)bpl, (int)1, infile) != 1)
    return(0);
  if (fread(pixel_line_2, (int)bpl, (int)1, infile) != 1)
    return(0);
  return(1);
}

write_targa_header(name)
char *name;
{
unsigned int lsb, msb;
int i, size = 18;

  for (i=0; i<size; i++)
    header_buffer_out[i] = header_buffer_in[i];

  lsb = pixels_x_out;
  msb=0;
  while (lsb > 255) {
    lsb -= 256;
    msb++;
  }
  header_buffer_out[12] = lsb;
  header_buffer_out[13] = msb;

  lsb = pixels_y_out;
  msb=0;
  while (lsb > 255) {
    lsb -= 256;
    msb++;
  }
  header_buffer_out[14] = lsb;
  header_buffer_out[15] = msb;

  if ((outfile = fopen(name, "w")) == NULL)
    done("Couldn't open outfile for writing.");

  fwrite(header_buffer_out, (int)size, (int)1, outfile);
  fwrite(file_id_buffer, (int)file_id_len, (int)1, outfile);
}

write_targa_line()
{
  if (fwrite(pixel_line_3, (int)bpl2, (int)1, outfile) != 1)
    done("Couldn't write 24-bit line");
}

anti_alias_targa_line()
{
int i;
float total;

  /*  This goes through all pixels, and averages 4 together into  */
  /*    one pixel...  RG&B separate  */
  for (i=0; i<pixels_x_out; i++) {
    /*  Red  */
    total = pixel_line_1[i*6+0] + pixel_line_1[i*6+3] +
            pixel_line_2[i*6+0] + pixel_line_2[i*6+3];
    total /= 4;
    pixel_line_3[i*3+0] = total;
    /*  Green  */
    total = pixel_line_1[i*6+1] + pixel_line_1[i*6+4] +
            pixel_line_2[i*6+1] + pixel_line_2[i*6+4];
    total /= 4;
    pixel_line_3[i*3+1] = total;
    /*  Blue  */
    total = pixel_line_1[i*6+2] + pixel_line_1[i*6+5] +
            pixel_line_2[i*6+2] + pixel_line_2[i*6+5];
    total /= 4;
    pixel_line_3[i*3+2] = total;
  }
}

done(s)
char *s;
{
  if (infile)  fclose(infile);
  if (outfile)  fclose(outfile);
  if (pixel_line_1)
    free(pixel_line_1);
  if (pixel_line_2)
    free(pixel_line_2);
  if (pixel_line_3)
    free(pixel_line_3);
  if (s)  printf("Aa: %s\n", s);
  exit(0);
}

