[comp.sys.mac.programmer] Precise Color with Offscreen Pixmap

jimo@phred.UUCP (Jim Osborn) (02/21/90)

What's the best way to achieve precise control over colors using an offscreen
PixMap and the Color Picker dialog?  I fill the offscreen PixMap with
8-bit indices and use CopyBits() to transfer the image to the window.
After I dismiss the Color Picker the screen flashes with the correct color
and then changes to a close-but-incorrect color, indicating that the
EraseRect() worked, but that either I filled the PixMap with the wrong
index, or CopyBits() failed to accurately copy the offscreen PixMap to my
window.  The fact that the incorrect color is close makes me worry about
limitations of some inverse mapping process within Color QD.

I'd like to be as friendly to other windows as possible, but I can't
afford to draw each pixel with MoveTo() and LineTo(), hence the need
to know the current color indices to place into the PixMap.

Here's the relevant code (TC 3.0, sys 6.0.4, Mac IIcx):
The important part (I think) is GetPix().

WindowPtr thescreen;
CGrafPort *myCGrafPtr;	/* Set up the offscreen PixMap per tn 120 */
long sizeofOff;		/* size in bytes of the PixMap image */
RGBColor fcolor, bcolor, thecolor;
PaletteHandle myPal;
char *myBits;		/* PixMap image baseaddr */
Rect r;
int lastindex;		/* remember the last color index */
#define pmIndex 5	/* palette index for window background color */

/*
 * Initialization includes:
 * myPal = NewPalette(6, NULL, pmTolerant, 0);
 * SetPalette(theScreen, myPal, TRUE);
 * ask to receive color-change updates
 */

/* 
 * This is the window update function:
 */
DrawWindow() {
	CGrafPort *savePort;

	GetPort(&savePort);
 	SetPort(theScreen);
	if (lastindex != Getpix(pmIndex)) /* Redraw PixMap if index changed */
		DrawBkg();
	BeginUpdate(theScreen);
	RGBForeColor(&fcolor);	/* black */
	RGBBackColor(&bcolor);	/* white */
	CopyBits((PixMapPtr) *myCGrafPtr->portPixMap, &theScreen->portBits,
		 &r, &r, 0, NULL);
	EndUpdate(theScreen);
	SetPort(savePort);
}

/*
 * Invoke the Color Picker dialog:
 */
SetColor() {
	int stat;
	
	if ((stat = GetColor(0L, string, &thecolor, &thecolor)) != 0) {
		SetEntryColor(myPal, pmIndex, &thecolor);
		ActivatePalette(theScreen);
	}
	return(stat);
}

/* 
 * Get the current PixMap index of the specified palette index:
 */
Getpix(index) {
 	RGBColor c, oldc;
 	int i;
 
	SetPort(theScreen);
	GetForeColor(&oldc);
	PmForeColor(index);
	GetForeColor(&c);
	i = (int) Color2Index(&c) & 0xFF;
	RGBForeColor(&oldc);
	return(i);
}

/* 
 * Fill window and the offscreen PixMap with the current background color:
 */
DrawBkg() {
	register long i;
	register char pix, *p;
 	RGBColor oldc;
		
	lastindex = Getpix(pmIndex);	/* sets port to our window */
	pix = (char) lastindex;
	i = sizeofOff-2;
	p = myBits-1;
	do {
		*++p = pix;
	} while (--i >= 0);
	GetBackColor(&oldc);
	PmBackColor(bkpmIndex);
	EraseRect(&r);
	RGBBackColor(&oldc);
}
-- 
pilchuck!jimo@phred		Jim Osborn, Physio Control Corp
				11811 Willows Rd, Redmond, WA, 98073
				206-867-4704 direct to my desk