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