[comp.sys.mac.programmer] color quickdraw and copybits glitches

ld231782@longs.LANCE.ColoState.Edu (Lawrence Detweiler) (12/08/89)

-----
Help!  I'm trying to use color quickdraw.  I'm looking to get the
updated Inside Macintosh that describes it.  In the mean time, can
someone help?  I have a program that works great except for COPYBITS,
which does strange things: 1) flips all color values--for example, I
have a greyscale palette, and when I do a direct bit transfer to the
screen, the colors range from black to white, but with COPYBITS, from
white to black! 2) this is what's really annoying--it refuses to put
white on the screen!  In my limited understanding I know this has
something to do with RGBFORECOLOR.  3) when I call up a dialog box,
several entries in my color table are replaced with the colors of the
apple logo.  Copybits thereafter avoids these entries when painting to
the screen!

I'm sure there is a method to all this madness.  Can someone summarize
the correct way to deal with color?  My palette setting routine avoids
entries 0 and 255, which are supposedly white and black.  I'd be greatly
grateful.  All I ask for is white!  (Please do not suggest setting
another entry to white other than the default; the program requires the
full range of values for TIFF pictures.)

oster@dewey.soe.berkeley.edu (David Phillip Oster) (12/08/89)

Once again, here is a short example of using color quickdraw. This
program takes a text file called "bush.ps" which is a postscript 16-gray
level bitmap of president bush, reads it in and displays it in a window.
This example is missing a few resources, and the actual "bush.ps" file.

/* ShowBush.c - short program to display a postscript picture of Bush.
	 in color quickdraw. You also get Bush on your clipboard.
   by David Phillip Oster.

   Copy and use this in any way you see fit.

	Basically an example of the pain you have to go through to actually
	use color quickdraw.

	In old quickdraw, you had some data and a window, and you CopyBit()s the data to
		the window.

	In color quickdraw, you have as your source:
		a.) the data.
		b.) a color table.
		c.) a "pixmap" that connects the data to the color table.
	as your destination, you have:
		a.) a color window
		b.) a palette, that informs the window manager of which colors you'll be
			using, so the color manager can change the color table in the video
			board to make those color available.

	This program works best with at least 16 colors!

 */
#include <ColorToolbox.h>

#define HEIGHT 200
#define WIDTH  200

#define NIL 0L
#define NOT !

SysEnvRec *world;
Handle			myPixels;
WindowPtr		myWin;
PixMapHandle	myPixMap;
CTabHandle		myCTable;
PaletteHandle	myPm;

enum {
	READERROR = 1,
	NEEDSCOLORQD,	/* this demo needs color quickdraw */
	NOPIXMAP,
	NOPIXELS,
	NOCTABLE,
	NOPALETTE,
	PIXDATACHANGED
};

enum {
	UNDOI = 1,
	COPYI = UNDOI + 1
};

main(){
	EventRecord myEvent;

	Init();
	for(;;){
		if(GetNextEvent(everyEvent, &myEvent)){
			HandleEvent(&myEvent);
		}
	}
}


Init(){
	PaletteHandle oldPm;

	FlushEvents(everyEvent, NIL);
	InitGraf( (Ptr) &thePort);
	InitFonts();
	InitWindows();
	InitCursor();
	InitDialogs(NIL);
	InitMenus();
	TEInit();

	world = (SysEnvRec *) NewPtr(sizeof(SysEnvRec));
	SysEnvirons(1, world);
	if( NOT world->hasColorQD){
		Error(NEEDSCOLORQD, "");
	}

	myWin = GetNewCWindow(128, NIL, -1L);				/* set up the window */
	SetPort(myWin);
	ClipRect(&thePort->portRect);

	myPixMap = NewPixMap();								/* allocate the pixmap */
	if(NIL == myPixMap){
		Error(NOPIXMAP, "");
	}
	myPixels = NewHandle( ((long) HEIGHT/2)*WIDTH);		/* allocate the pixel data */
	if(NIL == myPixels){
		Error(NOPIXELS, "");
	}													/* allocate the color table */
	myCTable = (CTabHandle) NewHandle(sizeof(ColorTable) + 15L*sizeof(ColorSpec));
	if(NIL == myCTable){
		Error(NOCTABLE, "");
	}
	InitPixels(myPixels);								/* set up the pixel data */
	InitCTable(myCTable);								/* set up the color table */

	(**myPixMap).bounds.left = 0;						/* set up the pixmap */
	(**myPixMap).bounds.top = 0;
	(**myPixMap).bounds.right = WIDTH;
	(**myPixMap).bounds.bottom = HEIGHT;
	(**myPixMap).rowBytes = 0x8000 | (WIDTH/2);
	if(NIL != (**myPixMap).pmTable)
		DisposHandle((**myPixMap).pmTable);
	(**myPixMap).pmTable = myCTable;
	(**myPixMap).pixelSize = 4;

	myPm = NewPalette(16, myCTable, pmTolerant, 0);		/* set up the palette */
	if(NIL == myPm){
		Error(NOPALETTE, "");
	}
	
	if(NIL != (oldPm = GetPalette(thePort))){
		DisposePalette(oldPm);
	}
	SetPalette(thePort, myPm, TRUE);
	ActivatePalette(thePort);
}

/* SwapMove - copy from src to dest, moving scan lines from top to bottom
	as you go (postscript images are upside down compared to quickdraw images)
 */
SwapMove(src, dest, cnt)Ptr src, dest;long cnt;{
	register short i, j;

	for(i = 0;i <200;i++){
		BlockMove(src + (i*(WIDTH/2)), dest  + ((199-i)*(WIDTH/2)), WIDTH/2);
	}
}

/* InitPixels- initialize our handle to the bush data
	SwapMove since Postscript is upside down from Mac.
 */
InitPixels(h)Handle h;{
	register Ptr p, pMax;
	register short i;
	Handle h2, GetBush();

	h2 = GetBush();
	SwapMove(*h2, *h, GetHandleSize(h));
}


/* InitCTable - initialize our color table to uniform gray
 */
InitCTable(ct)CTabHandle ct;{
	short i;

	(**ct).ctSeed = GetCTSeed();
	(**ct).ctFlags = 0;
	(**ct).ctSize  = 15;
	for(i = 0;i < 16;i++){
		(**ct).ctTable[i].value = i;
		(**ct).ctTable[i].rgb.red = 
		(**ct).ctTable[i].rgb.green = 
		(**ct).ctTable[i].rgb.blue  = (unsigned) i * 16*257;
	}
}

/* Error - print the error message
 */
Error(i, s1)short i;Str255 s1;{
	Str255 s;

	GetIndString(s, 128, i);
	ParamText(s, s1, "", "");
	Alert(129, NIL);
	ExitToShell();
}

/* HandleEvent - quit on mouse or key event
 */
HandleEvent(event)EventRecord *event;{
	switch(event->what){
	case mouseDown:
	case keyDown:	ExitToShell();
	case updateEvt:	GoUpdate(event);	break;
	}
}

/* GoUpdate - handle update event, paste it to clipboard
 */
GoUpdate(event)EventRecord *event;{
	SetPort(event->message);
	BeginUpdate(thePort);
	CopyMyBits();
	EndUpdate(thePort);
}

/* CopyMyBits - put bits to screen, put bits to clipboard
 */
CopyMyBits(){
	Rect r, r2;
	PicHandle ph;

	HLock(myPixels);
	HLock(myPixMap);
	(**myPixMap).baseAddr = *myPixels;
	r.left = 0;
	r.top = 0;
	r.right = WIDTH;
	r.bottom = HEIGHT;
	r2 = r;
	r2.top *= 2;
	r2.left *= 2;
	r2.right *= 2;
	r2.bottom *= 2;

	ph = OpenPicture(&r);
	CopyBits(*myPixMap, &thePort->portBits, &r, &r, srcCopy, NIL);
	ClosePicture();
	CopyBits(*myPixMap, &thePort->portBits, &r, &r2, srcCopy, NIL);

	HUnlock(myPixMap);
	HUnlock(myPixels);

	ZeroScrap();
	HLock(ph);
	PutScrap(GetHandleSize(ph), 'PICT', *ph);
	SystemEdit(COPYI-1);	/* so multifinder will take the scrap */
	KillPicture(ph);
}

/* GetBush
 */
Handle GetBush(){
	OSErr	val;
	short	ref;
	Handle	h;
	long	len;
	Str255	s;

	ref = 0;
	h = NIL;
	val = FSOpen("\pbush.ps", 0, &ref);
	if(noErr == val)val = GetEOF(ref, &len);
	if(noErr == val)h = NewHandle(len - 4);
	if(noErr == val && NIL != h){
		HLock(h);
		len = GetHandleSize(h);
		if(noErr == val)val = FSRead(ref, &len, *h);
		HexToBin(h);
		HUnlock(h);
	}
	if(0 != ref){
		FSClose(ref);
	}
	if(noErr != val){
		NumToString(val, s);
		Error(READERROR, s);
		if(NIL != h){
			DisposHandle(h);
			h = NIL;
		}
	}
	return h;
}

/* SkipHeader - advance p to point to data
 */
unsigned char *SkipHeader(p)register unsigned char *p;{
	while( NOT (p[0] == '\r' && p[1] == '0'))
		p++;

	return &p[1];
}

/* HexToBin - h is a locked handle containing text. turn it into binary
	Sorry about this. It is a quick and dirty hex ascii to binary routine.
 */
HexToBin(h)Handle h;{
	register unsigned char *src, *srcMax, *dest;

	src  = dest = (unsigned char *) *h;
	src = SkipHeader(src);
	srcMax = src + GetHandleSize(h);
	while(src < srcMax){
		if(*src >= '0' && *src <= '9'){
			*dest = (*src++ - '0') << 4;

			if(*src >= '0' && *src <= '9'){
				*dest++ |= *src++ - '0';
			}else if(*src >= 'A' && *src <= 'F'){
				*dest++ |= *src++ - 'A' + 10;	
			}else if(*src >= 'a' && *src <= 'f'){
				*dest++ |= *src++ - 'a' + 10;
			}
		}else if(*src >= 'A' && *src <= 'F'){
			*dest = (*src++ - 'A' + 10) << 4;

			if(*src >= '0' && *src <= '9'){
				*dest++ |= *src++ - '0';
			}else if(*src >= 'A' && *src <= 'F'){
				*dest++ |= *src++ - 'A' + 10;	
			}else if(*src >= 'a' && *src <= 'f'){
				*dest++ |= *src++ - 'a' + 10;
			}
		}else if(*src >= 'a' && *src <= 'f'){
			*dest = (*src++ - 'a' + 10) << 4;

			if(*src >= '0' && *src <= '9'){
				*dest++ |= *src++ - '0';
			}else if(*src >= 'A' && *src <= 'F'){
				*dest++ |= *src++ - 'A' + 10;	
			}else if(*src >= 'a' && *src <= 'f'){
				*dest++ |= *src++ - 'a' + 10;
			}
		}else{
			src++;
		}
	}
	SetHandleSize(h, dest - (unsigned char *) *h);
}