xref: /plan9/sys/src/cmd/gs/src/gsdevmem.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1995, 1999 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: gsdevmem.c,v 1.6 2004/04/01 06:46:17 ray Exp $ */
18 /* Memory device creation for Ghostscript library */
19 #include "math_.h"		/* for fabs */
20 #include "memory_.h"
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsdevice.h"		/* for prototypes */
24 #include "gxarith.h"
25 #include "gxdevice.h"
26 #include "gxdevmem.h"
27 
28 /* Make a memory (image) device. */
29 /* If colors_size = -16, -24, or -32, this is a true-color device; */
30 /* otherwise, colors_size is the size of the palette in bytes */
31 /* (2^N for gray scale, 3*2^N for RGB color). */
32 /* We separate device allocation and initialization at customer request. */
33 int
gs_initialize_wordimagedevice(gx_device_memory * new_dev,const gs_matrix * pmat,uint width,uint height,const byte * colors,int colors_size,bool word_oriented,bool page_device,gs_memory_t * mem)34 gs_initialize_wordimagedevice(gx_device_memory * new_dev, const gs_matrix * pmat,
35 	      uint width, uint height, const byte * colors, int colors_size,
36 		    bool word_oriented, bool page_device, gs_memory_t * mem)
37 {
38     const gx_device_memory *proto_dev;
39     int palette_count = colors_size;
40     int num_components = 1;
41     int pcount;
42     int bits_per_pixel;
43     float x_pixels_per_unit, y_pixels_per_unit;
44     byte palette[256 * 3];
45     bool has_color;
46 
47     switch (colors_size) {
48 	case 3 * 2:
49 	    palette_count = 2;
50 	    num_components = 3;
51 	case 2:
52 	    bits_per_pixel = 1;
53 	    break;
54 	case 3 * 4:
55 	    palette_count = 4;
56 	    num_components = 3;
57 	case 4:
58 	    bits_per_pixel = 2;
59 	    break;
60 	case 3 * 16:
61 	    palette_count = 16;
62 	    num_components = 3;
63 	case 16:
64 	    bits_per_pixel = 4;
65 	    break;
66 	case 3 * 256:
67 	    palette_count = 256;
68 	    num_components = 3;
69 	case 256:
70 	    bits_per_pixel = 8;
71 	    break;
72 	case -16:
73 	    bits_per_pixel = 16;
74 	    palette_count = 0;
75 	    break;
76 	case -24:
77 	    bits_per_pixel = 24;
78 	    palette_count = 0;
79 	    break;
80 	case -32:
81 	    bits_per_pixel = 32;
82 	    palette_count = 0;
83 	    break;
84 	default:
85 	    return_error(gs_error_rangecheck);
86     }
87     proto_dev = (word_oriented ?
88 		 gdev_mem_word_device_for_bits(bits_per_pixel) :
89 		 gdev_mem_device_for_bits(bits_per_pixel));
90     if (proto_dev == 0)		/* no suitable device */
91 	return_error(gs_error_rangecheck);
92     pcount = palette_count * 3;
93     /* Check to make sure the palette contains white and black, */
94     /* and, if it has any colors, the six primaries. */
95     if (bits_per_pixel <= 8) {
96 	const byte *p;
97 	byte *q;
98 	int primary_mask = 0;
99 	int i;
100 
101 	has_color = false;
102 	for (i = 0, p = colors, q = palette;
103 	     i < palette_count; i++, q += 3
104 	    ) {
105 	    int mask = 1;
106 
107 	    switch (num_components) {
108 		case 1:	/* gray */
109 		    q[0] = q[1] = q[2] = *p++;
110 		    break;
111 		default /* case 3 */ :		/* RGB */
112 		    q[0] = p[0], q[1] = p[1], q[2] = p[2];
113 		    p += 3;
114 	    }
115 #define shift_mask(b,n)\
116   switch ( b ) { case 0xff: mask <<= n; case 0: break; default: mask = 0; }
117 	    shift_mask(q[0], 4);
118 	    shift_mask(q[1], 2);
119 	    shift_mask(q[2], 1);
120 #undef shift_mask
121 	    primary_mask |= mask;
122 	    if (q[0] != q[1] || q[0] != q[2])
123 		has_color = true;
124 	}
125 	switch (primary_mask) {
126 	    case 129:		/* just black and white */
127 		if (has_color)	/* color but no primaries */
128 		    return_error(gs_error_rangecheck);
129 	    case 255:		/* full color */
130 		break;
131 	    default:
132 		return_error(gs_error_rangecheck);
133 	}
134     } else
135 	has_color = true;
136     /*
137      * The initial transformation matrix must map 1 user unit to
138      * 1/72".  Let W and H be the width and height in pixels, and
139      * assume the initial matrix is of the form [A 0 0 B X Y].
140      * Then the size of the image in user units is (W/|A|,H/|B|),
141      * hence the size in inches is ((W/|A|)/72,(H/|B|)/72), so
142      * the number of pixels per inch is
143      * (W/((W/|A|)/72),H/((H/|B|)/72)), or (|A|*72,|B|*72).
144      * Similarly, if the initial matrix is [0 A B 0 X Y] for a 90
145      * or 270 degree rotation, the size of the image in user
146      * units is (W/|B|,H/|A|), so the pixels per inch are
147      * (|B|*72,|A|*72).  We forbid non-orthogonal transformation
148      * matrices.
149      */
150     if (is_fzero2(pmat->xy, pmat->yx))
151 	x_pixels_per_unit = pmat->xx, y_pixels_per_unit = pmat->yy;
152     else if (is_fzero2(pmat->xx, pmat->yy))
153 	x_pixels_per_unit = pmat->yx, y_pixels_per_unit = pmat->xy;
154     else
155 	return_error(gs_error_undefinedresult);
156     /* All checks done, initialize the device. */
157     if (bits_per_pixel == 1) {
158 	/* Determine the polarity from the palette. */
159 	gs_make_mem_device(new_dev, proto_dev, mem,
160 			   (page_device ? 1 : -1), 0);
161 	/* This is somewhat bogus, but does the right thing */
162 	/* in the only cases we care about. */
163 	gdev_mem_mono_set_inverted(new_dev,
164 			       (palette[0] | palette[1] | palette[2]) != 0);
165     } else {
166 	byte *dev_palette = gs_alloc_string(mem, pcount,
167 					    "gs_makeimagedevice(palette)");
168 
169 	if (dev_palette == 0)
170 	    return_error(gs_error_VMerror);
171 	gs_make_mem_device(new_dev, proto_dev, mem,
172 			   (page_device ? 1 : -1), 0);
173 	new_dev->palette.size = pcount;
174 	new_dev->palette.data = dev_palette;
175 	memcpy(dev_palette, palette, pcount);
176 	if (!has_color) {
177 	    new_dev->color_info.num_components = 1;
178 	    new_dev->color_info.max_color = 0;
179 	    new_dev->color_info.dither_colors = 0;
180 	    new_dev->color_info.gray_index = 0;
181 	}
182     }
183     /* Memory defice is always initialised as an internal device but */
184     /* this is an external device */
185     new_dev->retained = true;
186     rc_init(new_dev, new_dev->memory, 1);
187 
188     new_dev->initial_matrix = *pmat;
189     new_dev->MarginsHWResolution[0] = new_dev->HWResolution[0] =
190 	fabs(x_pixels_per_unit) * 72;
191     new_dev->MarginsHWResolution[1] = new_dev->HWResolution[1] =
192 	fabs(y_pixels_per_unit) * 72;
193     gx_device_set_width_height((gx_device *) new_dev, width, height);
194     /* Set the ImagingBBox so we get a correct clipping region. */
195     {
196 	gs_rect bbox;
197 
198 	bbox.p.x = 0;
199 	bbox.p.y = 0;
200 	bbox.q.x = width;
201 	bbox.q.y = height;
202 	gs_bbox_transform_inverse(&bbox, pmat, &bbox);
203 	new_dev->ImagingBBox[0] = bbox.p.x;
204 	new_dev->ImagingBBox[1] = bbox.p.y;
205 	new_dev->ImagingBBox[2] = bbox.q.x;
206 	new_dev->ImagingBBox[3] = bbox.q.y;
207 	new_dev->ImagingBBox_set = true;
208     }
209     /* The bitmap will be allocated when the device is opened. */
210     new_dev->is_open = false;
211     new_dev->bitmap_memory = mem;
212     return 0;
213 }
214 
215 int
gs_makewordimagedevice(gx_device ** pnew_dev,const gs_matrix * pmat,uint width,uint height,const byte * colors,int num_colors,bool word_oriented,bool page_device,gs_memory_t * mem)216 gs_makewordimagedevice(gx_device ** pnew_dev, const gs_matrix * pmat,
217 	       uint width, uint height, const byte * colors, int num_colors,
218 		    bool word_oriented, bool page_device, gs_memory_t * mem)
219 {
220     int code;
221     gx_device_memory *pnew =
222     gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
223 		    "gs_makeimagedevice(device)");
224 
225     if (pnew == 0)
226 	return_error(gs_error_VMerror);
227     code = gs_initialize_wordimagedevice(pnew, pmat, width, height,
228 					 colors, num_colors, word_oriented,
229 					 page_device, mem);
230     if (code < 0) {
231 	gs_free_object(mem, pnew, "gs_makeimagedevice(device)");
232 	return code;
233     }
234     *pnew_dev = (gx_device *) pnew;
235     return 0;
236 }
237