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 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 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