1 /* Copyright (C) 1992, 1996 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: gdevtknk.c,v 1.6 2002/08/22 07:12:28 henrys Exp $*/
18 /*
19 This driver is written for Tektronix ink-jet 4696 and 4695 plotters.
20
21 It may easily be adopted to the 4393 and 4394 models as well, simply by
22 adding new device descriptors with other geometrical characteristics.
23 */
24 #include "gdevprn.h"
25 #include "malloc_.h"
26
27 /* Thanks to Karsten Spang (spang@nbivax.nbi.dk) for contributing */
28 /* this code to Aladdin Enterprises. */
29
30
31 /* The device descriptor */
32 /* We need our own color mapping procedures. */
33 private dev_proc_map_rgb_color(tekink_map_rgb_color);
34 private dev_proc_map_color_rgb(tekink_map_color_rgb);
35 private dev_proc_print_page(tekink_print_page);
36 private gx_device_procs tekink_procs =
37 prn_color_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
38 tekink_map_rgb_color, tekink_map_color_rgb);
39
40
41 /*
42 Device descriptor for the Tek 4696.
43 The 4696 plotter uses roll media, thus the y size is arbitrary. The
44 value below is chosen to make the image area A*-format like, i.e. the
45 aspect ratio is close to sqrt(2).
46 */
47 const gx_device_printer far_data gs_tek4696_device =
48 prn_device(tekink_procs,"tek4696",
49 85,120, /* Page size in 10th of inches */
50 120,120, /* Resolution in DPI */
51 0.0,0.0,0.0,0.0, /* Margins */
52 4, /* Bits per pixel */
53 tekink_print_page);
54
55 /* Color mapping.
56 The tek inkjets use subtractive colors B=0 M=1 Y=2 C=3. These are
57 represented as 4 bits B=1 M=2 Y=4 C=8 in a byte. This gives:
58 White = 0
59 Black = 1
60 Magenta = 2
61 Yellow = 4
62 Red = 6
63 Cyan = 8
64 Blue = 10
65 Green = 12
66 The remaining values are unused. (They give ugly results if sent to the
67 plotter.) Of course this could have been compressed into 3 bits, but
68 as the palette color memory device uses 8 bits anyway, this is easier,
69 and perhaps faster.
70 */
71
72 static gx_color_index rgb_to_index[8]={1,6,12,4,10,2,8,0};
73 static ushort index_to_rgb[16][3]={
74 {65535,65535,65535}, /* White */
75 {0,0,0}, /* Black */
76 {65535,0,65535}, /* Magenta */
77 {2,2,2}, /* Unused */
78 {65535,65535,0}, /* Yellow */
79 {2,2,2}, /* Unused */
80 {65535,0,0}, /* Red */
81 {2,2,2}, /* Unused */
82 {0,65535,65535}, /* Cyan */
83 {2,2,2}, /* Unused */
84 {0,0,65535}, /* Blue */
85 {2,2,2}, /* Unused */
86 {0,65535,0}, /* Green */
87 {2,2,2}, /* Unused */
88 {2,2,2}, /* Unused */
89 {2,2,2} /* Unused */
90 };
91
92 /* Map an RGB color to a printer color. */
93 private gx_color_index
tekink_map_rgb_color(gx_device * dev,const gx_color_value cv[])94 tekink_map_rgb_color(gx_device *dev, const gx_color_value cv[])
95 {
96 gx_color_value r = cv[0];
97 gx_color_value g = cv[1];
98 gx_color_value b = cv[2];
99
100 return(rgb_to_index[(((b>32767) << 2) + ((g>32767) << 1) +
101 (r>32767)) & 7]);
102 }
103
104 /* Map the printer color back to RGB. */
105 private int
tekink_map_color_rgb(gx_device * dev,gx_color_index color,ushort prgb[3])106 tekink_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
107 {
108 register ushort c = (ushort)color;
109 register int i;
110 if (c>15) return -1;
111 if (index_to_rgb[c][0]==2) return -1;
112 for (i=0;i<3;i++){
113 prgb[i]=index_to_rgb[c][i];
114 }
115 return 0;
116 }
117
118 /* Send the page to the printer. */
119 private int
tekink_print_page(gx_device_printer * pdev,FILE * prn_stream)120 tekink_print_page(gx_device_printer *pdev,FILE *prn_stream)
121 {
122 int line_size,color_line_size,scan_line,num_bytes,scan_lines,color_plane;
123 int roll_paper,out_line,micro_line,pending_micro_lines,line_blank,
124 blank_lines;
125 byte *outdata,*indata1,*bdata1,*mdata1,*ydata1,*cdata1;
126 register byte *indata,*bdatap,*mdatap,*ydatap,*cdatap;
127 register byte bdata,mdata,ydata,cdata;
128 register byte mask,inbyte;
129 register byte *indataend,*outdataend;
130
131 /* Allocate a temporary buffer for color separation.
132 The buffer is partitioned into an input buffer and four
133 output buffers for the color planes. The output buffers
134 are allocated with an extra sentinel byte. */
135
136 line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
137 color_line_size=(pdev->width+7)/8;
138 indata1=(byte *)malloc(line_size+4*(color_line_size+1));
139 if (indata1==NULL) return -1;
140 /* pointers to the partions */
141 indataend=indata1+line_size;
142 bdata1=indataend;
143 mdata1=bdata1+(color_line_size+1);
144 ydata1=mdata1+(color_line_size+1);
145 cdata1=ydata1+(color_line_size+1);
146
147 /* Does this device use roll paper? */
148 roll_paper=!strcmp(pdev->dname,"tek4696");
149
150 out_line=0;
151 blank_lines=0;
152 scan_lines=pdev->height;
153 for (scan_line=0;scan_line<scan_lines;scan_line++){
154 /* get data */
155 gdev_prn_copy_scan_lines(pdev,scan_line,indata1,line_size);
156 /* Separate data into color planes */
157 bdatap = bdata1+1;
158 mdatap = mdata1+1;
159 ydatap = ydata1+1;
160 cdatap = cdata1+1;
161 bdata=0;
162 mdata=0;
163 cdata=0;
164 ydata=0;
165 mask=0x80;
166 memset(indataend,0,4*(color_line_size+1));
167 for (indata=indata1;indata<indataend;indata++){
168 inbyte = *indata;
169 if (inbyte&0x01) bdata|=mask;
170 if (inbyte&0x02) mdata|=mask;
171 if (inbyte&0x04) ydata|=mask;
172 if (inbyte&0x08) cdata|=mask;
173 mask>>=1;
174 if (!mask){
175 *(bdatap++) = bdata;
176 *(mdatap++) = mdata;
177 *(cdatap++) = cdata;
178 *(ydatap++) = ydata;
179 bdata=0;
180 mdata=0;
181 cdata=0;
182 ydata=0;
183 mask=0x80;
184 }
185 }
186 if (mask!=0x80){
187 *bdatap = bdata;
188 *mdatap = mdata;
189 *cdatap = cdata;
190 *ydatap = ydata;
191 }
192 line_blank=1;
193 /* Output each of the four color planes */
194 for (color_plane=0;color_plane<4;color_plane++){
195 outdata=indataend+(color_plane*(color_line_size+1));
196 outdataend=outdata+color_line_size;
197
198 /* Remove trailing spaces and output the color line if it is
199 not blank */
200 *outdata=0xff;
201 while (!(*outdataend)) outdataend--;
202 if (num_bytes=(outdataend-outdata)){
203 line_blank=0;
204 /* On encountering the first non-blank data, output pending
205 blank lines */
206 if (blank_lines){
207 pending_micro_lines=((out_line+blank_lines+1)/4)-
208 (out_line/4);
209 for (micro_line=0;micro_line<pending_micro_lines;
210 micro_line++){
211 fputs("\033A",prn_stream);
212 }
213 out_line+=blank_lines;
214 blank_lines=0;
215 }
216 fprintf(prn_stream,"\033I%c%03d",'0'+(out_line%4)+
217 4*color_plane,num_bytes);
218 fwrite(outdata+1,1,num_bytes,prn_stream);
219 }
220 } /* loop over color planes */
221
222 /* If this line is blank, and if it is a roll paper model,
223 count the line. Otherwise output the line */
224 if (line_blank&&roll_paper){
225 /* Only increment the blank line count, if non blank lines
226 have been encountered previously, i.e. skip leading blank
227 lines. */
228 if (out_line) blank_lines++;
229 }
230 else{
231 if (out_line%4==3){
232 /* Write micro line feed code */
233 fputs("\033A",prn_stream);
234 }
235 out_line++;
236 }
237 } /* loop over scan lines */
238
239 /* if the number of scan lines written is not a multiple of four,
240 write the final micro line feed code */
241 if (out_line%4){
242 fputs("\033A",prn_stream);
243 }
244 /* Separate this plot from the next */
245 if (roll_paper){
246 fputs("\n\n\n\n\n",prn_stream);
247 }
248 else{
249 fputs("\f",prn_stream);
250 }
251
252 /* Deallocate temp buffer */
253 free(indata1);
254 return 0;
255 }
256