diff options
Diffstat (limited to 'pstoraster/gsimage.c')
-rw-r--r-- | pstoraster/gsimage.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/pstoraster/gsimage.c b/pstoraster/gsimage.c new file mode 100644 index 000000000..7d1bc834b --- /dev/null +++ b/pstoraster/gsimage.c @@ -0,0 +1,312 @@ +/* Copyright (C) 1996 Aladdin Enterprises. All rights reserved. + + This file is part of GNU Ghostscript. + + GNU Ghostscript is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to + anyone for the consequences of using it or for whether it serves any + particular purpose or works at all, unless he says so in writing. Refer to + the GNU General Public License for full details. + + Everyone is granted permission to copy, modify and redistribute GNU + Ghostscript, but only under the conditions described in the GNU General + Public License. A copy of this license is supposed to have been given to + you along with GNU Ghostscript so you can know your rights and + responsibilities. It should be in a file named COPYING. Among other + things, the copyright notice and this notice must be preserved on all + copies. + + Aladdin Enterprises is not affiliated with the Free Software Foundation or + the GNU Project. GNU Ghostscript, as distributed by Aladdin Enterprises, + does not depend on any other GNU software. +*/ + +/* gsimage.c */ +/* Image setup procedures for Ghostscript library */ +#include "memory_.h" +#include "gx.h" +#include "gserrors.h" +#include "gsstruct.h" +#include "gscspace.h" +#include "gsmatrix.h" /* for gsiparam.h */ +#include "gsimage.h" +#include "gxarith.h" /* for igcd */ +#include "gxdevice.h" +#include "gzstate.h" + +/* Define the enumeration state for this interface layer. */ +/*typedef struct gs_image_enum_s gs_image_enum;*/ /* in gsimage.h */ +struct gs_image_enum_s { + /* The following are set at initialization time. */ + gs_memory_t *memory; + gx_device *dev; + void *info; /* driver bookkeeping structure */ + int num_components; + bool multi; + int num_planes; + int width, height; + int bpp; /* bits per pixel (per plane, if multi) */ + int bytes_mod; /* minimum # of bytes for an integral # of pixels */ + uint raster; /* bytes per row (per plane), no padding */ + /* The following are updated dynamically. */ + int plane_index; /* index of next plane of data */ + int x, y; + uint pos; /* byte position within the scan line */ + gs_const_string planes[4]; + byte saved[4][6]; /* partial bytes_mod bytes */ + int num_saved; /* # of saved bytes (per plane) */ + bool error; +}; +gs_private_st_composite(st_gs_image_enum, gs_image_enum, "gs_image_enum", + gs_image_enum_enum_ptrs, gs_image_enum_reloc_ptrs); +#define gs_image_enum_num_ptrs 2 + +/* GC procedures */ +#define eptr ((gs_image_enum *)vptr) +private ENUM_PTRS_BEGIN(gs_image_enum_enum_ptrs) { + /* Enumerate the data planes. */ + index -= gs_image_enum_num_ptrs; + if ( index < eptr->plane_index ) + { *pep = (void *)&eptr->planes[index]; + return ptr_string_type; + } + return 0; + } + ENUM_PTR(0, gs_image_enum, dev); + ENUM_PTR(1, gs_image_enum, info); +ENUM_PTRS_END +private RELOC_PTRS_BEGIN(gs_image_enum_reloc_ptrs) { + int i; + RELOC_PTR(gs_image_enum, dev); + RELOC_PTR(gs_image_enum, info); + for ( i = 0; i < eptr->plane_index; i++ ) + RELOC_CONST_STRING_PTR(gs_image_enum, planes[i]); +} RELOC_PTRS_END +#undef eptr + +/* Allocate an image enumerator. */ +gs_image_enum * +gs_image_enum_alloc(gs_memory_t *mem, client_name_t cname) +{ gs_image_enum *pie = + gs_alloc_struct(mem, gs_image_enum, &st_gs_image_enum, cname); + + if ( pie != 0 ) + { int i; + pie->memory = mem; + pie->info = 0; + /* Clean pointers for GC. */ + pie->dev = 0; + for ( i = 0; i < countof(pie->planes); ++i ) + pie->planes[i].data = 0, pie->planes[i].size = 0; + } + return pie; +} + +/* Start processing an image. */ +int +gs_image_init(gs_image_enum *pie, const gs_image_t *pim, bool multi, + gs_state *pgs) +{ gx_device *dev = gs_currentdevice_inline(pgs); + gs_image_t image; + ulong samples_per_row = pim->Width; + int code; + + if ( pim->Width == 0 || pim->Height == 0 ) + return 1; + image = *pim; + if ( image.ImageMask ) + { image.ColorSpace = NULL; + if ( pgs->in_cachedevice <= 1 ) + image.adjust = false; + pie->num_components = pie->num_planes = 1; + } + else + { if ( pgs->in_cachedevice ) + return_error(gs_error_undefined); + if ( image.ColorSpace == NULL ) + image.ColorSpace = gs_color_space_DeviceGray(); + pie->num_components = + gs_color_space_num_components(image.ColorSpace); + if ( multi ) + pie->num_planes = pie->num_components; + else + { pie->num_planes = 1; + samples_per_row *= pie->num_components; + } + } + if ( image.ImageMask | image.CombineWithColor ) + gx_set_dev_color(pgs); + code = (*dev_proc(dev, begin_image)) + (dev, (const gs_imager_state *)pgs, &image, + (multi ? gs_image_format_component_planar : gs_image_format_chunky), + (gs_image_shape_t)(gs_image_shape_rows | gs_image_shape_split_row), + pgs->dev_color, pgs->clip_path, pie->memory, &pie->info); + if ( code < 0 ) + return code; + pie->dev = dev; + pie->multi = multi; + pie->bpp = + image.BitsPerComponent * pie->num_components / pie->num_planes; + pie->width = image.Width; + pie->height = image.Height; + pie->bytes_mod = pie->bpp / igcd(pie->bpp, 8); + pie->raster = (samples_per_row * image.BitsPerComponent + 7) >> 3; + /* Initialize the dynamic part of the state. */ + pie->plane_index = 0; + pie->x = pie->y = 0; + pie->pos = 0; + pie->num_saved = 0; + pie->error = false; + return 0; +} + +/* + * Return the number of bytes of data per row + * (per plane, if MultipleDataSources is true). + */ +uint +gs_image_bytes_per_row(const gs_image_enum *pie) +{ return pie->raster; +} + +/* Process the next piece of an image. */ +private int near +copy_planes(gx_device *dev, gs_image_enum *pie, const byte **planes, int w, int h) +{ int code = (*dev_proc(dev, image_data))(dev, pie->info, planes, + pie->raster, pie->x, pie->y, + w, h); + if ( code < 0 ) + pie->error = true; + return code; +} +int +gs_image_next(gs_image_enum *pie, const byte *dbytes, uint dsize, + uint *pused) +{ gx_device *dev = pie->dev; + uint left; + const byte *planes[4]; + int i; + int code; + + /* + * Handle the following differences between gs_image_next and + * the device image_data procedure: + * + * - image_data requires an array of planes; gs_image_next + * expects planes in successive calls. + * + * - image_data requires that each call pass an integral + * number of pixels, and not cross scan line boundaries + * unless all scan lines have the same amount of data; + * gs_image_next allows arbitrary amounts of data. + */ + if ( pie->plane_index != 0 ) + if ( dsize != pie->planes[0].size ) + return_error(gs_error_rangecheck); + pie->planes[pie->plane_index].data = dbytes; + pie->planes[pie->plane_index].size = dsize; + if ( ++(pie->plane_index) != pie->num_planes ) + return 0; + /* We have a full set of planes. */ + for ( i = 0; i < pie->num_planes; ++i ) + planes[i] = pie->planes[i].data; + left = dsize; + /* + * We might have some left-over bytes from the previous set of planes. + * Check for this now. + */ + if ( pie->num_saved != 0 ) + { int copy = + min(pie->bytes_mod, pie->raster - pie->pos) - pie->num_saved; + if ( dsize >= copy ) + { int w = pie->bytes_mod * 8 / pie->bpp; + const byte *mod_planes[4]; + + for ( i = 0; i < pie->num_planes; ++i ) + { mod_planes[i] = pie->saved[i]; + memcpy(pie->saved[i] + pie->num_saved, planes[i], copy); + planes[i] += copy; + } + pie->num_saved = 0; + left -= copy; + if ( pie->x + w >= pie->width ) + { w = pie->width - pie->x; + code = copy_planes(dev, pie, mod_planes, w, 1); + if ( code < 0 ) + return code; + pie->x = 0; + pie->y++; + pie->pos = 0; + if ( pie->y == pie->height ) + { *pused = dsize - left; + return 1; + } + } + else + { code = copy_planes(dev, pie, mod_planes, w, 1); + if ( code < 0 ) + return code; + pie->x += w; + pie->pos += pie->bytes_mod; + } + } + } + /* + * Pass data by rows. + */ + { uint row_left; + while ( left >= (row_left = pie->raster - pie->pos) ) + { int w = pie->width - pie->x; + int h = (pie->x == 0 ? left / row_left : 1); + + if ( h > pie->height - pie->y ) + h = pie->height - pie->y; + code = copy_planes(dev, pie, planes, w, h); + if ( code < 0 ) + return code; + row_left *= h; + for ( i = 0; i < pie->num_planes; ++i ) + planes[i] += row_left; + left -= row_left; + pie->x = 0; + pie->y += h; + pie->pos = 0; + if ( pie->y == pie->height ) + { *pused = dsize - left; + return 1; + } + } + if ( (row_left = left - left % pie->bytes_mod) != 0 ) + { int w = row_left * 8 / pie->bpp; + + code = copy_planes(dev, pie, planes, w, 1); + if ( code < 0 ) + return code; + for ( i = 0; i < pie->num_planes; ++i ) + planes[i] += row_left; + left -= row_left; + pie->x += w; + pie->pos += row_left; + } + } + /* + * Save any left-over bytes. + */ + if ( left != 0 ) + { for ( i = 0; i < pie->num_planes; ++i ) + memcpy(pie->saved[i] + pie->num_saved, planes[i], left); + pie->num_saved += left; + } + pie->plane_index = 0; + *pused = dsize; + return 0; +} + +/* Clean up after processing an image. */ +void +gs_image_cleanup(gs_image_enum *pie) +{ gx_device *dev = pie->dev; + + (*dev_proc(dev, end_image))(dev, pie->info, !pie->error); + /* Don't free the local enumerator -- the client does that. */ +} |