1 /* Copyright (C) 1992, 1993 Aladdin Enterprises. All rights reserved.
2
3 This file is part of Ghostscript.
4
5 Ghostscript is distributed in the hope that it will be useful, but
6 WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
7 to anyone for the consequences of using it or for whether it serves any
8 particular purpose or works at all, unless he says so in writing. Refer
9 to the Ghostscript General Public License for full details.
10
11 Everyone is granted permission to copy, modify and redistribute
12 Ghostscript, but only under the conditions described in the Ghostscript
13 General Public License. A copy of this license is supposed to have been
14 given to you along with Ghostscript so you can know your rights and
15 responsibilities. It should be in a file named COPYING. Among other
16 things, the copyright notice and this notice must be preserved on all
17 copies. */
18
19 /* gdevmag.c */
20 /* .MAG file format devices for Ghostscript */
21 #include "gdevprn.h"
22 #include "gdevpccm.h"
23 #include <stdlib.h>
24
25 /* ------ The device descriptors ------ */
26
27 /*
28 * Default X and Y resolution.
29 */
30 #define HEIGHT_10THS 117
31 #define DPI (8000.0/HEIGHT_10THS)
32 #define WIDTH_10THS (6400.0 / DPI)
33
34 static dev_proc_print_page(mag_4bit_print_page);
35 static dev_proc_open_device(gdev_mag_4bit_open);
36 static dev_proc_print_page(mag_8bit_print_page);
37 static dev_proc_open_device(gdev_mag_8bit_open);
38
39 /* internal routines. */
40 static int mag_make_flag(gx_device_printer *,int ,int ,byte **, byte *,byte *);
41 static int mag_comp_flag(gx_device_printer *,int ,byte * ,byte *,byte *, int, byte *);
42 static int mag_write_palette(gx_device_printer * ,int );
43 static int mag_print_page(gx_device_printer * , int , FILE * );
44
45 /* 4-bit planar (PC-9801 style) color. */
46
47 static gx_device_procs mag16_procs =
48 prn_color_procs(gdev_mag_4bit_open, gdev_prn_output_page, gdev_prn_close,
49 pc_4bit_map_rgb_color, pc_4bit_map_color_rgb);
50 gx_device_printer far_data gs_mag16_device =
51 prn_device(mag16_procs, "mag16",
52 (int)WIDTH_10THS, (int)HEIGHT_10THS,
53 DPI, DPI,
54 0,0,0,0, /* margins */
55 4, mag_4bit_print_page);
56
57 /* 8-bit planar color. */
58
59 static gx_device_procs mag256_procs =
60 prn_color_procs(gdev_mag_8bit_open, gdev_prn_output_page, gdev_prn_close,
61 pc_8bit_map_rgb_color, pc_8bit_map_color_rgb);
62 gx_device_printer far_data gs_mag256_device =
63 prn_device(mag256_procs, "mag256",
64 (int)WIDTH_10THS, (int)HEIGHT_10THS,
65 DPI, DPI,
66 0,0,0,0, /* margins */
67 8, mag_8bit_print_page);
68
69 /* ------ Private definitions ------ */
70
71 static int
gdev_mag_4bit_open(gx_device * dev)72 gdev_mag_4bit_open(gx_device *dev)
73 {
74 dev->width = (dev->width + 7) / 8 * 8;
75 return gdev_prn_open(dev);
76 }
77
78 static int
gdev_mag_8bit_open(gx_device * dev)79 gdev_mag_8bit_open(gx_device *dev)
80 {
81 dev->width = (dev->width + 3) / 4 * 4;
82 return gdev_prn_open(dev);
83 }
84
85 static int
mag_4bit_print_page(gx_device_printer * pdev,FILE * file)86 mag_4bit_print_page(gx_device_printer *pdev,FILE *file)
87 { return mag_print_page(pdev,4,file);
88 }
89
90 static int
mag_8bit_print_page(gx_device_printer * pdev,FILE * file)91 mag_8bit_print_page(gx_device_printer *pdev,FILE *file)
92 { return mag_print_page(pdev,8,file);
93 }
94
95 /* Write out a page in MAG format. */
96 /* This routine is used for all formats. */
97 static int
mag_print_page(gx_device_printer * pdev,int depth,FILE * file)98 mag_print_page(gx_device_printer *pdev, int depth, FILE *file)
99 {
100 int code = 0; /* return code */
101 const char *magic = "MAKI02 gs ";
102 char *user = getenv("USER");
103 char check[256];
104 byte header[32] = "\000\000\000\000"
105 "\000\000\000\000"
106 "\000\000\000\000";
107 byte *flag;
108 byte *flag_prev;
109 byte *flag_a,*flag_b;
110 byte *row_buffer;
111 byte *row[17];
112 byte *pixel;
113 int raster = gdev_prn_raster(pdev);
114 int height = pdev->height;
115 int width = pdev->width;
116 int width_pixel = width / ((depth == 4) ? 4 : 2 );
117 int flag_size = width_pixel / 2;
118 int flag_a_bytes = (flag_size + 7)/8 + 1;
119 int flag_b_size = flag_size;
120 long flag_b_bytes;
121 long pixel_bytes;
122 int y;
123
124 row_buffer = (byte *)gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), raster,17,"mag_row");
125 flag = (byte *)gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), flag_size,2,"mag_flag");
126 flag_prev = flag + flag_size;
127 flag_a = (byte *)gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), flag_a_bytes,1,"mag_flag_a");
128 flag_b = (byte *)gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), flag_b_size,1,"mag_flag_b");
129 pixel = (byte *)gs_malloc(gs_lib_ctx_get_non_gc_memory_t(), width,1,"mag_pixel");
130 if (row_buffer == 0 || flag == 0 ||
131 flag_a == 0 || flag_b == 0 || pixel == 0) {
132 code = -1;
133 goto mag_done;
134 }
135 for (y=0;y<17;y++)
136 row[y] = row_buffer + raster*y;
137
138 if (user == 0) user = "Unknown";
139 strcpy(check,magic);
140 sprintf(check+strlen(check),"%-18s",user);
141 sprintf(check+31," Ghostscript with %s driver\x1a", pdev->dname);
142
143 /* check sizes of flag and pixel data. */
144 pixel_bytes = 0;
145 flag_b_bytes = 0;
146 {
147 byte *f0=flag_prev,*f1=flag;
148 memset(f0,0,flag_size);
149 for (y=0;y<height;y++) {
150 byte *f2;
151 pixel_bytes += mag_make_flag(pdev,y,depth,row,f1,pixel);
152 flag_b_bytes += mag_comp_flag(pdev,flag_size,f0,f1,flag_a,0,flag_b);
153 f2 = f0; f0 = f1; f1 = f2;
154 }
155 }
156
157 /* make header */
158 { long offset;
159 #define put_word(b,w) ((b)[0] = (w)&0xff,(b)[1] = ((w)>>8)&0xff)
160 #define put_dword(b,w) (put_word(b,w),put_word((b)+2,(w)>>16))
161 header[3] = depth == 4 ? 0 : 0x80;
162 put_word(header+8,width-1);
163 put_word(header+10,height-1);
164 offset = 32 + (1 << depth) * 3;
165 put_dword(header+12,offset);
166 offset += (flag_size * height + 7) / 8;
167 put_dword(header+16,offset);
168 put_dword(header+20,flag_b_bytes);
169 offset += flag_b_bytes;
170 put_dword(header+24,offset);
171 put_dword(header+28,pixel_bytes);
172 #undef put_word
173 #undef put_dword
174 }
175
176 /* write magic number, header, palettes. */
177 fputs(check,file);
178 fwrite(header,32,1,file);
179 mag_write_palette(pdev,depth);
180
181 /* write image */
182 { int count;
183 int next_bit;
184 byte *f0=flag_prev,*f1=flag;
185
186 /* flag A */
187 memset(f0,0,flag_size);
188 next_bit = 0;
189 for (y=0;y<height;y++) {
190 byte *f2;
191 mag_make_flag(pdev,y,depth,row,f1,pixel);
192 mag_comp_flag(pdev,flag_size,f0,f1,flag_a,next_bit,flag_b);
193 count = (next_bit + flag_size) / 8;
194 next_bit = (next_bit + flag_size) % 8;
195 fwrite(flag_a,count,1,file);
196 if (next_bit) flag_a[0] = flag_a[count];
197 f2 = f0; f0 = f1; f1 = f2;
198 }
199 if (next_bit) fputc(flag_a[0],file);
200
201 /* flag B */
202 memset(f0,0,flag_size);
203 for (y=0;y<height;y++) {
204 byte *f2;
205 mag_make_flag(pdev,y,depth,row,f1,pixel);
206 count = mag_comp_flag(pdev,flag_size,f0,f1,flag_a,0,flag_b);
207 fwrite(flag_b,count,1,file);
208 f2 = f0; f0 = f1; f1 = f2;
209 }
210
211 /* pixel */
212 for (y=0;y<height;y++) {
213 count = mag_make_flag(pdev,y,depth,row,f1,pixel);
214 fwrite(pixel,count,1,file);
215 }
216 }
217
218 mag_done:
219 if (row_buffer) gs_free(gs_lib_ctx_get_non_gc_memory_t(), (char *)row_buffer, raster, 17, "mag_row");
220 if (flag) gs_free(gs_lib_ctx_get_non_gc_memory_t(), (char *)flag,flag_size,2,"mag_flag");
221 if (flag_a) gs_free(gs_lib_ctx_get_non_gc_memory_t(), (char *)flag_a,flag_a_bytes,1,"mag_flag_a");
222 if (flag_b) gs_free(gs_lib_ctx_get_non_gc_memory_t(), (char *)flag_b,flag_b_size,1,"mag_flag_b");
223 if (pixel) gs_free(gs_lib_ctx_get_non_gc_memory_t(), (char *)pixel,width,1,"mag_pixel");
224
225 fflush(file);
226
227 return code;
228 }
229
230 /* make flag and pixel data */
231 static int
mag_make_flag(gx_device_printer * pdev,int line_no,int depth,byte ** row,byte * flag,byte * pixel)232 mag_make_flag(gx_device_printer *pdev,int line_no, int depth,
233 byte **row, byte *flag,byte *pixel)
234 {
235 int x;
236 int raster = gdev_prn_raster(pdev);
237 byte *ppixel = pixel;
238
239 { byte *prow = row[16];
240 for (x=16;x>0;x--)
241 row[x] = row[x-1];
242 row[0] = prow;
243 }
244 gdev_prn_copy_scan_lines(pdev,line_no,row[0],raster);
245
246 if (depth == 4) {
247 for (x=0;x<raster;x++) {
248 if (x&1) *(row[0]+x/2) |= *(row[0]+x);
249 else *(row[0]+x/2) = *(row[0]+x) << 4;
250 }
251 raster = (raster + 1) / 2;
252 }
253
254 #define check_pixel(a,b) \
255 (x >= (a) && line_no >= (b) && \
256 *(row[0]+x) == *(row[b] + (x - (a))) && \
257 *(row[0]+x+1) == *(row[b] + (x+1 - (a))))
258 #define set_flag(v) \
259 ((x & 2) ? (flag[x>>2] |= (v)) : (flag[x>>2] = (v)<<4))
260
261 for (x=0; x<raster ;x+=2) {
262 if (check_pixel(2,0)) set_flag(1); /* 1 */
263 else if (check_pixel(0,1)) set_flag(4); /* 4 */
264 else if (check_pixel(2,1)) set_flag(5); /* 5 */
265 else if (check_pixel(0,2)) set_flag(6); /* 6 */
266 else if (check_pixel(2,2)) set_flag(7); /* 7 */
267 else if (check_pixel(0,4)) set_flag(9); /* 9 */
268 else if (check_pixel(2,4)) set_flag(10); /* 10 */
269 else if (check_pixel(4,0)) set_flag(2); /* 2 */
270 else if (check_pixel(4,2)) set_flag(8); /* 8 */
271 else if (check_pixel(4,4)) set_flag(11); /* 11 */
272 else if (check_pixel(0,8)) set_flag(12); /* 12 */
273 else if (check_pixel(2,8)) set_flag(13); /* 13 */
274 else if (check_pixel(4,8)) set_flag(14); /* 14 */
275 else if (check_pixel(8,0)) set_flag(3); /* 3 */
276 else if (check_pixel(0,16)) set_flag(15); /* 15 */
277 else { /* 0 */
278 set_flag(0);
279 *ppixel++ = *(row[0] + x);
280 *ppixel++ = *(row[0] + x+1);
281 }
282 }
283 #undef check_pixel
284 #undef set_flag
285
286 return ppixel - pixel;
287 }
288
289 /* compress flags (make flag A and B) */
290 static int
mag_comp_flag(gx_device_printer * pdev,int size,byte * f0,byte * f1,byte * flag_a,int next_bit,byte * flag_b)291 mag_comp_flag(gx_device_printer *pdev, int size,byte *f0,byte *f1,
292 byte *flag_a,int next_bit,byte *flag_b)
293 {
294 byte mask = 0x80>>next_bit;
295 byte *pflag_b = flag_b;
296
297 for ( ;size>0 ; size--) {
298 byte b = *f0 ^ *f1;
299 if (mask == 0x80) {
300 *flag_a = 0;
301 }
302 if (b) {
303 *flag_a |= mask;
304 *pflag_b++ = b;
305 }
306 mask >>= 1;
307 f0++;
308 f1++;
309 if (mask == 0) {
310 mask = 0x80;
311 flag_a++;
312 }
313 }
314
315 return pflag_b - flag_b;
316 }
317
318 /* write palette */
319 static int
mag_write_palette(gx_device_printer * pdev,int depth)320 mag_write_palette(gx_device_printer *pdev,int depth)
321 {
322 uint i;
323 gx_color_value rgb[3];
324 int max_index = 1 << depth;
325
326 for ( i = 0; i < max_index; i++ ) {
327 byte grb[3];
328 (pdev->orig_procs.map_color_rgb)((gx_device *)pdev, (gx_color_index)i, rgb);
329 grb[0] = rgb[1] >> (gx_color_value_bits - 8);
330 grb[1] = rgb[0] >> (gx_color_value_bits - 8);
331 grb[2] = rgb[2] >> (gx_color_value_bits - 8);
332 fwrite(grb, 3,1,pdev->file);
333 }
334 return 0;
335 }
336