DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T g

⟦4e910131c⟧ TextFile

    Length: 14803 (0x39d3)
    Types: TextFile
    Names: »gsimage.c«

Derivation

└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
    └─⟦ff23ba0e6⟧ »./ghostscript-1.3.tar.Z« 
        └─⟦a24a58cd3⟧ 
            └─⟦this⟧ »gsimage.c« 

TextFile

/* Copyright (C) 1989 Aladdin Enterprises.  All rights reserved.
   Distributed by Free Software Foundation, Inc.

This file is part of Ghostscript.

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 Ghostscript General Public License for full details.

Everyone is granted permission to copy, modify and redistribute
Ghostscript, but only under the conditions described in the Ghostscript
General Public License.  A copy of this license is supposed to have been
given to you along with 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.  */

/* gsimage.c */
/* Image procedures for GhostScript library */
#include "gx.h"
#include "malloc_.h"
#include "memory_.h"
#include "gserrors.h"
#include "gxfixed.h"
#include "gxmatrix.h"
#include "gspaint.h"
#include "gzstate.h"
#include "gzdevice.h"			/* requires gsstate.h */
#include "gzcolor.h"			/* requires gxdevice.h */
#include "gzpath.h"
#include "gximage.h"

/* Exported size of enumerator */
int gs_image_enum_sizeof = sizeof(gs_image_enum);

/* Forward declarations */
private int image_init(P8(gs_image_enum *, int, int, int,
  gs_matrix *, gs_state *, gx_color_index, gx_color_index));
private int image_process_direct(iprocess_proc_args);
private int image_process_0(iprocess_proc_args);
private int image_process_1(iprocess_proc_args);
private int image_process_2(iprocess_proc_args);
private int image_process_3(iprocess_proc_args);
private int image_process_mono(iprocess_proc_args);

/* Start processing an image */
int
gs_image_init(gs_image_enum *penum, gs_state *pgs,
  int width, int height, int bps, gs_matrix *pmat)
{	int log2_bps = bps >> 1;	/* works for 1, 2, 4 */
	if ( pgs->in_show ) return_error(gs_error_undefined);
	switch ( bps )
	   {
	default: return_error(gs_error_rangecheck);
	case 8: log2_bps = 3;		/* falls through */
	case 1: case 2: case 4: ;
	   }
	penum->pcolor = &penum->rcolor;
	penum->rcolor.hue = penum->rcolor.saturation = 0;
	return image_init(penum, width, height, log2_bps, pmat, pgs, pgs->device->black, pgs->device->white);
}

/* Start processing a masked image */
int
gs_imagemask_init(gs_image_enum *penum, gs_state *pgs,
  int width, int height, int invert, gs_matrix *pmat)
{	gx_color_index color0, color1;
	penum->pcolor = pgs->color;
	gx_color_render(pgs->color, pgs);
	/* The following is wrong for halftones, but */
	/* it doesn't matter, because color0 and color1 */
	/* won't be used if the color isn't pure. */
	if ( invert )
		color0 = gx_no_color_index,
		color1 = pgs->color->dev_color.color1;
	else
		color0 = pgs->color->dev_color.color1,
		color1 = gx_no_color_index;
	return image_init(penum, width, height, 0, pmat, pgs, color0, color1);
}

/* Common setup for image and imagemask. */
private unsigned long big_end_map_4_to_32[16] = {
	0x00000000L, 0x000000ffL, 0x0000ff00L, 0x0000ffffL,
	0x00ff0000L, 0x00ff00ffL, 0x00ffff00L, 0x00ffffffL,
	0xff000000L, 0xff0000ffL, 0xff00ff00L, 0xff00ffffL,
	0xffff0000L, 0xffff00ffL, 0xffffff00L, 0xffffffffL
   };
private unsigned long little_end_map_4_to_32[16] = {
	0x00000000L, 0xff000000L, 0x00ff0000L, 0xffff0000L,
	0x0000ff00L, 0xff00ff00L, 0x00ffff00L, 0xffffff00L,
	0x000000ffL, 0xff0000ffL, 0x00ff00ffL, 0xffff00ffL,
	0x0000ffffL, 0xff00ffffL, 0x00ffffffL, 0xffffffffL
   };
private unsigned long *map_4_to_32;
private unsigned short big_end_map_4_to_16[16] = {
	0x0000, 0x0055, 0x00aa, 0x00ff,  0x5500, 0x5555, 0x55aa, 0x55ff,
	0xaa00, 0xaa55, 0xaaaa, 0xaaff,  0xff00, 0xff55, 0xffaa, 0xffff
   };
private unsigned short little_end_map_4_to_16[16] = {
	0x0000, 0x5500, 0xaa00, 0xff00,  0x0055, 0x5555, 0xaa55, 0xff55,
	0x00aa, 0x55aa, 0xaaaa, 0xffaa,  0xaaff, 0x55ff, 0xaaff, 0xffff
   };
private unsigned short *map_4_to_16;
private int
image_init(register gs_image_enum *penum, int width, int height,
  int log2_bps, gs_matrix *pmat, gs_state *pgs,
  gx_color_index color0, gx_color_index color1)
{	int code;
	gs_matrix mat;
	uint bsize = width + 8;		/* round up, +1 for end-of-run byte */
	byte *buffer;
	if ( width <= 0 || height < 0 )
		return_error(gs_error_undefinedresult);
	if ( height == 0 ) return 0;	/* empty image */
	if (	(code = gs_matrix_invert(pmat, &mat)) < 0 ||
		(code = gs_matrix_multiply(&mat, &pgs->ctm, &mat)) < 0
	   )	return code;
	buffer = (byte *)malloc(bsize);
	if ( buffer == 0 ) return_error(gs_error_VMerror);
	/* We really only need to do the following once.... */
	if ( *(char *)&big_end_map_4_to_32[1] )
	   {	/* little-endian */
		map_4_to_32 = little_end_map_4_to_32;
		map_4_to_16 = little_end_map_4_to_16;
	   }
	else
	   {	/* big-endian */
		map_4_to_32 = big_end_map_4_to_32;
		map_4_to_16 = big_end_map_4_to_16;
	   }
	penum->width = width;
	penum->height = height;
	penum->log2_bps = log2_bps;
	penum->fxx = float2fixed(mat.xx);
	penum->fxy = float2fixed(mat.xy);
	penum->fyx = float2fixed(mat.yx);
	penum->fyy = float2fixed(mat.yy);
	penum->ftx = float2fixed(mat.tx);
	penum->fty = float2fixed(mat.ty);
	penum->skewed = (penum->fxy | penum->fyx) != 0;
	penum->pgs = pgs;
	penum->buffer = buffer;
	penum->buffer_size = bsize;
	/* Initialize the color table */
#define chtl(i)\
  penum->colors[i].dev_color.halftone_level
	penum->icolor0 = color0;
	chtl(0) = 0;				/* pure color */
	penum->icolor1 = color1;
	chtl(15) = 0;				/* pure color */
	switch ( log2_bps )
	   {
	case 2:
		chtl(1) = chtl(2) = chtl(3) = chtl(4) =
		  chtl(6) = chtl(7) = chtl(8) = chtl(9) =
		  chtl(11) = chtl(12) = chtl(13) = chtl(14) = -1;
	case 1:
		chtl(5) = chtl(10) = -1;
	/* 0 and 3 don't need any further initialization */
	   }
#undef chtl
	/* If all four extrema of the image fall within the clipping */
	/* rectangle, clipping is never required. */
	   {	gx_path *pcpath = pgs->clip_path;
		int xmin = fixed2int(pcpath->cbox.xmin);
		int ymin = fixed2int(pcpath->cbox.ymin);
		int xmax = fixed2int(pcpath->cbox.xmax);
		int ymax = fixed2int(pcpath->cbox.ymax);
		int mtx = mat.tx, mty = mat.ty;
		int mdx, mdy;
		gs_point mdim;
		gs_distance_transform((float)width, (float)height, &mat, &mdim);
		mdx = mdim.x, mdy = mdim.y;
		penum->never_clip =
			(mdx < 0 ?
				mtx + mdx > xmin && mtx < xmax :
				mtx > xmin && mtx + mdx < xmax) &&
			(mdy < 0 ?
				mty + mdy > ymin && mty < ymax :
				mty > ymin && mty + mdy < ymax);
	   }
	   {	static int (*mono_procs[4])(iprocess_proc_args) = {
			image_process_0, image_process_1,
			image_process_2, image_process_3
		   };
		penum->slow_loop = !penum->never_clip || penum->skewed ||
			/* Use slow loop for imagemask with a halftone */
			((color0 == gx_no_color_index || color1 == gx_no_color_index) && !color_is_pure(pgs->color));
		penum->process =
			(log2_bps == 0 && !penum->slow_loop ?
			 image_process_direct :
			 mono_procs[log2_bps]);
	   }
	penum->x = penum->y = 0;
	penum->xrow = penum->xcur = penum->ftx;
	penum->yrow = penum->ycur = penum->fty;
#ifdef DEBUG
if ( gs_debug['b'] )
	printf("[b]Image: w=%d h=%d %s\n   [%f %f %f %f %f %f]\n",
		width, height, (penum->never_clip ? "no clip" : "must clip"),
		mat.xx, mat.xy, mat.yx, mat.yy, mat.tx, mat.ty);
#endif
	return 0;
}

/* Process the next piece of an image */
int
gs_image_next(register gs_image_enum *penum, byte *dbytes, uint dsize)
{	byte *data = dbytes;
	uint size = dsize;
	int code;
	int log2_spb = 3 - penum->log2_bps;	/* samples per byte */
	while ( size )
	   {	int left = penum->width - penum->x;
		int samples_to_use = size << log2_spb;
		if ( samples_to_use >= left )
		   {	int bytes_to_use = ((left - 1) >> log2_spb) + 1;
			code = (*penum->process)(penum, data, left);
			penum->y++;
			if ( code >= 0 && penum->y == penum->height )
			   {	/* All done */
				free((char *)penum->buffer);
				return 1;
			   }
			penum->x = 0;
			/* Advance coordinates to next row */
			penum->xcur = penum->xrow += penum->fyx;
			penum->ycur = penum->yrow += penum->fyy;
			size -= bytes_to_use;
			data += bytes_to_use;
		   }
		else
		   {	code = (*penum->process)(penum, data, samples_to_use);
			penum->x += samples_to_use;
			penum->xcur += penum->fxx * samples_to_use;
			penum->ycur += penum->fxy * samples_to_use;
			size = 0;
		   }
		if ( code < 0 )		/* error, abort */
		   {	free((char *)penum->buffer);
			return code;
		   }
	   }
	return 0;
}

/* Procedure for displaying a 1-bit-per-pixel sampled image */
/* with no clipping, skewing, or rotation. */
/* This checks whether a direct BitBlt is possible. */
private int
image_process_direct(gs_image_enum *penum, byte *data, int w)
{	fixed xt = penum->xcur;
	long dw2 = fixed2long((xt + w * penum->fxx) << 1) - fixed2long(xt << 1);
	if ( dw2 == w << 1 )
	   {	/* Samples are 1-for-1 with device pixels, no clipping */
		fixed yt = penum->ycur;
		int ix = fixed2int(xt), iy = fixed2int(yt);
		int ht = fixed2int(yt + penum->fyy) - iy;
		gx_device *dev = penum->pgs->device->info;
		int (*proc)(P10(gx_device *, byte *, int, int, int, int, int, int, gx_color_index, gx_color_index)) = dev->procs->copy_mono;
		gx_color_index zero = penum->icolor0, one = penum->icolor1;
		int dy;
		if ( ht < 0 )
			yt += ht, ht = -ht;
		for ( dy = 0; dy < ht; dy++ )
			(*proc)(dev, data, 0, 0, ix, iy + dy, w, 1, zero, one);
		return 0;
	   }
	return image_process_0(penum, data, w);
}

/* Procedures for expanding a sampled image to 1 byte per pixel. */
private int
image_process_0(gs_image_enum *penum, register byte *data, int w)
{	byte *buffer = penum->buffer;
	register unsigned long *bufp = (unsigned long *)buffer;
	int left;
	for ( left = (w + 7) >> 3; left--; )
	   {	register unsigned b = *data++;
		*bufp++ = map_4_to_32[b >> 4];
		*bufp++ = map_4_to_32[b & 0xf];
	   }
	return image_process_mono(penum, buffer, w);
}
private int
image_process_1(gs_image_enum *penum, register byte *data, int w)
{	byte *buffer = penum->buffer;
	register unsigned short *bufp = (unsigned short *)buffer;
	int left;
	for ( left = (w + 3) >> 2; left--; )
	   {	register unsigned b = *data++;
		*bufp++ = map_4_to_16[b >> 4];
		*bufp++ = map_4_to_16[b & 0xf];
	   }
	return image_process_mono(penum, buffer, w);
}
private int
image_process_2(gs_image_enum *penum, register byte *data, int w)
{	byte *buffer = penum->buffer;
	register byte *bufp = buffer;
	int left;
	for ( left = (w + 1) >> 1; left--; )
	   {	register unsigned b = *data++;
		*bufp++ = (b & 0xf0) + (b >> 4);
		b &= 0xf;
		*bufp++ = (b << 4) + b;
	   }
	return image_process_mono(penum, buffer, w);
}
private int
image_process_3(gs_image_enum *penum, byte *data, int w)
{	byte *buffer = penum->buffer;
	memcpy(buffer, data, w);
	return image_process_mono(penum, buffer, w);
}

/* Common procedure for the general case of displaying a sampled image, */
/* dealing with multiple bit-per-sample images, */
/* bits not 1-for-1 with the device, clipping, and general transformations. */
/* This procedure handles a single (partial) scan line. */
private int
image_process_mono(gs_image_enum *penum, byte *buffer, int w)
{	gx_color_index zero = penum->icolor0, one = penum->icolor1;
	gs_state *pgs = penum->pgs;
	fixed	dxx = penum->fxx, dxy = penum->fxy,
		dyx = penum->fyx, dyy = penum->fyy;
	int skew = penum->skewed;
	fixed xt = penum->xcur;
	fixed ytf = penum->ycur;
	int yt, yb, ht;
	gs_color *pcolor = penum->pcolor;
/* Note: image_set_gray assumes that log2_bps != 0. */
#define image_set_rgb(sample_value)\
  pcolor->brightness = pcolor->red = pcolor->green = pcolor->blue =\
    (sample_value) * (max_color_param / 255)
#define image_set_gray(sample_value)\
  if ( penum->log2_bps == 3 )\
   { image_set_rgb(sample_value);\
     gx_color_render(pcolor, pgs);\
   }\
  else\
   { gx_device_color *pdevc;\
     pcolor = &penum->colors[(sample_value) >> 4];\
     pdevc = &pcolor->dev_color;\
     if ( pdevc->halftone_level < 0 )\
      { image_set_rgb(sample_value);\
	pcolor->hue = pcolor->saturation = 0;\
        gx_color_render(pcolor, pgs);\
      }\
     else\
       gx_color_load(pdevc, pgs);\
   }
	/* Spread or squeeze the bits horizontally. */
	int xcnt = w;
	fixed xl = xt;
	byte *psrc = buffer;
	fixed xrun = xt;		/* x at start of run */
	fixed yrun = ytf;		/* y ditto */
	int run = *psrc;		/* run value */
	int htrun = -2;			/* halftone run value */
	gx_device *dev = pgs->device->info;
	int (*fill_proc)(P6(gx_device *, int, int, int, int, gx_color_index)) = dev->procs->fill_rectangle;
	/* Make sure ybf > ytf */
	if ( dyy < 0 ) yrun = ytf -= (dyy = -dyy);
	if ( !skew )
		yt = fixed2int(ytf),
		yb = fixed2int(ytf + dyy),
		ht = yb - yt;
	buffer[w] = ~buffer[w - 1];	/* force end of run */
#ifdef DEBUG
if ( gs_debug['b'] )
		printf("[b]x=%d y=%d w=%d xt=%f yt=%f yb=%f\n",
			penum->x, penum->y, w,
			fixed2float(xt), fixed2float(ytf), fixed2float(ytf + dyy));
#endif
	while ( xcnt-- >= 0 )	/* 1 extra iteration */
				/* to handle final run */
	   {	if ( *psrc++ != run )
		   {	fixed xi = xl;
			/* Fill the region between */
			/* xrun and xi */
			fixed wi = xi - xrun;
			if ( wi < 0 )
				xrun = xi, wi = -wi;
			if ( penum->slow_loop )
			   {	/* Must use general fill */
				gx_path ipath;
				gx_path *ppath = &ipath;
				int code;
				/* Use halftone if needed. */
				/* Also handle imagemask here. */
				if ( run != htrun )
				   {	htrun = run;
					if ( run == 0 )
					   {	if ( zero == gx_no_color_index ) goto trans;
					   }
					else if ( run == 255 )
					   {	if ( one == gx_no_color_index ) goto trans;
					   }
					else
					   {	image_set_gray(run);
					   }
				   }
				gx_path_init(ppath, &pgs->memory_procs);
				code = gx_path_add_pgram(ppath,
					xrun, yrun, xrun + wi, ytf,
					xrun + wi + dyx, ytf + dyy);
				if ( code < 0 )
				   {	gx_path_release(ppath);
					return code;
				   }
				gx_fill_path(ppath, pcolor, pgs, gx_rule_winding_number);
				gx_path_release(ppath);
trans: ;		   }
			else if ( run == 0 )
			   {	if ( zero != gx_no_color_index )
				   {	int xint = fixed2int(xrun);
					(*fill_proc)(dev, xint, yt, fixed2int(xrun + wi) - xint, ht, zero);
				}
			   }
			else if ( run == 255 )
			   {	if ( one != gx_no_color_index )
				   {	int xint = fixed2int(xrun);
					(*fill_proc)(dev, xint, yt, fixed2int(xrun + wi) - xint, ht, one);
				   }
			   }
			else
			   {	int xint = fixed2int(xrun);
				/* Use halftone if needed */
				if ( run != htrun )
				   {	image_set_gray(run);
					htrun = run;
				   }
				gz_fill_rectangle(xint, yt, fixed2int(xrun + wi) - xint, ht, pcolor, pgs);
			   }
			xrun = xi;
			yrun = ytf;
			run = psrc[-1];
		   }
		xl += dxx;
		ytf += dxy;		/* harmless if no skew */
	   }
	return 0;
}