17dd7cddfSDavid du Colombier /* Copyright (C) 1995, 1999 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gsdevmem.c,v 1.6 2004/04/01 06:46:17 ray Exp $ */
187dd7cddfSDavid du Colombier /* Memory device creation for Ghostscript library */
197dd7cddfSDavid du Colombier #include "math_.h" /* for fabs */
207dd7cddfSDavid du Colombier #include "memory_.h"
217dd7cddfSDavid du Colombier #include "gx.h"
227dd7cddfSDavid du Colombier #include "gserrors.h"
237dd7cddfSDavid du Colombier #include "gsdevice.h" /* for prototypes */
247dd7cddfSDavid du Colombier #include "gxarith.h"
257dd7cddfSDavid du Colombier #include "gxdevice.h"
267dd7cddfSDavid du Colombier #include "gxdevmem.h"
277dd7cddfSDavid du Colombier
287dd7cddfSDavid du Colombier /* Make a memory (image) device. */
297dd7cddfSDavid du Colombier /* If colors_size = -16, -24, or -32, this is a true-color device; */
307dd7cddfSDavid du Colombier /* otherwise, colors_size is the size of the palette in bytes */
317dd7cddfSDavid du Colombier /* (2^N for gray scale, 3*2^N for RGB color). */
327dd7cddfSDavid du Colombier /* We separate device allocation and initialization at customer request. */
337dd7cddfSDavid du Colombier 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)347dd7cddfSDavid du Colombier gs_initialize_wordimagedevice(gx_device_memory * new_dev, const gs_matrix * pmat,
357dd7cddfSDavid du Colombier uint width, uint height, const byte * colors, int colors_size,
367dd7cddfSDavid du Colombier bool word_oriented, bool page_device, gs_memory_t * mem)
377dd7cddfSDavid du Colombier {
387dd7cddfSDavid du Colombier const gx_device_memory *proto_dev;
397dd7cddfSDavid du Colombier int palette_count = colors_size;
407dd7cddfSDavid du Colombier int num_components = 1;
417dd7cddfSDavid du Colombier int pcount;
427dd7cddfSDavid du Colombier int bits_per_pixel;
437dd7cddfSDavid du Colombier float x_pixels_per_unit, y_pixels_per_unit;
447dd7cddfSDavid du Colombier byte palette[256 * 3];
457dd7cddfSDavid du Colombier bool has_color;
467dd7cddfSDavid du Colombier
477dd7cddfSDavid du Colombier switch (colors_size) {
487dd7cddfSDavid du Colombier case 3 * 2:
497dd7cddfSDavid du Colombier palette_count = 2;
507dd7cddfSDavid du Colombier num_components = 3;
517dd7cddfSDavid du Colombier case 2:
527dd7cddfSDavid du Colombier bits_per_pixel = 1;
537dd7cddfSDavid du Colombier break;
547dd7cddfSDavid du Colombier case 3 * 4:
557dd7cddfSDavid du Colombier palette_count = 4;
567dd7cddfSDavid du Colombier num_components = 3;
577dd7cddfSDavid du Colombier case 4:
587dd7cddfSDavid du Colombier bits_per_pixel = 2;
597dd7cddfSDavid du Colombier break;
607dd7cddfSDavid du Colombier case 3 * 16:
617dd7cddfSDavid du Colombier palette_count = 16;
627dd7cddfSDavid du Colombier num_components = 3;
637dd7cddfSDavid du Colombier case 16:
647dd7cddfSDavid du Colombier bits_per_pixel = 4;
657dd7cddfSDavid du Colombier break;
667dd7cddfSDavid du Colombier case 3 * 256:
677dd7cddfSDavid du Colombier palette_count = 256;
687dd7cddfSDavid du Colombier num_components = 3;
697dd7cddfSDavid du Colombier case 256:
707dd7cddfSDavid du Colombier bits_per_pixel = 8;
717dd7cddfSDavid du Colombier break;
727dd7cddfSDavid du Colombier case -16:
737dd7cddfSDavid du Colombier bits_per_pixel = 16;
747dd7cddfSDavid du Colombier palette_count = 0;
757dd7cddfSDavid du Colombier break;
767dd7cddfSDavid du Colombier case -24:
777dd7cddfSDavid du Colombier bits_per_pixel = 24;
787dd7cddfSDavid du Colombier palette_count = 0;
797dd7cddfSDavid du Colombier break;
807dd7cddfSDavid du Colombier case -32:
817dd7cddfSDavid du Colombier bits_per_pixel = 32;
827dd7cddfSDavid du Colombier palette_count = 0;
837dd7cddfSDavid du Colombier break;
847dd7cddfSDavid du Colombier default:
857dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
867dd7cddfSDavid du Colombier }
877dd7cddfSDavid du Colombier proto_dev = (word_oriented ?
887dd7cddfSDavid du Colombier gdev_mem_word_device_for_bits(bits_per_pixel) :
897dd7cddfSDavid du Colombier gdev_mem_device_for_bits(bits_per_pixel));
907dd7cddfSDavid du Colombier if (proto_dev == 0) /* no suitable device */
917dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
927dd7cddfSDavid du Colombier pcount = palette_count * 3;
937dd7cddfSDavid du Colombier /* Check to make sure the palette contains white and black, */
947dd7cddfSDavid du Colombier /* and, if it has any colors, the six primaries. */
957dd7cddfSDavid du Colombier if (bits_per_pixel <= 8) {
967dd7cddfSDavid du Colombier const byte *p;
977dd7cddfSDavid du Colombier byte *q;
987dd7cddfSDavid du Colombier int primary_mask = 0;
997dd7cddfSDavid du Colombier int i;
1007dd7cddfSDavid du Colombier
1017dd7cddfSDavid du Colombier has_color = false;
1027dd7cddfSDavid du Colombier for (i = 0, p = colors, q = palette;
1037dd7cddfSDavid du Colombier i < palette_count; i++, q += 3
1047dd7cddfSDavid du Colombier ) {
1057dd7cddfSDavid du Colombier int mask = 1;
1067dd7cddfSDavid du Colombier
1077dd7cddfSDavid du Colombier switch (num_components) {
1087dd7cddfSDavid du Colombier case 1: /* gray */
1097dd7cddfSDavid du Colombier q[0] = q[1] = q[2] = *p++;
1107dd7cddfSDavid du Colombier break;
1117dd7cddfSDavid du Colombier default /* case 3 */ : /* RGB */
1127dd7cddfSDavid du Colombier q[0] = p[0], q[1] = p[1], q[2] = p[2];
1137dd7cddfSDavid du Colombier p += 3;
1147dd7cddfSDavid du Colombier }
1157dd7cddfSDavid du Colombier #define shift_mask(b,n)\
1167dd7cddfSDavid du Colombier switch ( b ) { case 0xff: mask <<= n; case 0: break; default: mask = 0; }
1177dd7cddfSDavid du Colombier shift_mask(q[0], 4);
1187dd7cddfSDavid du Colombier shift_mask(q[1], 2);
1197dd7cddfSDavid du Colombier shift_mask(q[2], 1);
1207dd7cddfSDavid du Colombier #undef shift_mask
1217dd7cddfSDavid du Colombier primary_mask |= mask;
1227dd7cddfSDavid du Colombier if (q[0] != q[1] || q[0] != q[2])
1237dd7cddfSDavid du Colombier has_color = true;
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier switch (primary_mask) {
1267dd7cddfSDavid du Colombier case 129: /* just black and white */
1277dd7cddfSDavid du Colombier if (has_color) /* color but no primaries */
1287dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
1297dd7cddfSDavid du Colombier case 255: /* full color */
1307dd7cddfSDavid du Colombier break;
1317dd7cddfSDavid du Colombier default:
1327dd7cddfSDavid du Colombier return_error(gs_error_rangecheck);
1337dd7cddfSDavid du Colombier }
1347dd7cddfSDavid du Colombier } else
1357dd7cddfSDavid du Colombier has_color = true;
1367dd7cddfSDavid du Colombier /*
1377dd7cddfSDavid du Colombier * The initial transformation matrix must map 1 user unit to
1387dd7cddfSDavid du Colombier * 1/72". Let W and H be the width and height in pixels, and
1397dd7cddfSDavid du Colombier * assume the initial matrix is of the form [A 0 0 B X Y].
1407dd7cddfSDavid du Colombier * Then the size of the image in user units is (W/|A|,H/|B|),
1417dd7cddfSDavid du Colombier * hence the size in inches is ((W/|A|)/72,(H/|B|)/72), so
1427dd7cddfSDavid du Colombier * the number of pixels per inch is
1437dd7cddfSDavid du Colombier * (W/((W/|A|)/72),H/((H/|B|)/72)), or (|A|*72,|B|*72).
1447dd7cddfSDavid du Colombier * Similarly, if the initial matrix is [0 A B 0 X Y] for a 90
1457dd7cddfSDavid du Colombier * or 270 degree rotation, the size of the image in user
1467dd7cddfSDavid du Colombier * units is (W/|B|,H/|A|), so the pixels per inch are
1477dd7cddfSDavid du Colombier * (|B|*72,|A|*72). We forbid non-orthogonal transformation
1487dd7cddfSDavid du Colombier * matrices.
1497dd7cddfSDavid du Colombier */
1507dd7cddfSDavid du Colombier if (is_fzero2(pmat->xy, pmat->yx))
1517dd7cddfSDavid du Colombier x_pixels_per_unit = pmat->xx, y_pixels_per_unit = pmat->yy;
1527dd7cddfSDavid du Colombier else if (is_fzero2(pmat->xx, pmat->yy))
1537dd7cddfSDavid du Colombier x_pixels_per_unit = pmat->yx, y_pixels_per_unit = pmat->xy;
1547dd7cddfSDavid du Colombier else
1557dd7cddfSDavid du Colombier return_error(gs_error_undefinedresult);
1567dd7cddfSDavid du Colombier /* All checks done, initialize the device. */
1577dd7cddfSDavid du Colombier if (bits_per_pixel == 1) {
1587dd7cddfSDavid du Colombier /* Determine the polarity from the palette. */
1597dd7cddfSDavid du Colombier gs_make_mem_device(new_dev, proto_dev, mem,
1607dd7cddfSDavid du Colombier (page_device ? 1 : -1), 0);
1617dd7cddfSDavid du Colombier /* This is somewhat bogus, but does the right thing */
1627dd7cddfSDavid du Colombier /* in the only cases we care about. */
1637dd7cddfSDavid du Colombier gdev_mem_mono_set_inverted(new_dev,
1647dd7cddfSDavid du Colombier (palette[0] | palette[1] | palette[2]) != 0);
1657dd7cddfSDavid du Colombier } else {
1667dd7cddfSDavid du Colombier byte *dev_palette = gs_alloc_string(mem, pcount,
1677dd7cddfSDavid du Colombier "gs_makeimagedevice(palette)");
1687dd7cddfSDavid du Colombier
1697dd7cddfSDavid du Colombier if (dev_palette == 0)
1707dd7cddfSDavid du Colombier return_error(gs_error_VMerror);
1717dd7cddfSDavid du Colombier gs_make_mem_device(new_dev, proto_dev, mem,
1727dd7cddfSDavid du Colombier (page_device ? 1 : -1), 0);
1737dd7cddfSDavid du Colombier new_dev->palette.size = pcount;
1747dd7cddfSDavid du Colombier new_dev->palette.data = dev_palette;
1757dd7cddfSDavid du Colombier memcpy(dev_palette, palette, pcount);
1767dd7cddfSDavid du Colombier if (!has_color) {
1777dd7cddfSDavid du Colombier new_dev->color_info.num_components = 1;
1787dd7cddfSDavid du Colombier new_dev->color_info.max_color = 0;
1797dd7cddfSDavid du Colombier new_dev->color_info.dither_colors = 0;
180*593dc095SDavid du Colombier new_dev->color_info.gray_index = 0;
1817dd7cddfSDavid du Colombier }
1827dd7cddfSDavid du Colombier }
183*593dc095SDavid du Colombier /* Memory defice is always initialised as an internal device but */
184*593dc095SDavid du Colombier /* this is an external device */
185*593dc095SDavid du Colombier new_dev->retained = true;
186*593dc095SDavid du Colombier rc_init(new_dev, new_dev->memory, 1);
187*593dc095SDavid du Colombier
1887dd7cddfSDavid du Colombier new_dev->initial_matrix = *pmat;
1897dd7cddfSDavid du Colombier new_dev->MarginsHWResolution[0] = new_dev->HWResolution[0] =
1907dd7cddfSDavid du Colombier fabs(x_pixels_per_unit) * 72;
1917dd7cddfSDavid du Colombier new_dev->MarginsHWResolution[1] = new_dev->HWResolution[1] =
1927dd7cddfSDavid du Colombier fabs(y_pixels_per_unit) * 72;
1937dd7cddfSDavid du Colombier gx_device_set_width_height((gx_device *) new_dev, width, height);
1947dd7cddfSDavid du Colombier /* Set the ImagingBBox so we get a correct clipping region. */
1957dd7cddfSDavid du Colombier {
1967dd7cddfSDavid du Colombier gs_rect bbox;
1977dd7cddfSDavid du Colombier
1987dd7cddfSDavid du Colombier bbox.p.x = 0;
1997dd7cddfSDavid du Colombier bbox.p.y = 0;
2007dd7cddfSDavid du Colombier bbox.q.x = width;
2017dd7cddfSDavid du Colombier bbox.q.y = height;
2027dd7cddfSDavid du Colombier gs_bbox_transform_inverse(&bbox, pmat, &bbox);
2037dd7cddfSDavid du Colombier new_dev->ImagingBBox[0] = bbox.p.x;
2047dd7cddfSDavid du Colombier new_dev->ImagingBBox[1] = bbox.p.y;
2057dd7cddfSDavid du Colombier new_dev->ImagingBBox[2] = bbox.q.x;
2067dd7cddfSDavid du Colombier new_dev->ImagingBBox[3] = bbox.q.y;
2077dd7cddfSDavid du Colombier new_dev->ImagingBBox_set = true;
2087dd7cddfSDavid du Colombier }
2097dd7cddfSDavid du Colombier /* The bitmap will be allocated when the device is opened. */
2107dd7cddfSDavid du Colombier new_dev->is_open = false;
2117dd7cddfSDavid du Colombier new_dev->bitmap_memory = mem;
2127dd7cddfSDavid du Colombier return 0;
2137dd7cddfSDavid du Colombier }
2147dd7cddfSDavid du Colombier
2157dd7cddfSDavid du Colombier 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)2167dd7cddfSDavid du Colombier gs_makewordimagedevice(gx_device ** pnew_dev, const gs_matrix * pmat,
2177dd7cddfSDavid du Colombier uint width, uint height, const byte * colors, int num_colors,
2187dd7cddfSDavid du Colombier bool word_oriented, bool page_device, gs_memory_t * mem)
2197dd7cddfSDavid du Colombier {
2207dd7cddfSDavid du Colombier int code;
2217dd7cddfSDavid du Colombier gx_device_memory *pnew =
2227dd7cddfSDavid du Colombier gs_alloc_struct(mem, gx_device_memory, &st_device_memory,
2237dd7cddfSDavid du Colombier "gs_makeimagedevice(device)");
2247dd7cddfSDavid du Colombier
2257dd7cddfSDavid du Colombier if (pnew == 0)
2267dd7cddfSDavid du Colombier return_error(gs_error_VMerror);
2277dd7cddfSDavid du Colombier code = gs_initialize_wordimagedevice(pnew, pmat, width, height,
2287dd7cddfSDavid du Colombier colors, num_colors, word_oriented,
2297dd7cddfSDavid du Colombier page_device, mem);
2307dd7cddfSDavid du Colombier if (code < 0) {
2317dd7cddfSDavid du Colombier gs_free_object(mem, pnew, "gs_makeimagedevice(device)");
2327dd7cddfSDavid du Colombier return code;
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier *pnew_dev = (gx_device *) pnew;
2357dd7cddfSDavid du Colombier return 0;
2367dd7cddfSDavid du Colombier }
237