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

  1.  
  2. //Copyright 1991-1992 Roger Bedell All rights reserved
  3. //See the attached readme file for licensing information.
  4.  
  5. #include "time.h"
  6. #include "stdlib.h"
  7. #include "stdio.h"
  8. #include "string.h"
  9. #include "io.h"
  10. #include "grafprnt.hpp"
  11. #include "graffile.hpp"
  12. #include "mem.h"
  13.  
  14. //global printer error flag  set to 1 on a printer error
  15. extern int printer_error_flag;
  16.  
  17. void * graphics_printer::allocate_graphics_printer(int pixels_per_line)
  18. {
  19.     void *printer_ptr;
  20.     //figure out which kind of printer to create
  21.     switch(printer_type)
  22.     {
  23.         case 1:
  24.         printer_ptr = new epson_24_graphics_printer(pixels_per_line);
  25.         break;
  26.         case 2:
  27.         printer_ptr = new hp_laser_graphics_printer(pixels_per_line);
  28.         break;
  29.     }
  30.     return printer_ptr;
  31.  
  32. }
  33.  
  34.  
  35. void graphics_printer::line_feed()
  36. {
  37.     char feed[3] = {0x0a,0x0d};
  38.     send_print_buffer(feed,2);
  39. }
  40.  
  41. extern int bbprinter_number;
  42. int send_cmd( char *line_buffer, int length );
  43. int opn_prt(char * path ,int i);
  44. int cls_prt(int flag);
  45. int flush_buf(void);
  46.  
  47.  
  48. void epson_24_graphics_printer::open_graphics_printer()
  49. {
  50.     port_handle = 4;  //prn device
  51.  
  52.     bbprinter_number = 0;
  53.     opn_prt("lpt1", 0);
  54.  
  55.     //send it the appropriate string for turn on
  56.     char turn_on_string[6]={0x1b,0x40,0x1b,0x33,0x18};
  57.  
  58.     send_print_buffer(turn_on_string, 5);
  59.  
  60.  
  61. }
  62. void hp_laser_graphics_printer::open_graphics_printer()
  63. {
  64.     port_handle = 4;  //prn device
  65.  
  66.     bbprinter_number = 0;
  67.     opn_prt("lpt1", 0);
  68.  
  69.     //set it to 300 dpi and prepare for graphics
  70.     send_print_buffer("\x1b*t300R", strlen("\x1b*t300R"));
  71.     send_print_buffer("\x1b*r0A", strlen("\x1b*r0A"));
  72.  
  73.  
  74. }
  75.  
  76.  
  77.  
  78.  
  79. void epson_24_graphics_printer::close_graphics_printer()
  80. {
  81. //send it the appropriate string for turn on
  82.     char turn_off_string[6]={0xC};
  83.  
  84.     send_print_buffer(turn_off_string, 1);
  85.  
  86. }
  87.  
  88. void hp_laser_graphics_printer::close_graphics_printer()
  89. {
  90. //send it the appropriate string for turn off
  91.     send_print_buffer("\x1b*rB", strlen("\x1b*rB"));
  92.     send_print_buffer("\x0c", strlen("\x0c"));
  93.  
  94. }
  95.  
  96. void graphics_printer::send_print_buffer(char * line_buffer, int length)
  97. {
  98.     send_cmd(line_buffer, length);
  99. }
  100.  
  101. void epson_24_graphics_printer::send_graphics_buffer(char * line_buffer, int length)
  102. {
  103.  
  104.     //for an epson, the width is in dot columns
  105.     //in this case three bytes for each column
  106.     int temp = length / 3;
  107.  
  108.     char n1 = temp % 256;
  109.     char n2 = temp / 256;
  110.  
  111.     //send the epson prelude to a graphics line
  112.     char turn_on_graphics_string[6]={0x1B,0x2A,0x27};
  113.     turn_on_graphics_string[3]=n1;
  114.     turn_on_graphics_string[4]=n2;
  115.     send_print_buffer(turn_on_graphics_string, 5);
  116.  
  117.     send_print_buffer(line_buffer, length);
  118.  
  119.     //do a line feed
  120.     char turn_off_graphics_string[6]={0xD,0xA};
  121.     send_print_buffer(turn_off_graphics_string, 2);
  122.  
  123. }
  124.  
  125.  
  126. void hp_laser_graphics_printer::send_graphics_buffer(unsigned char * line_buffer, int length)
  127. {
  128.  
  129.     //for an HP, the width is in dot columns
  130.     //in this case three bytes for each column
  131.  
  132.     //send the hp prelude to a graphics line
  133.     char turn_on_graphics[20];
  134.     sprintf(turn_on_graphics,"\x1b*b%dW", length);
  135.  
  136.     send_print_buffer(turn_on_graphics, strlen(turn_on_graphics));
  137.  
  138.     //send the data itself. no line feed is necessary
  139.     send_print_buffer((char *)line_buffer, length);
  140.  
  141. }
  142.  
  143.  
  144.  
  145.  
  146. //this is the entry to the printer from the graphics file object
  147. //a generic grey scaled line is passed to this method. The
  148. //printer object will then dither and print this line according
  149. //to the scaling factors required for the printer resolution and
  150. //page size.
  151.  
  152. void graphics_printer::print_grey_line(char * buffer, int buffer_length)
  153. {
  154.     //Set the object variables
  155.     grey_line_buffer = buffer;
  156.     grey_line_count = buffer_length;
  157.  
  158.     expand_grey_line();
  159.  
  160.     //send the expanded grey info to the ditherer a line at a time,
  161.     //then convert
  162.     //the dithered line to a line of bits, then send the line of bits
  163.     //to the printer
  164.     int i;
  165.     for(i = 0; i < expansion_factor_y; i++)
  166.     {
  167.         //send a line to the ditherer, it will produce a dithered line
  168.         dither_expanded_line(i);
  169.  
  170.         //send the line to the bits converter, produces a bits line
  171.         convert_dithered_line_to_bits();
  172.  
  173.         //send the bits line to the printer
  174.         bits_to_printer();
  175.  
  176.     }
  177.  
  178.  
  179. }
  180.  
  181.  
  182. //constructor
  183. //pass it the width of the pcx graphic so it can allocae buffers
  184. epson_24_graphics_printer::epson_24_graphics_printer(int pixels_per_line)
  185. {
  186.  
  187.     //set the expansion factors
  188.     expansion_factor_x = 2;
  189.     expansion_factor_y = 2;
  190.  
  191.     //init pin counter counts from 0 to 23 pins on this 24 pin ptr
  192.     pin_number = 0;
  193.  
  194.     //and the length of each line
  195.     len_expanded_lines = expansion_factor_x * pixels_per_line;
  196.  
  197.     //allocate memory for the various buffers
  198.     //allocate memory for the expansion buffer
  199.     for( int j = 0; j < expansion_factor_y; j++)
  200.     {
  201.         expansion_buffer[j] = mem_malloc(len_expanded_lines);
  202.         if(expansion_buffer[j] ==NULL)
  203.         {
  204.             error_message("Not enough memory for print buffer.",NONFATAL);
  205.             deallocate_graphics_printer();
  206.             return;
  207.         }
  208.     }
  209.  
  210.     //and for the dither buffer
  211.     for( j = 0; j < 2; j++)
  212.     {
  213.         dither_buffer[j] = mem_malloc(len_expanded_lines + 10);
  214.  
  215.         if(dither_buffer[j] ==NULL)
  216.         {
  217.             error_message("Not enough memory for print buffer.",NONFATAL);
  218.             deallocate_graphics_printer();
  219.             return;
  220.         }
  221.  
  222.         //set the dither buffer to all 129s so it will be white with
  223.         //very little error in the first line
  224.         memset(dither_buffer[j], 255, len_expanded_lines);
  225.     }
  226.  
  227.     completed_dither_buffer = mem_malloc(len_expanded_lines);
  228.  
  229.     if(completed_dither_buffer ==NULL)
  230.     {
  231.         error_message("Not enough memory for print buffer.",NONFATAL);
  232.         deallocate_graphics_printer();
  233.         return;
  234.     }
  235.     bits_buffer = mem_malloc(((len_expanded_lines) / 8) + 1);
  236.     if(bits_buffer ==NULL)
  237.     {
  238.         error_message("Not enough memory for print buffer.",NONFATAL);
  239.         deallocate_graphics_printer();
  240.         return;
  241.     }
  242.  
  243.     //and for the printer buffer itself.
  244.      printer_buffer = mem_malloc(len_expanded_lines * 3);
  245.     if(printer_buffer ==NULL)
  246.     {
  247.         error_message("Not enough memory for print buffer.",NONFATAL);
  248.         deallocate_graphics_printer();
  249.         return;
  250.     }
  251.      //clear it
  252.      memset(printer_buffer, 0, len_expanded_lines * 3);
  253.  
  254.     open_graphics_printer();
  255.  
  256. }
  257.  
  258. //destructor
  259. void epson_24_graphics_printer::deallocate_graphics_printer(void)
  260. {
  261.     int j;
  262.  
  263.     //deallocate the memory for the buffers
  264.     for( j = 0; j < expansion_factor_y; j++)
  265.     {
  266.         mem_free(expansion_buffer[j]);
  267.     }
  268.  
  269.  
  270.     //deallocate the memory for the buffers
  271.     for( j = 0; j < 2; j++)
  272.     {
  273.         mem_free(dither_buffer[j]);
  274.     }
  275.     mem_free(completed_dither_buffer);
  276.     mem_free(bits_buffer);
  277.  
  278.     mem_free(printer_buffer);
  279.  
  280.     close_graphics_printer();
  281. }
  282.  
  283. //constructor
  284. //pass it the width of the pcx graphic so it can allocae buffers
  285. hp_laser_graphics_printer::hp_laser_graphics_printer(int pixels_per_line)
  286. {
  287.  
  288.     //set the expansion factors
  289.     expansion_factor_x = 3;
  290.     expansion_factor_y = 3;
  291.  
  292.     //and the length of each line
  293.     len_expanded_lines = expansion_factor_x * pixels_per_line;
  294.  
  295.     //allocate memory for the various buffers
  296.     //allocate memory for the expansion buffer
  297.     for( int j = 0; j < expansion_factor_y; j++)
  298.     {
  299.         expansion_buffer[j] = mem_malloc(pixels_per_line * expansion_factor_x);
  300.         if(expansion_buffer[j] ==NULL)
  301.         {
  302.             error_message("Not enough memory for print buffer.",NONFATAL);
  303.             deallocate_graphics_printer();
  304.             return;
  305.         }
  306.     }
  307.  
  308.     //and for the dither buffer
  309.     for( j = 0; j < 2; j++)
  310.     {
  311.         dither_buffer[j] = mem_malloc(pixels_per_line * expansion_factor_x + 10);
  312.         if(dither_buffer[j] ==NULL)
  313.         {
  314.             error_message("Not enough memory for print buffer.",NONFATAL);
  315.             deallocate_graphics_printer();
  316.             return;
  317.         }
  318.  
  319.         //set the dither buffer to all 129s so it will be white with
  320.         //very little error in the first line
  321.         memset(dither_buffer[j], 255, len_expanded_lines);
  322.     }
  323.  
  324.     completed_dither_buffer = mem_malloc(len_expanded_lines);
  325.     if(completed_dither_buffer == NULL)
  326.     {
  327.         error_message("Not enough memory for print buffer.",NONFATAL);
  328.         deallocate_graphics_printer();
  329.         return;
  330.     }
  331.  
  332.     //and for the bits buffer. no printer buffer is needed
  333.     //as this is the final step
  334.     bits_buffer = mem_malloc(((len_expanded_lines) / 8) + 1);
  335.     if(bits_buffer ==NULL)
  336.     {
  337.         error_message("Not enough memory for print buffer.",NONFATAL);
  338.         deallocate_graphics_printer();
  339.         return;
  340.     }
  341.  
  342.     open_graphics_printer();
  343.  
  344. }
  345.  
  346. //destructor
  347. void hp_laser_graphics_printer::deallocate_graphics_printer(void)
  348. {
  349.     int j;
  350.  
  351.     //deallocate the memory for the buffers
  352.     for( j = 0; j < expansion_factor_y; j++)
  353.     {
  354.         mem_free(expansion_buffer[j]);
  355.     }
  356.     //deallocate the memory for the buffers
  357.     for( j = 0; j < 2; j++)
  358.     {
  359.         mem_free(dither_buffer[j]);
  360.     }
  361.     mem_free(completed_dither_buffer);
  362.     mem_free(bits_buffer);
  363.  
  364.     close_graphics_printer();
  365. }
  366.  
  367. //generic grey line expander. Given the x and y expansion
  368. //factors, we can expand the grey line into the expand buffer
  369. void graphics_printer::expand_grey_line()
  370. {
  371.     //currently we can only handle integral expansion factors
  372.     int i,j,k;
  373.  
  374.  
  375.     //for each and every byte in the grey line...
  376.     for( i = 0; i < grey_line_count; i++)
  377.     {
  378.         //expand the number of times specified in the y direction
  379.         for( j = 0; j < expansion_factor_y; j++)
  380.         {
  381.             //expand the number of times specified in the x direction
  382.             for( k = 0; k < expansion_factor_x; k++)
  383.             {
  384.                 expansion_buffer[j][(i * expansion_factor_x) + k] =
  385.                             grey_line_buffer[i];
  386.             }
  387.          }
  388.  
  389.     }
  390.  
  391. }
  392.  
  393. void graphics_printer::dither_expanded_line(int line_number)
  394. {
  395.     //takes the specified expanded line and puts it into the
  396.     //bottom of the dither buffer. Then runs the Floyd Steinberg
  397.     //dither algorithm on the three lines in the buffer. When
  398.     //done, takes the top line and copies it into the completed
  399.     //dithered line buffer.
  400.  
  401.     //copy the second line into the first
  402.     memcpy(dither_buffer[0], dither_buffer[1], len_expanded_lines);
  403.  
  404.     //and the new one into the second
  405.     memcpy(dither_buffer[1], expansion_buffer[line_number], len_expanded_lines);
  406.  
  407.     int error;
  408.     //apply Floyd Steinberg dither to the dither buffer
  409.     //go along the top row and diffuse the errors that are seen
  410.     //however, do a serpentine scan. Dither from the left
  411.     //to right one time, then right to left the next time
  412.  
  413.  
  414.     if(serpentine == 0)
  415.     {   //left to right
  416.         serpentine = 1;
  417.         for( int i = 1; i < len_expanded_lines - 2; i++)
  418.         {
  419.             if(dither_buffer[0][i] > 128)  //it will be white
  420.             {
  421.                 //calculate the error (since its not quite white)
  422.                 error = dither_buffer[0][i] - 255;
  423.             }
  424.             else   //it will be a black dot
  425.             {
  426.                 //calculate the error (since its not quite black)
  427.                 error = dither_buffer[0][i];
  428.             }
  429.  
  430.             //Now distribute the error.
  431.             //see Rimmer P.391
  432.             dither_buffer[0][i + 1] += (7 * error) / 16;
  433.             dither_buffer[1][i - 1] += (3 * error) / 16;
  434.             dither_buffer[1][i] += (5 * error) / 16;
  435.             dither_buffer[1][i + 1] += (1 * error) / 16;
  436.  
  437.         }
  438.     }
  439.     else    //dither right to left
  440.     {
  441.         serpentine = 0;
  442.         for( int i = len_expanded_lines; i > 2; i--)
  443.         {
  444.             if(dither_buffer[0][i] > 128)  //it will be white
  445.             {
  446.                 //calculate the error (since its not quite white)
  447.                 error = dither_buffer[0][i] - 255;
  448.             }
  449.             else   //it will be a black dot
  450.             {
  451.                 //calculate the error (since its not quite black)
  452.                 error = dither_buffer[0][i];
  453.             }
  454.  
  455.             //Now distribute the error.
  456.             //see Rimmer P.391
  457.             dither_buffer[0][i + 1] += (7 * error) / 16;
  458.             dither_buffer[1][i - 1] += (3 * error) / 16;
  459.             dither_buffer[1][i] += (5 * error) / 16;
  460.             dither_buffer[1][i + 1] += (1 * error) / 16;
  461.  
  462.         }
  463.  
  464.  
  465.     }
  466.  
  467.     //Copy the completed first line to the completed dither buffer
  468.     memcpy(completed_dither_buffer, dither_buffer[0], len_expanded_lines);
  469.  
  470.  
  471. }
  472.  
  473. void graphics_printer::convert_dithered_line_to_bits(void)
  474. {
  475.     //takes the dithered line buffer and converts it to
  476.     //a single line of bits using a threshold of 128
  477.  
  478.     char set_byte;
  479.  
  480.     //clear the bits buffer to all zeros
  481.     memset(bits_buffer, 0 , (len_expanded_lines / 8)+1);
  482.  
  483.     for( int i = 0; i < len_expanded_lines; i++)
  484.     {
  485.         if(completed_dither_buffer[i] > 128)
  486.         {
  487.             //its white, so dont print it (0)
  488.             //(nothing needs to be done)
  489.         }
  490.         else   //its black, so print it (1)
  491.         {
  492.             set_byte = 1;  //start with one
  493.  
  494.             set_byte = set_byte << (i % 8);  //left shift to get it in the right spot
  495.  
  496.             bits_buffer[i / 8] |= set_byte; //Or it to set the right bit
  497.         }
  498.     }
  499.  
  500.  
  501. }
  502.  
  503. void graphics_printer::bits_to_printer(void)
  504. {
  505.     //takes the line of bits and sends it to the printer. If its
  506.     //a dot matrix, this is a little more complicated, but
  507.     //eventually the printer prints out a line made of these bits.
  508.     //laser printers are really easy!
  509. }
  510.  
  511. void epson_24_graphics_printer::bits_to_printer(void)
  512. {
  513.     //takes the line of bits and sends it to the printer.
  514.     //In this case, the orientation of the pins on the printer
  515.     //and how they are addressed assume primary proportion
  516.     //In a 24 pin printer, there are three bytes for each
  517.     //24 pin impact. What we will do is set the bits for
  518.     //the top pin all the way across the paper, then the
  519.     //second pin the next time this routine is called etc.
  520.     //when we've done this 24 times, we ship the whole thing
  521.     //out to the printer.
  522.  
  523.     //we're dealing with the same pin all the way across the swath
  524.     int pin_row_byte = pin_number / 8;
  525.     int pin_row_bit = pin_number % 8;
  526.     //Top pin is the MSBit
  527.     unsigned char pin_row_set_bit = 0x80 >> pin_row_bit;
  528.  
  529.     for( int i = 0; i < len_expanded_lines; i++)
  530.     {
  531.         //see if the ith bit is 1 or 0 and
  532.         //set the corresponding bit in the printer buffer
  533.         unsigned char set_byte = 0x01;  //start with one
  534.  
  535.         set_byte = set_byte << (i % 8);  //left shift to get it in the right spot
  536.  
  537.         //Note that the least significant bit in the
  538.         //3 byte word controls the bottom pin, the most
  539.         //significant bit controls the top pin
  540.         if(bits_buffer[i / 8] & set_byte)  //set or not?
  541.         {
  542.             //its a one!
  543.             //so set the pin in the swath . This is the final step
  544.             //before printing
  545.             printer_buffer[( i * 3 )  + pin_row_byte  ] |= pin_row_set_bit;
  546.         }
  547.         else
  548.         {//do nothing
  549.         }
  550.  
  551.     }
  552.  
  553.     if(++pin_number >= 24)
  554.     {
  555.         //print the swath
  556.         send_graphics_buffer(printer_buffer,len_expanded_lines * 3);
  557. //        printf("Swath printed.\n");
  558.  
  559.         //clear out the printer buffer
  560.         memset(printer_buffer, 0, len_expanded_lines * 3);
  561.  
  562.         //reset the pin counter
  563.         pin_number = 0;
  564.     }
  565.  
  566.  
  567. }
  568.  
  569.  
  570. void reverse_bytes_in_buffer(unsigned char *buffer, int len);
  571.  
  572. void hp_laser_graphics_printer::bits_to_printer(void)
  573. {
  574.     //takes the line of bits and sends it to the printer.
  575.     //In this case, the orientation of the pins on the printer
  576.     //and how they are addressed assume primary proportion
  577.     //In a laser printer, there is one bit for each dot
  578.  
  579.     //just ship them out the way they are in the dot buffer
  580.  
  581.     //reverse the bytes, then ship them out
  582.     reverse_bytes_in_buffer(bits_buffer, len_expanded_lines / 8);
  583.     send_graphics_buffer(bits_buffer, len_expanded_lines / 8);
  584.  
  585. }
  586.  
  587. //for each byte in the buffer, reverse the bit order
  588. void reverse_bytes_in_buffer(unsigned char *buffer, int len)
  589. {
  590.     //for each byte in the buffer, reverse the bit order
  591.     for(int i = 0; i < len; i ++)
  592.     {
  593.         char temp_char = buffer[i];
  594.         char temp_char2 = 0;
  595.  
  596.         for (int j=0; j < 8; j++)
  597.         {
  598.             temp_char2 = temp_char2 << 1;
  599.  
  600.             if(temp_char & 1 == 1)
  601.             {
  602.                 //or a one to the the end result
  603.                 temp_char2 |= 1;
  604.             }
  605.             //left shift the end result and right shift the temp
  606.             temp_char = temp_char >> 1;
  607.  
  608.         }
  609.         buffer[i] = temp_char2;
  610.     }
  611.  
  612. }
  613.  
  614.  
  615.