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