xref: /plan9/sys/src/cmd/gs/src/gdevtknk.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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