1 /* Copyright (C) 2000 Aladdin Enterprises. All rights reserved. 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License as published by 5 the Free Software Foundation; either version 2 of the License, or 6 (at your option) any later version. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License 14 along with this program; if not, write to the Free Software 15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 U.S.A. 16 17 This program may also be distributed as part of AFPL Ghostscript, 18 under the terms of the Aladdin Free Public License (the "License"). 19 20 AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author 21 or distributor accepts any responsibility for the consequences of using 22 it, or for whether it serves any particular purpose or works at all, 23 unless he or she says so in writing. Refer to the Aladdin Free Public 24 License (the "License") for full details. 25 26 Every copy of AFPL Ghostscript must include a copy of the License, 27 normally in a plain ASCII text file named PUBLIC. The License grants you 28 the right to copy, modify and redistribute AFPL Ghostscript, but only 29 under certain conditions described in the License. Among other things, the 30 License requires that the copyright notice and this notice be preserved on 31 all copies. 32 */ 33 34 /*$Id: gdevatx.c,v 1.6 2000/09/19 19:00:11 lpd Exp $ */ 35 /* Practical Automation ATX-23, -24, and -38 driver */ 36 #include "math_.h" 37 #include "gdevprn.h" 38 39 /* 40 * All of the ATX printers have an unprintable margin of 0.125" at the top 41 * and bottom of the page. They also have unprintable left/right margins: 42 * ATX-23 0.25" 43 * ATX-24 0.193" 44 * ATS-38 0.25" 45 * The code below assumes that coordinates refer only to the *printable* 46 * part of each page. This is wrong and must eventually be changed. 47 */ 48 49 /* Define the printer commands. */ 50 #define ATX_SET_PAGE_LENGTH "\033f" /* + 2-byte length */ 51 #define ATX_VERTICAL_TAB "\033L" /* + 2-byte count */ 52 #define ATX_UNCOMPRESSED_DATA "\033d" /* + 2-byte count */ 53 #define ATX_COMPRESSED_DATA "\033x" /* + 1-byte word count */ 54 #define ATX_END_PAGE "\033e" 55 56 /* The device descriptors */ 57 private dev_proc_print_page(atx23_print_page); 58 private dev_proc_print_page(atx24_print_page); 59 private dev_proc_print_page(atx38_print_page); 60 61 #define ATX_DEVICE(dname, w10, h10, dpi, lrm, btm, print_page)\ 62 prn_device_margins(prn_std_procs, dname, w10, h10, dpi, dpi, 0, 0,\ 63 lrm, btm, lrm, btm, 1, print_page) 64 65 const gx_device_printer gs_atx23_device = /* real width = 576 pixels */ 66 ATX_DEVICE("atx23", 28 /* 2.84" */, 35 /* (minimum) */, 67 203, 0.25, 0.125, atx23_print_page); 68 69 const gx_device_printer gs_atx24_device = /* real width = 832 pixels */ 70 ATX_DEVICE("atx24", 41 /* 4.1" */, 35 /* (minimum) */, 71 203, 0.193, 0.125, atx24_print_page); 72 73 const gx_device_printer gs_atx38_device = /* real width = 2400 pixels */ 74 ATX_DEVICE("atx38", 80 /* 8.0" */, 35 /* (minimum) */, 75 300, 0.25, 0.125, atx38_print_page); 76 77 /* Output a printer command with a 2-byte, little-endian numeric argument. */ 78 private void 79 fput_atx_command(FILE *f, const char *str, int value) 80 { 81 fputs(str, f); 82 fputc((byte)value, f); 83 fputc((byte)(value >> 8), f); 84 } 85 86 /* 87 * Attempt to compress a scan line of data. in_size and out_size are even. 88 * Return -1 if the compressed data would exceed out_size, otherwise the 89 * size of the compressed data (always even). 90 */ 91 #define MIN_IN_SIZE_TO_COMPRESS 50 92 #define MAX_COMPRESSED_SEGMENT_PAIRS 127 93 #define MAX_UNCOMPRESSED_SEGMENT_PAIRS 255 94 #define COMPRESSED_SEGMENT_COMMAND 0x80 /* + # of repeated pairs */ 95 #define UNCOMPRESSED_SEGMENT_COMMAND 0x7f /* followed by # of pairs */ 96 private int 97 atx_compress(const byte *in_buf, int in_size, byte *out_buf, int out_size) 98 { 99 const byte *const in_end = in_buf + in_size; 100 byte *const out_end = out_buf + out_size; 101 const byte *in = in_buf; 102 byte *out = out_buf; 103 byte *out_command; 104 int pair_count; 105 106 if (in_size < MIN_IN_SIZE_TO_COMPRESS) 107 return -1; /* not worth compressing */ 108 109 /* Start a new segment. */ 110 New_Segment: 111 if (in == in_end) /* end of input data */ 112 return out - out_buf; 113 if (out == out_end) /* output buffer full */ 114 return -1; 115 out_command = out; 116 out += 2; 117 if (in[1] == in[0]) { /* start compressed segment */ 118 /* out[-2] will be compressed segment command */ 119 out[-1] = in[0]; 120 pair_count = 1; 121 goto Scan_Compressed_Pair; 122 } else { /* start uncompressed segment */ 123 out[-2] = UNCOMPRESSED_SEGMENT_COMMAND; 124 /* out[-1] will be pair count */ 125 pair_count = 0; 126 goto Scan_Uncompressed_Pair; 127 } 128 129 /* Scan compressed data. */ 130 Scan_Compressed: 131 if (pair_count == MAX_COMPRESSED_SEGMENT_PAIRS || 132 in == in_end || in[0] != in[-1] || in[1] != in[0] 133 ) { /* end the segment */ 134 out_command[0] = COMPRESSED_SEGMENT_COMMAND + pair_count; 135 goto New_Segment; 136 } 137 ++pair_count; 138 Scan_Compressed_Pair: 139 in += 2; 140 goto Scan_Compressed; 141 142 /* Scan uncompressed data. */ 143 Scan_Uncompressed: 144 if (pair_count == MAX_UNCOMPRESSED_SEGMENT_PAIRS || 145 in == in_end || in[1] == in[0] 146 ) { /* end the segment */ 147 out_command[1] = pair_count; 148 goto New_Segment; 149 } 150 Scan_Uncompressed_Pair: 151 if (out == out_end) /* output buffer full */ 152 return -1; 153 out[0] = in[0], out[1] = in[1]; 154 in += 2; 155 out += 2; 156 ++pair_count; 157 goto Scan_Uncompressed; 158 159 } 160 161 /* Send the page to the printer. */ 162 private int 163 atx_print_page(gx_device_printer *pdev, FILE *f, int max_width_bytes) 164 { 165 /* 166 * The page length command uses 16 bits to represent the length in 167 * units of 0.01", so the maximum representable page length is 168 * 655.35", including the unprintable top and bottom margins. 169 * Compute the maximum height of the printable area in pixels. 170 */ 171 float top_bottom_skip = (pdev->HWMargins[1] + pdev->HWMargins[3]) / 72.0; 172 int max_height = (int)(pdev->HWResolution[1] * 655 - top_bottom_skip); 173 int height = min(pdev->height, max_height); 174 int page_length_100ths = 175 (int)ceil((height / pdev->HWResolution[1] + top_bottom_skip) * 100); 176 gs_memory_t *mem = pdev->memory; 177 int raster = gx_device_raster((gx_device *)pdev, true); 178 byte *buf; 179 /* 180 * ATX_COMPRESSED_DATA only takes a 1-byte (word) count. 181 * Thus no compressed scan line can take more than 510 bytes. 182 */ 183 int compressed_raster = min(raster / 2, 510); /* require 50% compression */ 184 byte *compressed; 185 int blank_lines, lnum; 186 int code = 0; 187 188 /* Enforce a minimum 3" page length. */ 189 if (page_length_100ths < 300) 190 page_length_100ths = 300; 191 buf = gs_alloc_bytes(mem, raster, "atx_print_page(buf)"); 192 compressed = gs_alloc_bytes(mem, compressed_raster, 193 "atx_print_page(compressed)"); 194 if (buf == 0 || compressed == 0) { 195 code = gs_note_error(gs_error_VMerror); 196 goto done; 197 } 198 fput_atx_command(f, ATX_SET_PAGE_LENGTH, page_length_100ths); 199 for (blank_lines = 0, lnum = 0; lnum < height; ++lnum) { 200 byte *row; 201 byte *end; 202 int count; 203 204 gdev_prn_get_bits(pdev, lnum, buf, &row); 205 /* Find the end of the non-blank data. */ 206 for (end = row + raster; end > row && end[-1] == 0 && end[-2] == 0; ) 207 end -= 2; 208 if (end == row) { /* blank line */ 209 ++blank_lines; 210 continue; 211 } 212 if (blank_lines) { /* skip vertically */ 213 fput_atx_command(f, ATX_VERTICAL_TAB, blank_lines + 1); 214 blank_lines = 0; 215 } 216 /* Truncate the line to the maximum printable width. */ 217 if (end - row > max_width_bytes) 218 end = row + max_width_bytes; 219 count = atx_compress(row, end - row, compressed, compressed_raster); 220 if (count >= 0) { /* compressed line */ 221 /* 222 * Note that since compressed_raster can't exceed 510, count 223 * can't exceed 510 either. 224 */ 225 fputs(ATX_COMPRESSED_DATA, f); 226 fputc(count / 2, f); 227 fwrite(compressed, 1, count, f); 228 } else { /* uncompressed line */ 229 int num_bytes = end - row; 230 231 fput_atx_command(f, ATX_UNCOMPRESSED_DATA, num_bytes); 232 fwrite(row, 1, num_bytes, f); 233 } 234 } 235 236 #if 0 /**************** MAY NOT BE NEEDED ****************/ 237 /* Enforce the minimum page length, and skip any final blank lines. */ 238 { 239 int paper_length = (int)(pdev->HWResolution[1] * 3 + 0.5); 240 int printed_length = height - blank_lines; 241 242 if (height > paper_length) 243 paper_length = height; 244 if (printed_length < paper_length) 245 fput_atx_command(f, ATX_VERTICAL_TAB, 246 paper_length - printed_length + 1); 247 } 248 #endif 249 250 /* End the page. */ 251 fputs(ATX_END_PAGE, f); 252 253 done: 254 gs_free_object(mem, compressed, "atx_print_page(compressed)"); 255 gs_free_object(mem, buf, "atx_print_page(buf)"); 256 return code; 257 } 258 259 /* Print pages with specified maximum pixel widths. */ 260 private int 261 atx23_print_page(gx_device_printer *pdev, FILE *f) 262 { 263 return atx_print_page(pdev, f, 576 / 8); 264 } 265 private int 266 atx24_print_page(gx_device_printer *pdev, FILE *f) 267 { 268 return atx_print_page(pdev, f, 832 / 8); 269 } 270 private int 271 atx38_print_page(gx_device_printer *pdev, FILE *f) 272 { 273 return atx_print_page(pdev, f, 2400 / 8); 274 } 275