home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / cprog / newprt10.zip / GRAFFILE.CPP < prev    next >
C/C++ Source or Header  |  1992-02-17  |  15KB  |  581 lines

  1.  
  2. //Copyright 1991-1992 Roger Bedell All rights reserved
  3. //See the attached readme file for licensing information.
  4.  
  5.  
  6. #include "time.h"
  7. #include "stdlib.h"
  8. #include "stdio.h"
  9. #include "string.h"
  10. #include "io.h"
  11. #include "grafprnt.hpp"
  12. #include "graffile.hpp"
  13. #include "mem.h"
  14.  
  15. //global printer error flag  set to 1 on a printer error
  16. extern int printer_error_flag;
  17.  
  18. int check_for_user_input(void); //external function for allowing user abort
  19.  
  20.  
  21. //Constructor for the base class.
  22. graphics_file::graphics_file(char * filename)
  23. {
  24.     //open the file and save its file pointer
  25.     file_ptr = fopen(filename,"rb");
  26.     if(file_ptr == NULL)
  27.     {
  28.         error_message("Could not open .PCX file",NONFATAL);
  29.     }
  30.  
  31. }
  32.  
  33. //Constructor for the derived class.
  34. //pass the filename to the base class constructor
  35. pcx_graphics_file::pcx_graphics_file(char * filename):graphics_file(filename)
  36. {
  37.  
  38. }
  39.  
  40.  
  41.  
  42. //derived class for pcx file printing
  43. void pcx_graphics_file::print_file(void)
  44. {
  45.  
  46.     //in this case its a PCX file
  47.     //read the PCX header and decide on how we are going to approach
  48.     //it (16 or 256 color etc...)
  49.     if(fread((char *)&pcx_header, 1, sizeof(PCX_HEAD), file_ptr) != sizeof(PCX_HEAD))
  50.     {
  51.         //couldnt read the header
  52.         error_message("couldnt read pcx header", NONFATAL);
  53.         return;
  54.     }
  55.     //check for reasonable values in the header
  56.     if(pcx_header.manufacturer != 0x0a)
  57.     {
  58.         error_message("Bad PCX header", NONFATAL);
  59.         return;
  60.     }
  61.  
  62.     //allocate memory for the grey buffer.
  63.     //The grey buffer will hold one line of grey data,
  64.     //one byte per pixel.
  65.     grey_buffer_ptr = mem_malloc(pcx_header.xmax - pcx_header.xmin + 100);
  66.  
  67.     //figure out how to handle it,whether its a 256 or 16 color
  68.     //bitmap
  69.     if(pcx_header.bits_per_pixel == 8)
  70.     {
  71.         //print the body object
  72.         print_256_body();
  73.     }
  74.     else if(pcx_header.bits_per_pixel == 1 && pcx_header.color_planes == 4)
  75.     {
  76.         //print the body object
  77.         print_16_body();
  78.     }
  79.     else
  80.     {
  81.         error_message("Bad PCX header", NONFATAL);
  82.         return;
  83.     }
  84.     mem_free( grey_buffer_ptr);
  85.  
  86. }
  87.  
  88.  
  89. //body print for 256 color PCX files
  90. //Note, this hasn't been fully tested
  91. void pcx_graphics_file::print_256_body(void)
  92. {
  93.     //read the palette (256 colors)
  94.     if(read_256_palette() == -1)
  95.     {
  96.         return;
  97.     }
  98.  
  99.     //go to the start of the real data.
  100.     int return_code = fseek(file_ptr, 128L, SEEK_SET);
  101.     if (return_code != 0)
  102.     {
  103.         error_message("Could not seek to image data",NONFATAL);
  104.         return;
  105.     }
  106.  
  107.     long temp = ftell(file_ptr);
  108.  
  109.  
  110.     //create a printer object.
  111.     //get a pointer that will be of the correct printer type
  112.     //pass it the pixels per line so it knows how big to
  113.     //allocate its buffers
  114.  
  115.     printer = graphics_printer::allocate_graphics_printer(pcx_header.bytes_per_line);
  116.  
  117.     //read in each line, expanding the compression,
  118.     //and calculating the grey value from the palette as we go
  119.     //and put the results in the grey buffer.
  120.     int i,j;
  121.     int dup_count;
  122.     int dup_byte;
  123.     int read_byte;  //byte read in from the file
  124.     int num_lines = pcx_header.ymax - pcx_header.ymin;
  125.     int depth = pcx_header.ymax  - pcx_header.ymin;
  126.     int buffer_count;
  127.  
  128.     char *carry_buffer;  //carries stuff from the end of the line to another
  129.     int carry_count = 0;
  130.  
  131.     //carry buffer. Runs cant be longer than 256
  132.     carry_buffer = mem_malloc( 256 );
  133.  
  134.     for( i = 0; i < depth; i++)
  135.     {
  136.         buffer_count = 0; //how far we are in the buffer
  137.  
  138.         //put the stuff left over from the last run into the buffer
  139.         for( j = 0; j < carry_count; j ++)
  140.         {
  141.             grey_buffer_ptr[buffer_count] = carry_buffer[j];
  142.             buffer_count++;
  143.         }
  144.         carry_count = 0;
  145.  
  146.         do  //until we've unpacked a line
  147.         {
  148.             //get a byte.
  149.             read_byte = fgetc(file_ptr);
  150.             temp = ftell(file_ptr);
  151.             if(read_byte == EOF)
  152.             {
  153.                 error_message("Unexpected end of data", NONFATAL);
  154.                 break;
  155.             }
  156.             //trim off any upper stuff left over
  157.             read_byte &= 0xff;
  158.  
  159.             //see if it is a run of bytes indicator (a 0xC0)
  160.             if( (read_byte & 0xc0) == 0xc0 )
  161.             {
  162.                 //figure out how many bytes to duplicate
  163.                 dup_count = read_byte & 0x3f;
  164.  
  165.                 //get the byte to duplicate
  166.                 dup_byte = fgetc(file_ptr);
  167.  
  168.                 //convert the byte to the proper grey scale value
  169.                 dup_byte = grey_convert_256(dup_byte);
  170.  
  171.                 //add the dup byte to the output buffer dup_count times
  172.                 while(dup_count--)
  173.                 {
  174.                     if(buffer_count >= pcx_header.bytes_per_line - 1)
  175.                     {  //overflow of the line buffer. carry it over
  176.                         //to the next line
  177.                         carry_buffer[carry_count++] = (char)dup_byte;
  178.                     }
  179.                     else  //normal, add to the output buffer
  180.                     {
  181.                         grey_buffer_ptr[buffer_count++]=(char)dup_byte;
  182.                     }
  183.                 }
  184.             }
  185.             else    //only one byte, convert and save it in the buffer
  186.             {
  187.                 read_byte = grey_convert_256(read_byte);
  188.  
  189.                 grey_buffer_ptr[buffer_count++] = read_byte;
  190.             }
  191.         } while ( buffer_count < pcx_header.bytes_per_line );
  192.  
  193.         //at the end of each line, send it out to the printer
  194.         printer -> print_grey_line(grey_buffer_ptr, pcx_header.bytes_per_line);
  195.  
  196.         //check the printer error status
  197.         if(printer_error_flag == 1)
  198.         {
  199.             printer_error_flag = 0;
  200.             break;
  201.         }
  202.         //check for user input
  203.         //This allows the user to abort a print in mid-stream
  204.         if(check_for_user_input() == 1)
  205.         {
  206.             break;
  207.         }
  208.  
  209.     }
  210.  
  211.     //deallocate the printer object. Call a pseudo-destructor
  212.     //explicitly to make sure the right one is called (there may
  213.     //be a more elegant way to do this...)
  214.     printer->deallocate_graphics_printer();
  215.     delete printer;
  216.  
  217.     //deallocate carry buffer.
  218.     mem_free(carry_buffer);
  219.  
  220. }
  221.  
  222. int pcx_graphics_file::read_256_palette(void)
  223. {
  224.     //create a temporary rgb palette
  225.     unsigned char temp_palette[768];
  226.  
  227.     //go to the end, then back 769 bytes
  228.     fseek(file_ptr,-769L,SEEK_END);
  229.     long temp2 = ftell(file_ptr);
  230.  
  231.     //make sure the palette is there
  232.     int temp = fgetc(file_ptr);
  233.     temp2 = ftell(file_ptr);
  234.  
  235.     if(temp != 0x0c)
  236.     {
  237.         error_message("Could not read 256 color palette",NONFATAL);
  238.         return -1;
  239.     }
  240.  
  241.     //read the palette into the palette array
  242.     temp = fread(temp_palette, 1, 768, file_ptr);
  243.     temp2 = ftell(file_ptr);
  244.     if(temp != 768)
  245.     {
  246.         error_message("Could not read 256 color palette",NONFATAL);
  247.         return -1;
  248.     }
  249.  
  250.  
  251.     // Convert the RGB values to a grey scale number from 0-255
  252.     //See S.Rimmer, page 386
  253.     int i;
  254.     for( i = 0; i < 256; i++)
  255.     {
  256.         double red = 0.30 * double(temp_palette[i * 3]);
  257.         double green = 0.59 * double(temp_palette[(i * 3) +1]);
  258.         double blue = 0.11 * double(temp_palette[(i * 3) + 2]);
  259.  
  260.         double total = red + green + blue;
  261.  
  262.         unsigned char temp = unsigned char(total);
  263.  
  264.         palette_256[i] = temp;
  265.  
  266.     }
  267.  
  268.     return 0;
  269.  
  270. }
  271.  
  272.  
  273.  //now, a little contrast needs to be added via a lookup
  274. //table (Rimmer P388) to get a better looking image
  275. unsigned char greymap[256] =
  276.     {
  277.         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  278.         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  279.  
  280.         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  281.         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  282.  
  283.         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
  284.         0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
  285.  
  286.         0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
  287.         0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a,
  288.  
  289.         0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21,
  290.         0x22, 0x23, 0x23, 0x24, 0x25, 0x27, 0x27, 0x28,
  291.  
  292.         0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x2f,
  293.         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
  294.  
  295.         0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
  296.         0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
  297.  
  298.         0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
  299.         0x50, 0x51, 0x52, 0x53, 0x55, 0x56, 0x57, 0x58,
  300.  
  301.         0x59, 0x5a, 0x5b, 0x5d, 0x5e, 0x5f, 0x60, 0x61,
  302.         0x63, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6a, 0x6b,
  303.  
  304.         0x6c, 0x6e, 0x70, 0x72, 0x73, 0x74, 0x76, 0x78,
  305.         0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88,
  306.  
  307.         0x8a, 0x8c, 0x8f, 0x91, 0x93, 0x95, 0x98, 0x9a,
  308.         0x9c, 0x9f, 0xa1, 0xa4, 0xa6, 0xa9, 0xab, 0xae,
  309.  
  310.         0xb0, 0xb2, 0xb3, 0xb5, 0xb7, 0xb9, 0xba, 0xbc,
  311.         0xbd, 0xbe, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca,
  312.  
  313.         0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd9, 0xdb,
  314.         0xdd, 0xe0, 0xe3, 0xe6, 0xe8, 0xeb, 0xed, 0xef,
  315.  
  316.         0xf2, 0xf5, 0xf8, 0xfb, 0xfe, 0xfe, 0xfe, 0xfe,
  317.         0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
  318.  
  319.         0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
  320.         0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
  321.  
  322.         0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
  323.         0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe
  324.  
  325.     };
  326.  
  327.  
  328. int pcx_graphics_file::grey_convert_256(int convert_char)
  329. {
  330.     //the input is an index into the palette
  331.     //we just need to convert it to a grey scale value
  332.  
  333.      unsigned char grey_value = palette_256[convert_char];
  334.  
  335.     //brighten it up a little
  336.     int temp = grey_value + 30;
  337.     if(temp > 255)
  338.     {
  339.         temp = 255;
  340.     }
  341.     grey_value = char(temp);
  342.  
  343.  
  344.     //substitute the lookup grey value for the one derived from
  345.     //the palette
  346.  
  347.     return greymap[grey_value];
  348.  
  349. }
  350.  
  351.  
  352.  
  353. //body print for 16 color PCX files
  354. //These are in planes, a little different to decode and transform
  355. void pcx_graphics_file::print_16_body(void)
  356. {
  357.     //read the palette (16 colors)
  358.     if(read_16_palette() == -1)
  359.     {
  360.         return;
  361.     }
  362.  
  363.     //we should be already at the start of the data
  364.     long temp = ftell(file_ptr);
  365.  
  366.  
  367.     //create a printer object.
  368.     //get a pointer that will be of the correct printer type
  369.     //pass it the pixels per line so it knows how big to
  370.     //allocate its buffers
  371.     pixels_per_line = pcx_header.xmax - pcx_header.xmin;
  372.  
  373.     printer = graphics_printer::allocate_graphics_printer(pixels_per_line);
  374.  
  375.     //read in each line, expanding the compression,
  376.     //4 color pcx files are a little weird, the first line
  377.     //has the msbit of the palette index, the fourth line has
  378.     //the lsbit of the palett index etc So we need to read in
  379.     //four lines at a time, then convert to a grey line to
  380.     //output to the printer object
  381.     //and put the results in the grey buffer.
  382.     int i,j;
  383.     int dup_count;
  384.     int dup_byte;
  385.     int read_byte;  //byte read in from the file
  386.     int num_lines = pcx_header.ymax - pcx_header.ymin;
  387.     int depth = pcx_header.ymax  - pcx_header.ymin;
  388.     int buffer_count = 0;
  389.     int temp_line_count = 0;
  390.     char *temp_buffer[4];  //temporarily keeps the four lines
  391.     char *carry_buffer;  //carries stuff from the end of the line to another
  392.     int carry_count = 0;
  393.  
  394.  
  395.     FILE * testfile = fopen("testout.out","w");
  396.  
  397.     //allocate room for the temp buffers
  398.     for(i = 0; i < 4; i++)
  399.     {
  400.         temp_buffer[i] = mem_malloc( pcx_header.bytes_per_line + 256);
  401.     }
  402.     //carry buffer. Runs cant be longer than 256
  403.     carry_buffer = mem_malloc( 256 );
  404.  
  405.     for( i = 0; i < depth; i++)
  406.     {
  407.  
  408.         //do four lines at a time (four planes)
  409.         for(temp_line_count = 0; temp_line_count < 4; temp_line_count++)
  410.         {
  411.             buffer_count = 0;
  412.  
  413.             //put the stuff left over from the last run into the buffer
  414.             for( j = 0; j < carry_count; j ++)
  415.             {
  416.                 temp_buffer[temp_line_count][buffer_count] = carry_buffer[j];
  417.                 buffer_count++;
  418.             }
  419.             carry_count = 0;
  420.  
  421.             do  //until we've unpacked a line
  422.             {
  423.                 //get a byte.
  424.                 read_byte = fgetc(file_ptr);
  425.                 temp = ftell(file_ptr);
  426.  
  427.  
  428.                 if(read_byte == EOF)
  429.                 {
  430.                     error_message("Unexpected end of data", NONFATAL);
  431.                     break;
  432.                 }
  433.                 //trim off any upper stuff left over
  434.                 read_byte &= 0xff;
  435.  
  436.                 //see if it is a run of bytes indicator (a 0xC0)
  437.                 if( (read_byte & 0xc0) == 0xc0 )
  438.                 {
  439.                     //figure out how many bytes to duplicate
  440.                     dup_count = read_byte & 0x3f;
  441.  
  442.                     //get the byte to duplicate
  443.                     dup_byte = fgetc(file_ptr);
  444.  
  445.                     //add the dup byte to the output buffer dup_count times
  446.                     while(dup_count--)
  447.                     {
  448.                         if(buffer_count >= pcx_header.bytes_per_line -1 )
  449.                         {  //overflow of the line buffer. carry it over
  450.                             //to the next line
  451.                             carry_buffer[carry_count++] = (char)dup_byte;
  452.                         }
  453.                         else  //normal, add to the output buffer
  454.                         {
  455.                             temp_buffer[temp_line_count][buffer_count++]=
  456.                                     (char)dup_byte;
  457.                         }
  458.                     }
  459.                 }
  460.                 else    //only one byte, convert and save it in the buffer
  461.                 {
  462.                     temp_buffer[temp_line_count][buffer_count++]=(char)read_byte;
  463.                 }
  464.  
  465.             } while ( buffer_count < pcx_header.bytes_per_line );
  466.  
  467.  
  468.         }//end for
  469.  
  470.         //convert the 4 plane lines to one grey line
  471.         grey_convert_16(temp_buffer);
  472.  
  473.  
  474.         //at the end of each line, send it out to the printer
  475.         printer -> print_grey_line(grey_buffer_ptr, pixels_per_line);
  476.  
  477.         //check the printer error status
  478.         if(printer_error_flag == 1)
  479.         {
  480.             printer_error_flag = 0;
  481.             break;
  482.         }
  483.  
  484.         //check for user input
  485.         //This allows the user to abort a print in mid-stream
  486.         if(check_for_user_input() == 1)
  487.         {
  488.             break;
  489.         }
  490.  
  491.  
  492.     }
  493.  
  494.     //deallocate the printer object. Call a pseudo-destructor
  495.     //explicitly to make sure the right one is called (there may
  496.     //be a more elegant way to do this...)
  497.     printer->deallocate_graphics_printer();
  498.     delete printer;
  499.  
  500.     //deallocate room for the temp buffers
  501.     for(i = 0; i < 4; i++)
  502.     {
  503.         mem_free(temp_buffer[i]);
  504.     }
  505.     //deallocate carry buffer.
  506.     mem_free(carry_buffer);
  507.  
  508. }
  509.  
  510. //converts the 4 plane lines to one grey line
  511. int pcx_graphics_file::grey_convert_16(char * temp_buffer[4])
  512. {
  513.     int temp_palette_index = 0;
  514.  
  515.     for(int i = 0; i < pixels_per_line; i++)
  516.     {
  517.         temp_palette_index = 0;
  518.  
  519.         for(int j = 0; j < 4; j ++)
  520.         {
  521.             //which bit?
  522.             int bit_in_byte = 0x80 >> (i % 8 );
  523.             int byte_num = i / 8;
  524.  
  525.             //construct a palette index from the bits in each plane
  526.             //get the bit and put it in the temp palette index
  527.  
  528.             //see if its a one or a zero
  529.             if(bit_in_byte & temp_buffer[j][byte_num])
  530.             {  //its a one
  531.                 temp_palette_index |= 1 << j;
  532.             }
  533.             //else its a zero, so do nothing.
  534.  
  535.         }
  536.  
  537.         //so now we have the palette index, look up the grey palette
  538.         //and assign a grey 8 bit value to it and stick it in
  539.         //the grey buffer.
  540.  
  541.         int temp_int = palette_16[temp_palette_index];
  542.         if(temp_int > 255)
  543.         {
  544.             temp_int = 255;
  545.         }
  546.  
  547.         grey_buffer_ptr[i] = temp_int;
  548.  
  549.  
  550.     }
  551.     return 0;
  552.  
  553. }
  554.  
  555. //doesnt actually read anything, but sets up the
  556. //grey 16 color palette
  557. int pcx_graphics_file::read_16_palette(void)
  558. {
  559.  
  560.     // Convert the RGB values to a grey scale number from 0-255
  561.     //See S.Rimmer, page 386
  562.     int i;
  563.     for( i = 0; i < 16; i++)
  564.     {
  565.         double red = 0.30 * double(pcx_header.palette[i * 3]);
  566.         double green = 0.59 * double(pcx_header.palette[(i * 3) +1]);
  567.         double blue = 0.11 * double(pcx_header.palette[(i * 3) + 2]);
  568.  
  569.         double total = red + green + blue;
  570.  
  571.         unsigned char temp = unsigned char(total);
  572.  
  573.         palette_16[i] = temp;
  574.  
  575.     }
  576.  
  577.     return 0;
  578.  
  579.  
  580. }
  581.