1 /* Copyright (C) 2000 Aladdin Enterprises. All rights reserved. 2 3 This software is provided AS-IS with no warranty, either express or 4 implied. 5 6 This software is distributed under license and may not be copied, 7 modified or distributed except as expressly authorized under the terms 8 of the license contained in the file LICENSE in this distribution. 9 10 For more information about licensing, please refer to 11 http://www.ghostscript.com/licensing/. For information on 12 commercial licensing, go to http://www.artifex.com/licensing/ or 13 contact Artifex Software, Inc., 101 Lucas Valley Road #110, 14 San Rafael, CA 94903, U.S.A., +1(415)492-9861. 15 */ 16 17 /* $Id: gdevatx.c,v 1.9 2004/01/29 18:19:41 ray Exp $ */ 18 /* Practical Automation ATX-23, -24, and -38 driver */ 19 #include "math_.h" 20 #include "gdevprn.h" 21 22 /* 23 * All of the ATX printers have an unprintable margin of 0.125" at the top 24 * and bottom of the page. They also have unprintable left/right margins: 25 * ATX-23 0.25" 26 * ATX-24 0.193" 27 * ATS-38 0.25" 28 * The code below assumes that coordinates refer only to the *printable* 29 * part of each page. This is wrong and must eventually be changed. 30 */ 31 32 /* Define the printer commands. */ 33 #define ATX_SET_PAGE_LENGTH "\033f" /* + 2-byte length */ 34 #define ATX_VERTICAL_TAB "\033L" /* + 2-byte count */ 35 #define ATX_UNCOMPRESSED_DATA "\033d" /* + 2-byte count */ 36 #define ATX_COMPRESSED_DATA "\033x" /* + 1-byte word count */ 37 #define ATX_END_PAGE "\033e" 38 39 /* The device descriptors */ 40 private dev_proc_print_page(atx23_print_page); 41 private dev_proc_print_page(atx24_print_page); 42 private dev_proc_print_page(atx38_print_page); 43 44 #define ATX_DEVICE(dname, w10, h10, dpi, lrm, btm, print_page)\ 45 prn_device_margins(prn_std_procs, dname, w10, h10, dpi, dpi, 0, 0,\ 46 lrm, btm, lrm, btm, 1, print_page) 47 48 const gx_device_printer gs_atx23_device = /* real width = 576 pixels */ 49 ATX_DEVICE("atx23", 28 /* 2.84" */, 35 /* (minimum) */, 50 203, 0.25, 0.125, atx23_print_page); 51 52 const gx_device_printer gs_atx24_device = /* real width = 832 pixels */ 53 ATX_DEVICE("atx24", 41 /* 4.1" */, 35 /* (minimum) */, 54 203, 0.193, 0.125, atx24_print_page); 55 56 const gx_device_printer gs_atx38_device = /* real width = 2400 pixels */ 57 ATX_DEVICE("atx38", 80 /* 8.0" */, 35 /* (minimum) */, 58 300, 0.25, 0.125, atx38_print_page); 59 60 /* Output a printer command with a 2-byte, little-endian numeric argument. */ 61 private void 62 fput_atx_command(FILE *f, const char *str, int value) 63 { 64 fputs(str, f); 65 fputc((byte)value, f); 66 fputc((byte)(value >> 8), f); 67 } 68 69 /* 70 * Attempt to compress a scan line of data. in_size and out_size are even. 71 * Return -1 if the compressed data would exceed out_size, otherwise the 72 * size of the compressed data (always even). 73 */ 74 #define MIN_IN_SIZE_TO_COMPRESS 50 75 #define MAX_COMPRESSED_SEGMENT_PAIRS 127 76 #define MAX_UNCOMPRESSED_SEGMENT_PAIRS 255 77 #define COMPRESSED_SEGMENT_COMMAND 0x80 /* + # of repeated pairs */ 78 #define UNCOMPRESSED_SEGMENT_COMMAND 0x7f /* followed by # of pairs */ 79 private int 80 atx_compress(const byte *in_buf, int in_size, byte *out_buf, int out_size) 81 { 82 const byte *const in_end = in_buf + in_size; 83 byte *const out_end = out_buf + out_size; 84 const byte *in = in_buf; 85 byte *out = out_buf; 86 byte *out_command; 87 int pair_count; 88 89 if (in_size < MIN_IN_SIZE_TO_COMPRESS) 90 return -1; /* not worth compressing */ 91 92 /* Start a new segment. */ 93 New_Segment: 94 if (in == in_end) /* end of input data */ 95 return out - out_buf; 96 if (out == out_end) /* output buffer full */ 97 return -1; 98 out_command = out; 99 out += 2; 100 if (in[1] == in[0]) { /* start compressed segment */ 101 /* out[-2] will be compressed segment command */ 102 out[-1] = in[0]; 103 pair_count = 1; 104 goto Scan_Compressed_Pair; 105 } else { /* start uncompressed segment */ 106 out[-2] = UNCOMPRESSED_SEGMENT_COMMAND; 107 /* out[-1] will be pair count */ 108 pair_count = 0; 109 goto Scan_Uncompressed_Pair; 110 } 111 112 /* Scan compressed data. */ 113 Scan_Compressed: 114 if (pair_count == MAX_COMPRESSED_SEGMENT_PAIRS || 115 in == in_end || in[0] != in[-1] || in[1] != in[0] 116 ) { /* end the segment */ 117 out_command[0] = COMPRESSED_SEGMENT_COMMAND + pair_count; 118 goto New_Segment; 119 } 120 ++pair_count; 121 Scan_Compressed_Pair: 122 in += 2; 123 goto Scan_Compressed; 124 125 /* Scan uncompressed data. */ 126 Scan_Uncompressed: 127 if (pair_count == MAX_UNCOMPRESSED_SEGMENT_PAIRS || 128 in == in_end || in[1] == in[0] 129 ) { /* end the segment */ 130 out_command[1] = pair_count; 131 goto New_Segment; 132 } 133 Scan_Uncompressed_Pair: 134 if (out == out_end) /* output buffer full */ 135 return -1; 136 out[0] = in[0], out[1] = in[1]; 137 in += 2; 138 out += 2; 139 ++pair_count; 140 goto Scan_Uncompressed; 141 142 } 143 144 /* Send the page to the printer. */ 145 private int 146 atx_print_page(gx_device_printer *pdev, FILE *f, int max_width_bytes) 147 { 148 /* 149 * The page length command uses 16 bits to represent the length in 150 * units of 0.01", so the maximum representable page length is 151 * 655.35", including the unprintable top and bottom margins. 152 * Compute the maximum height of the printable area in pixels. 153 */ 154 float top_bottom_skip = (pdev->HWMargins[1] + pdev->HWMargins[3]) / 72.0; 155 int max_height = (int)(pdev->HWResolution[1] * 655 - top_bottom_skip); 156 int height = min(pdev->height, max_height); 157 int page_length_100ths = 158 (int)ceil((height / pdev->HWResolution[1] + top_bottom_skip) * 100); 159 gs_memory_t *mem = pdev->memory; 160 int raster = gx_device_raster((gx_device *)pdev, true); 161 byte *buf; 162 /* 163 * ATX_COMPRESSED_DATA only takes a 1-byte (word) count. 164 * Thus no compressed scan line can take more than 510 bytes. 165 */ 166 int compressed_raster = min(raster / 2, 510); /* require 50% compression */ 167 byte *compressed; 168 int blank_lines, lnum; 169 int code = 0; 170 171 /* Enforce a minimum 3" page length. */ 172 if (page_length_100ths < 300) 173 page_length_100ths = 300; 174 buf = gs_alloc_bytes(mem, raster, "atx_print_page(buf)"); 175 compressed = gs_alloc_bytes(mem, compressed_raster, 176 "atx_print_page(compressed)"); 177 if (buf == 0 || compressed == 0) { 178 code = gs_note_error(gs_error_VMerror); 179 goto done; 180 } 181 fput_atx_command(f, ATX_SET_PAGE_LENGTH, page_length_100ths); 182 for (blank_lines = 0, lnum = 0; lnum < height; ++lnum) { 183 byte *row; 184 byte *end; 185 int count; 186 187 gdev_prn_get_bits(pdev, lnum, buf, &row); 188 /* Find the end of the non-blank data. */ 189 for (end = row + raster; end > row && end[-1] == 0 && end[-2] == 0; ) 190 end -= 2; 191 if (end == row) { /* blank line */ 192 ++blank_lines; 193 continue; 194 } 195 if (blank_lines) { /* skip vertically */ 196 fput_atx_command(f, ATX_VERTICAL_TAB, blank_lines + 1); 197 blank_lines = 0; 198 } 199 /* Truncate the line to the maximum printable width. */ 200 if (end - row > max_width_bytes) 201 end = row + max_width_bytes; 202 count = atx_compress(row, end - row, compressed, compressed_raster); 203 if (count >= 0) { /* compressed line */ 204 /* 205 * Note that since compressed_raster can't exceed 510, count 206 * can't exceed 510 either. 207 */ 208 fputs(ATX_COMPRESSED_DATA, f); 209 fputc(count / 2, f); 210 fwrite(compressed, 1, count, f); 211 } else { /* uncompressed line */ 212 int num_bytes = end - row; 213 214 fput_atx_command(f, ATX_UNCOMPRESSED_DATA, num_bytes); 215 fwrite(row, 1, num_bytes, f); 216 } 217 } 218 219 #if 0 /**************** MAY NOT BE NEEDED ****************/ 220 /* Enforce the minimum page length, and skip any final blank lines. */ 221 { 222 int paper_length = (int)(pdev->HWResolution[1] * 3 + 0.5); 223 int printed_length = height - blank_lines; 224 225 if (height > paper_length) 226 paper_length = height; 227 if (printed_length < paper_length) 228 fput_atx_command(f, ATX_VERTICAL_TAB, 229 paper_length - printed_length + 1); 230 } 231 #endif 232 233 /* End the page. */ 234 fputs(ATX_END_PAGE, f); 235 236 done: 237 gs_free_object(mem, compressed, "atx_print_page(compressed)"); 238 gs_free_object(mem, buf, "atx_print_page(buf)"); 239 return code; 240 } 241 242 /* Print pages with specified maximum pixel widths. */ 243 private int 244 atx23_print_page(gx_device_printer *pdev, FILE *f) 245 { 246 return atx_print_page(pdev, f, 576 / 8); 247 } 248 private int 249 atx24_print_page(gx_device_printer *pdev, FILE *f) 250 { 251 return atx_print_page(pdev, f, 832 / 8); 252 } 253 private int 254 atx38_print_page(gx_device_printer *pdev, FILE *f) 255 { 256 return atx_print_page(pdev, f, 2400 / 8); 257 } 258