[comp.lang.c] Looking for routine to expand bitmap

bobc@attctc.Dallas.TX.US (Bob Calbridge) (08/08/89)

Novice that I am I have two unrelated problems to solve.  The first involves
expanding a bitmap.  For example, I have an N x M bitmap that I need to
expand by A to get a resulting AN x AM bitmap.  The vertical I can handle once
I get the horizontal expansion.  By way of example if I have an 8 X 14 bit
matrix and the first byte is 01101011 and I need to have it expanded 3 times
so that the resulting three bytes are 00011111,10001110,00111111, where each
zero is replaced by three zeros and ditto for the ones.

Is there a general algorithm for handling this type of expansion?

The second problem is probably simpler.  I have pretty much determined that
Turbo C stores integers with the least significant byte first.  One file
structure that I'm accessing does it most significant byte first.  I've used
a macro to get around the problem of printing out the value of this integer
but was wondering for the sake of manipulating the value if there is a standard
structure or "typedef" that can be used instead.

Thanks beaucoup,
Bob
-- 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=             I know it's petty..........                                     =
-                  But I have to justify my salary!                           -
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/09/89)

In article <8917@attctc.Dallas.TX.US> bobc@attctc.Dallas.TX.US (Bob Calbridge) writes:
>Is there a general algorithm for handling this type of expansion?

static void
Magnify( b, r, tb, p, fac )		/* adapted from "lens" */
	register Bitmap	*b, *tb;
	Rectangle	r;
	Point		p, fac;
	{
	register Bitmap	*stage;
	register int	i, shift;
	Point		d;
	Rectangle	s;

#if 0
	if ( fac.x < 1 || fac.y < 1 )	/* "can't happen" */
		return;
#endif

	d = sub( r.corner, r.origin );
	s.origin = p;
	s.corner = add( p, Pt( fac.x * d.x, fac.y * d.y ) );

	/* Copy source into origin of dest */

	bitblt( b, r, tb, p, F_STORE );

	/* Clear rest of dest */

	rectf( tb, Rect( s.origin.x + d.x, s.origin.y,
			 s.corner.x, s.corner.y
		       ),
	       F_CLR
	     );
	rectf( tb, Rect( s.origin.x, s.origin.y + d.y,
			 s.origin.x + d.x, s.corner.y
		       ),
	       F_CLR
	     );

	/* Now we expand in place */

	/* 1: expand horizontally */
	if ( fac.x > 1 )
		for( i = d.x - 1; i > 0; --i )
			{
			bitblt( tb, Rect( p.x + i, p.y, p.x + i + 1, p.y + d.y),
				tb, Pt( p.x + i * fac.x, p.y ), F_OR
			      );
			rectf( tb, Rect( p.x + i, p.y, p.x + i + 1, p.y + d.y ),
			       F_CLR
			     );
			}

	/* 2: smear horizontally */
	for( i = 1; i < fac.x; i *= 2 )
		{
		shift = min( i, fac.x - i );
		bitblt( tb, Rect( p.x, p.y, s.corner.x - shift, p.y + d.y ),
			tb, Pt( p.x + shift, p.y ), F_OR
		      );
		}

	/* 3: expand vertically */	
	if ( fac.y > 1 )
		for ( i = d.y - 1; i > 0; --i )
			{
			bitblt( tb, Rect( p.x, p.y + i, s.corner.x, p.y + i + 1
					),
				tb, Pt( p.x, p.y + i * fac.y ), F_OR
			      );
			rectf( tb, Rect( p.x, p.y + i, s.corner.x, p.y + i + 1
				       ),
			       F_CLR
			     );
			}

	/* 4: smear vertically */
	for ( i = 1; i < fac.y; i *= 2 )
		{
		shift = min( i, fac.y - i );
		bitblt( tb, Rect( p.x, p.y, s.corner.x, s.corner.y - shift ),
			tb, Pt( p.x, p.y + shift ), F_OR
		      );
		}	
	}

ado@elsie.UUCP (Arthur David Olson) (08/19/89)

Here's the X-Window-System code used to do such a job at elsie.
Doug Gwyn's code uses fewer bitblt operations;
this code applies operations to fewer bits.
--
X Window System is a trademark of the Massachusetts Institute of Technology.
-- 
	Arthur David Olson    ado@alw.nih.gov    ADO is a trademark of Ampex.

static int
is_power_of_two(i)
int	i;
{
	if (i > 0)
		while ((i % 2) == 0)
			i /= 2;
	return i == 1;
}

typedef enum {
	FORWARD,
	BACKWARD
} direction_t;

typedef enum {
	DONTSWAPXY,
	SWAPXY
} swapxy_t;

#define ROTCOPY(disp, src, dest, gc, sx, sy, w, h, dx, dy, swapxy) \
		(((swapxy) == DONTSWAPXY) ? \
			XCopyArea((disp), (src), (dest), (gc), \
				(sx), (sy), \
				(unsigned int) (w), (unsigned int) (h), \
				(dx), (dy)) : \
			XCopyArea((disp), (src), (dest), (gc), \
				(sy), (sx), \
				(unsigned int) (h), (unsigned int) (w), \
				(dy), (dx)))

static void
smear(disp, drawable, gc, x, y, w, h, direction, swapxy)
Display * const		disp;
const Drawable		drawable;
const GC		gc;
const int		x, y, w, h;
const direction_t	direction;
const swapxy_t		swapxy;
{
	register int	src_x, dest_x;
	register int	done, copy_w;

	if (h <= 0)
		return;
	for (done = 1; done < w; done += copy_w) {
		copy_w = w - done;
		if (copy_w > done)
			copy_w = done;
		if (direction == FORWARD) {
			dest_x = x + done;
			src_x = dest_x - copy_w;
		} else {
			src_x = x - done + 1;
			dest_x = src_x - copy_w;
		}
		ROTCOPY(disp, drawable, drawable, gc,
			src_x, y, copy_w, h, dest_x, y, swapxy);
	}
}

static void
enlsub(disp, drawable, gc, x, y, z, w, h, swapxy)
Display * const		disp;
const Drawable		drawable;
const int		x, y, z, w, h;
const GC		gc;
const swapxy_t		swapxy;
{
	register int	src_x, dest_x, copy_w;
	register int	special, final_z;

	if (w <= z) {
		smear(disp, drawable, gc, x, y, w, h, FORWARD, swapxy);
		return;
	}
	copy_w = (w - 1) % z + 1;
	src_x = x + (w - 1) / z - 1;
	dest_x = x + w - copy_w - 1;
	special = is_power_of_two(z - 1);
	for ( ; ; ) {
		ROTCOPY(disp, drawable, drawable, gc,
			src_x, y, 2, h, dest_x, y, swapxy);
		smear(disp, drawable, gc,
			dest_x + 1, y, copy_w, h, FORWARD, swapxy);
		if (src_x-- == x) {
			final_z = z - 1;
			break;
		}
		if (special && src_x > x) {
			copy_w = z - 1;
			dest_x -= z;
			continue;
		}
		smear(disp, drawable, gc, dest_x, y, z, h, BACKWARD, swapxy);
		if (src_x-- == x) {
			final_z = z;
			break;
		}
		copy_w = z;
		dest_x -= 2 * z;
	}
	smear(disp, drawable, gc, x, y, final_z, h, FORWARD, swapxy);
}

int
enlarge(disp, drawable, gc, x, y, z, w, h)
Display *	disp;
Drawable	drawable;
GC		gc;
int		x, y, z, w, h;
{
	register int	myh;

	if (z <= 1 || w <= 0 || h <= 0)
		return 0;
	myh = (h + z - 1) / z;
	enlsub(disp, drawable, gc, x, y, z, w, myh, DONTSWAPXY);
	enlsub(disp, drawable, gc, y, x, z, h, w, SWAPXY);
	return 0;
}