17dd7cddfSDavid du Colombier /* Copyright (C) 1992, 1996, 1997 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
177dd7cddfSDavid du Colombier #include "gdevprn.h"
187dd7cddfSDavid du Colombier
197dd7cddfSDavid du Colombier
20*593dc095SDavid du Colombier /* $Id: gdevdm24.c,v 1.8 2004/08/04 23:33:29 stefan Exp $*/
217dd7cddfSDavid du Colombier /* High-res 24Dot-matrix printer driver */
227dd7cddfSDavid du Colombier
237dd7cddfSDavid du Colombier /* Supported printers
247dd7cddfSDavid du Colombier * NEC P6 and similar, implemented by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de)
257dd7cddfSDavid du Colombier * Epson LQ850, implemented by Christian Felsch (felsch@tu-harburg.d400.de)
267dd7cddfSDavid du Colombier */
277dd7cddfSDavid du Colombier
287dd7cddfSDavid du Colombier /* Driver for NEC P6 */
297dd7cddfSDavid du Colombier private dev_proc_print_page (necp6_print_page);
303ff48bf5SDavid du Colombier const gx_device_printer far_data gs_necp6_device =
317dd7cddfSDavid du Colombier prn_device (prn_std_procs, "necp6",
327dd7cddfSDavid du Colombier DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
337dd7cddfSDavid du Colombier 360, 360,
347dd7cddfSDavid du Colombier 0, 0, 0.5, 0, /* margins */
357dd7cddfSDavid du Colombier 1, necp6_print_page);
367dd7cddfSDavid du Colombier
377dd7cddfSDavid du Colombier
387dd7cddfSDavid du Colombier /* Driver for Epson LQ850 */
397dd7cddfSDavid du Colombier /* I've tested this driver on a BJ300 with LQ850 emulation and there it produce correct 360x360dpi output. */
407dd7cddfSDavid du Colombier private dev_proc_print_page (lq850_print_page);
413ff48bf5SDavid du Colombier const gx_device_printer gs_lq850_device =
427dd7cddfSDavid du Colombier prn_device (prn_std_procs, "lq850",
437dd7cddfSDavid du Colombier DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
447dd7cddfSDavid du Colombier 360, 360,
457dd7cddfSDavid du Colombier 0, 0, 0.5, 0, /* margins */
467dd7cddfSDavid du Colombier 1, lq850_print_page);
477dd7cddfSDavid du Colombier
487dd7cddfSDavid du Colombier /* ------ Internal routines ------ */
497dd7cddfSDavid du Colombier
507dd7cddfSDavid du Colombier /* Forward references */
51*593dc095SDavid du Colombier private void dot24_output_run (byte *, int, int, FILE *);
52*593dc095SDavid du Colombier private void dot24_improve_bitmap (byte *, int);
537dd7cddfSDavid du Colombier
547dd7cddfSDavid du Colombier /* Send the page to the printer. */
557dd7cddfSDavid du Colombier private int
dot24_print_page(gx_device_printer * pdev,FILE * prn_stream,char * init_string,int init_len)567dd7cddfSDavid du Colombier dot24_print_page (gx_device_printer *pdev, FILE *prn_stream, char *init_string, int init_len)
577dd7cddfSDavid du Colombier {
58*593dc095SDavid du Colombier int xres = (int)pdev->x_pixels_per_inch;
59*593dc095SDavid du Colombier int yres = (int)pdev->y_pixels_per_inch;
607dd7cddfSDavid du Colombier int x_high = (xres == 360);
617dd7cddfSDavid du Colombier int y_high = (yres == 360);
627dd7cddfSDavid du Colombier int bits_per_column = (y_high ? 48 : 24);
637dd7cddfSDavid du Colombier uint line_size = gdev_prn_raster (pdev);
647dd7cddfSDavid du Colombier uint in_size = line_size * bits_per_column;
65*593dc095SDavid du Colombier byte *in = (byte *) gs_malloc (pdev->memory, in_size, 1, "dot24_print_page (in)");
667dd7cddfSDavid du Colombier uint out_size = ((pdev->width + 7) & -8) * 3;
67*593dc095SDavid du Colombier byte *out = (byte *) gs_malloc (pdev->memory, out_size, 1, "dot24_print_page (out)");
687dd7cddfSDavid du Colombier int y_passes = (y_high ? 2 : 1);
697dd7cddfSDavid du Colombier int dots_per_space = xres / 10; /* pica space = 1/10" */
707dd7cddfSDavid du Colombier int bytes_per_space = dots_per_space * 3;
717dd7cddfSDavid du Colombier int skip = 0, lnum = 0, ypass;
727dd7cddfSDavid du Colombier
737dd7cddfSDavid du Colombier /* Check allocations */
747dd7cddfSDavid du Colombier if (in == 0 || out == 0)
757dd7cddfSDavid du Colombier {
767dd7cddfSDavid du Colombier if (out)
77*593dc095SDavid du Colombier gs_free (pdev->memory, (char *) out, out_size, 1, "dot24_print_page (out)");
787dd7cddfSDavid du Colombier if (in)
79*593dc095SDavid du Colombier gs_free (pdev->memory, (char *) in, in_size, 1, "dot24_print_page (in)");
807dd7cddfSDavid du Colombier return_error (gs_error_VMerror);
817dd7cddfSDavid du Colombier }
827dd7cddfSDavid du Colombier
837dd7cddfSDavid du Colombier /* Initialize the printer and reset the margins. */
847dd7cddfSDavid du Colombier fwrite (init_string, init_len - 1, sizeof (char), prn_stream);
857dd7cddfSDavid du Colombier fputc ((int) (pdev->width / pdev->x_pixels_per_inch * 10) + 2,
867dd7cddfSDavid du Colombier prn_stream);
877dd7cddfSDavid du Colombier
887dd7cddfSDavid du Colombier /* Print lines of graphics */
897dd7cddfSDavid du Colombier while (lnum < pdev->height)
907dd7cddfSDavid du Colombier {
917dd7cddfSDavid du Colombier byte *inp;
927dd7cddfSDavid du Colombier byte *in_end;
937dd7cddfSDavid du Colombier byte *out_end;
947dd7cddfSDavid du Colombier byte *out_blk;
957dd7cddfSDavid du Colombier register byte *outp;
967dd7cddfSDavid du Colombier int lcnt;
977dd7cddfSDavid du Colombier
987dd7cddfSDavid du Colombier /* Copy 1 scan line and test for all zero. */
997dd7cddfSDavid du Colombier gdev_prn_copy_scan_lines (pdev, lnum, in, line_size);
1007dd7cddfSDavid du Colombier if (in[0] == 0
1017dd7cddfSDavid du Colombier && !memcmp ((char *) in, (char *) in + 1, line_size - 1))
1027dd7cddfSDavid du Colombier {
1037dd7cddfSDavid du Colombier lnum++;
1047dd7cddfSDavid du Colombier skip += 2 - y_high;
1057dd7cddfSDavid du Colombier continue;
1067dd7cddfSDavid du Colombier }
1077dd7cddfSDavid du Colombier
1087dd7cddfSDavid du Colombier /* Vertical tab to the appropriate position. */
1097dd7cddfSDavid du Colombier while ((skip >> 1) > 255)
1107dd7cddfSDavid du Colombier {
1117dd7cddfSDavid du Colombier fputs ("\033J\377", prn_stream);
1127dd7cddfSDavid du Colombier skip -= 255 * 2;
1137dd7cddfSDavid du Colombier }
1147dd7cddfSDavid du Colombier
1157dd7cddfSDavid du Colombier if (skip)
1167dd7cddfSDavid du Colombier {
1177dd7cddfSDavid du Colombier if (skip >> 1)
1187dd7cddfSDavid du Colombier fprintf (prn_stream, "\033J%c", skip >> 1);
1197dd7cddfSDavid du Colombier if (skip & 1)
1207dd7cddfSDavid du Colombier fputc ('\n', prn_stream);
1217dd7cddfSDavid du Colombier }
1227dd7cddfSDavid du Colombier
1237dd7cddfSDavid du Colombier /* Copy the rest of the scan lines. */
1247dd7cddfSDavid du Colombier if (y_high)
1257dd7cddfSDavid du Colombier {
1267dd7cddfSDavid du Colombier inp = in + line_size;
1277dd7cddfSDavid du Colombier for (lcnt = 1; lcnt < 24; lcnt++, inp += line_size)
1287dd7cddfSDavid du Colombier if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2, inp,
1297dd7cddfSDavid du Colombier line_size))
1307dd7cddfSDavid du Colombier {
1317dd7cddfSDavid du Colombier memset (inp, 0, (24 - lcnt) * line_size);
1327dd7cddfSDavid du Colombier break;
1337dd7cddfSDavid du Colombier }
1347dd7cddfSDavid du Colombier inp = in + line_size * 24;
1357dd7cddfSDavid du Colombier for (lcnt = 0; lcnt < 24; lcnt++, inp += line_size)
1367dd7cddfSDavid du Colombier if (!gdev_prn_copy_scan_lines (pdev, lnum + lcnt * 2 + 1, inp,
1377dd7cddfSDavid du Colombier line_size))
1387dd7cddfSDavid du Colombier {
1397dd7cddfSDavid du Colombier memset (inp, 0, (24 - lcnt) * line_size);
1407dd7cddfSDavid du Colombier break;
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier }
1437dd7cddfSDavid du Colombier else
1447dd7cddfSDavid du Colombier {
1457dd7cddfSDavid du Colombier lcnt = 1 + gdev_prn_copy_scan_lines (pdev, lnum + 1, in + line_size,
1467dd7cddfSDavid du Colombier in_size - line_size);
1477dd7cddfSDavid du Colombier if (lcnt < 24)
1487dd7cddfSDavid du Colombier /* Pad with lines of zeros. */
1497dd7cddfSDavid du Colombier memset (in + lcnt * line_size, 0, in_size - lcnt * line_size);
1507dd7cddfSDavid du Colombier }
1517dd7cddfSDavid du Colombier
1527dd7cddfSDavid du Colombier for (ypass = 0; ypass < y_passes; ypass++)
1537dd7cddfSDavid du Colombier {
1547dd7cddfSDavid du Colombier out_end = out;
1557dd7cddfSDavid du Colombier inp = in;
1567dd7cddfSDavid du Colombier if (ypass)
1577dd7cddfSDavid du Colombier inp += line_size * 24;
1587dd7cddfSDavid du Colombier in_end = inp + line_size;
1597dd7cddfSDavid du Colombier
1607dd7cddfSDavid du Colombier for (; inp < in_end; inp++, out_end += 24)
1617dd7cddfSDavid du Colombier {
1627dd7cddfSDavid du Colombier memflip8x8 (inp, line_size, out_end, 3);
1637dd7cddfSDavid du Colombier memflip8x8 (inp + line_size * 8, line_size, out_end + 1, 3);
1647dd7cddfSDavid du Colombier memflip8x8 (inp + line_size * 16, line_size, out_end + 2, 3);
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier /* Remove trailing 0s. */
1677dd7cddfSDavid du Colombier while (out_end - 3 >= out && out_end[-1] == 0
1687dd7cddfSDavid du Colombier && out_end[-2] == 0 && out_end[-3] == 0)
1697dd7cddfSDavid du Colombier out_end -= 3;
1707dd7cddfSDavid du Colombier
1717dd7cddfSDavid du Colombier for (out_blk = outp = out; outp < out_end;)
1727dd7cddfSDavid du Colombier {
1737dd7cddfSDavid du Colombier /* Skip a run of leading 0s. */
1747dd7cddfSDavid du Colombier /* At least 10 are needed to make tabbing worth it. */
1757dd7cddfSDavid du Colombier
1767dd7cddfSDavid du Colombier if (outp[0] == 0 && outp + 12 <= out_end
1777dd7cddfSDavid du Colombier && outp[1] == 0 && outp[2] == 0
1787dd7cddfSDavid du Colombier && outp[3] == 0 && outp[4] == 0 && outp[5] == 0
1797dd7cddfSDavid du Colombier && outp[6] == 0 && outp[7] == 0 && outp[8] == 0
1807dd7cddfSDavid du Colombier && outp[9] == 0 && outp[10] == 0 && outp[11] == 0)
1817dd7cddfSDavid du Colombier {
1827dd7cddfSDavid du Colombier byte *zp = outp;
1837dd7cddfSDavid du Colombier int tpos;
1847dd7cddfSDavid du Colombier byte *newp;
1857dd7cddfSDavid du Colombier outp += 12;
1867dd7cddfSDavid du Colombier while (outp + 3 <= out_end
1877dd7cddfSDavid du Colombier && outp[0] == 0 && outp[1] == 0 && outp[2] == 0)
1887dd7cddfSDavid du Colombier outp += 3;
1897dd7cddfSDavid du Colombier tpos = (outp - out) / bytes_per_space;
1907dd7cddfSDavid du Colombier newp = out + tpos * bytes_per_space;
1917dd7cddfSDavid du Colombier if (newp > zp + 10)
1927dd7cddfSDavid du Colombier {
1937dd7cddfSDavid du Colombier /* Output preceding bit data. */
1947dd7cddfSDavid du Colombier /* only false at beginning of line */
1957dd7cddfSDavid du Colombier if (zp > out_blk)
1967dd7cddfSDavid du Colombier {
1977dd7cddfSDavid du Colombier if (x_high)
1987dd7cddfSDavid du Colombier dot24_improve_bitmap (out_blk, (int) (zp - out_blk));
1997dd7cddfSDavid du Colombier dot24_output_run (out_blk, (int) (zp - out_blk),
2007dd7cddfSDavid du Colombier x_high, prn_stream);
2017dd7cddfSDavid du Colombier }
2027dd7cddfSDavid du Colombier /* Tab over to the appropriate position. */
2037dd7cddfSDavid du Colombier fprintf (prn_stream, "\033D%c%c\t", tpos, 0);
2047dd7cddfSDavid du Colombier out_blk = outp = newp;
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier }
2077dd7cddfSDavid du Colombier else
2087dd7cddfSDavid du Colombier outp += 3;
2097dd7cddfSDavid du Colombier }
2107dd7cddfSDavid du Colombier if (outp > out_blk)
2117dd7cddfSDavid du Colombier {
2127dd7cddfSDavid du Colombier if (x_high)
2137dd7cddfSDavid du Colombier dot24_improve_bitmap (out_blk, (int) (outp - out_blk));
2147dd7cddfSDavid du Colombier dot24_output_run (out_blk, (int) (outp - out_blk), x_high,
2157dd7cddfSDavid du Colombier prn_stream);
2167dd7cddfSDavid du Colombier }
2177dd7cddfSDavid du Colombier
2187dd7cddfSDavid du Colombier fputc ('\r', prn_stream);
2197dd7cddfSDavid du Colombier if (ypass < y_passes - 1)
2207dd7cddfSDavid du Colombier fputc ('\n', prn_stream);
2217dd7cddfSDavid du Colombier }
2227dd7cddfSDavid du Colombier skip = 48 - y_high;
2237dd7cddfSDavid du Colombier lnum += bits_per_column;
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier
2267dd7cddfSDavid du Colombier /* Eject the page and reinitialize the printer */
2277dd7cddfSDavid du Colombier fputs ("\f\033@", prn_stream);
2287dd7cddfSDavid du Colombier fflush (prn_stream);
2297dd7cddfSDavid du Colombier
230*593dc095SDavid du Colombier gs_free (pdev->memory, (char *) out, out_size, 1, "dot24_print_page (out)");
231*593dc095SDavid du Colombier gs_free (pdev->memory, (char *) in, in_size, 1, "dot24_print_page (in)");
2327dd7cddfSDavid du Colombier
2337dd7cddfSDavid du Colombier return 0;
2347dd7cddfSDavid du Colombier }
2357dd7cddfSDavid du Colombier
2367dd7cddfSDavid du Colombier /* Output a single graphics command. */
2377dd7cddfSDavid du Colombier private void
dot24_output_run(byte * data,int count,int x_high,FILE * prn_stream)2387dd7cddfSDavid du Colombier dot24_output_run (byte *data, int count, int x_high, FILE *prn_stream)
2397dd7cddfSDavid du Colombier {
2407dd7cddfSDavid du Colombier int xcount = count / 3;
2417dd7cddfSDavid du Colombier fputc (033, prn_stream);
2427dd7cddfSDavid du Colombier fputc ('*', prn_stream);
2437dd7cddfSDavid du Colombier fputc ((x_high ? 40 : 39), prn_stream);
2447dd7cddfSDavid du Colombier fputc (xcount & 0xff, prn_stream);
2457dd7cddfSDavid du Colombier fputc (xcount >> 8, prn_stream);
2467dd7cddfSDavid du Colombier fwrite (data, 1, count, prn_stream);
2477dd7cddfSDavid du Colombier }
2487dd7cddfSDavid du Colombier
2497dd7cddfSDavid du Colombier /* If xdpi == 360, the P6 / LQ850 cannot print adjacent pixels. Clear the
2507dd7cddfSDavid du Colombier second last pixel of every run of set pixels, so that the last pixel
2517dd7cddfSDavid du Colombier is always printed. */
2527dd7cddfSDavid du Colombier private void
dot24_improve_bitmap(byte * data,int count)2537dd7cddfSDavid du Colombier dot24_improve_bitmap (byte *data, int count)
2547dd7cddfSDavid du Colombier {
2557dd7cddfSDavid du Colombier int i;
2567dd7cddfSDavid du Colombier register byte *p = data + 6;
2577dd7cddfSDavid du Colombier
2587dd7cddfSDavid du Colombier for (i = 6; i < count; i += 3, p += 3)
2597dd7cddfSDavid du Colombier {
2607dd7cddfSDavid du Colombier p[-6] &= ~(~p[0] & p[-3]);
2617dd7cddfSDavid du Colombier p[-5] &= ~(~p[1] & p[-2]);
2627dd7cddfSDavid du Colombier p[-4] &= ~(~p[2] & p[-1]);
2637dd7cddfSDavid du Colombier }
2647dd7cddfSDavid du Colombier p[-6] &= ~p[-3];
2657dd7cddfSDavid du Colombier p[-5] &= ~p[-2];
2667dd7cddfSDavid du Colombier p[-4] &= ~p[-1];
2677dd7cddfSDavid du Colombier
2687dd7cddfSDavid du Colombier }
2697dd7cddfSDavid du Colombier
2707dd7cddfSDavid du Colombier
2717dd7cddfSDavid du Colombier private int
necp6_print_page(gx_device_printer * pdev,FILE * prn_stream)2727dd7cddfSDavid du Colombier necp6_print_page(gx_device_printer *pdev, FILE *prn_stream)
2737dd7cddfSDavid du Colombier {
2747dd7cddfSDavid du Colombier char necp6_init_string [] = "\033@\033P\033l\000\r\034\063\001\033Q";
2757dd7cddfSDavid du Colombier
2767dd7cddfSDavid du Colombier return dot24_print_page(pdev, prn_stream, necp6_init_string, sizeof(necp6_init_string));
2777dd7cddfSDavid du Colombier }
2787dd7cddfSDavid du Colombier
2797dd7cddfSDavid du Colombier
2807dd7cddfSDavid du Colombier private int
lq850_print_page(gx_device_printer * pdev,FILE * prn_stream)2817dd7cddfSDavid du Colombier lq850_print_page(gx_device_printer *pdev, FILE *prn_stream)
2827dd7cddfSDavid du Colombier {
2837dd7cddfSDavid du Colombier char lq850_init_string [] = "\033@\033P\033l\000\r\033\053\001\033Q";
2847dd7cddfSDavid du Colombier
2857dd7cddfSDavid du Colombier return dot24_print_page(pdev, prn_stream, lq850_init_string, sizeof(lq850_init_string));
2867dd7cddfSDavid du Colombier }
2877dd7cddfSDavid du Colombier
288