home *** CD-ROM | disk | FTP | other *** search
- /*
- pcsqcmap.c
-
- % Compress the color palette for given pixel maps into a given color range.
-
- 2/22/88 By Ted.
-
- OWL 1.1
- Copyright (c) 1988, 1989 by Oakland Group, Inc.
- ALL RIGHTS RESERVED.
-
- Revision History:
- -----------------
- */
-
- #include "pcpriv.h"
-
- typedef struct {
- pmap_type *maps; /* array of pmaps to be translated to new colormap */
- int nmaps; /* number of pmaps in array */
- ocolmap_type cmap; /* old color map */
- unsigned short hist[256];/* histogram of color frequency in pmap */
- byte swaptab[256]; /* pixel map table for mapping pmap to new colormap */
- unsigned nunpicked; /* number of unpicked colors in new table */
- byte picktab[256]; /* map table from picked color in old map to new map */
- byte nopickval; /* place holder val for unpicked colors in picktab */
- } IMAGE;
-
- #define inithist(hist) memset(hist, 0, 256*sizeof(unsigned))
- #define initbtab(ptab, val) memset(ptab, val, 256*sizeof(byte))
- #define OC_BLACK 0,0,0
-
- OSTATIC void DIGPRIV pal_slide(_arg2(IMAGE *image, ocolmap_type crange));
- OSTATIC void DIGPRIV pal_pickcols(_arg2(IMAGE *image, ocolmap_type crange));
- OSTATIC void DIGPRIV pal_match(_arg2(IMAGE *image, ocolmap_type tcmap));
- OSTATIC boolean DIGPRIV pickcol(_arg3(IMAGE *image, ocolmap_type crange, int next));
- OSTATIC byte DIGPRIV markpick(_arg2(IMAGE *image, unsigned pick));
- OSTATIC void DIGPRIV initpick(_arg1(IMAGE *image));
- OSTATIC int DIGPRIV dohist(_arg1(IMAGE *image));
- OSTATIC void DIGPRIV initcswap(_arg1(byte *swaptab));
- OSTATIC void DIGPRIV pmap_cswap(_arg2(pmap_type pmap, byte *swaptab));
- OSTATIC void DIGPRIV bhist(_arg3(byte *buf, unsigned bufsize, unsigned short *histtab));
-
- /* nearestc.asm */
- opixval DIGPRIV ocolmap_nearestcol(_arg2(orgb_struct *rgb, ocolmap_type cmap));
-
- /* bxlat.asm */
- void DIGPRIV bxlat(_arg3(byte *bufaddr, unsigned bufsize, byte *swaptab));
- /* -------------------------------------------------------------------------- */
-
- void DIGPRIV pc_squeezecmap(pmap, cmap, crange)
- pmap_type pmap;
- ocolmap_type cmap; /* cmap belonging to pmaps */
- ocolmap_type crange; /* color range to be squeezed into */
- /*
- Compress the color palette for a given set of pixel maps into a
- given color range.
- */
- {
- IMAGE image;
-
- if (pmap == NULL || crange == NULL) {
- return;
- }
- /* If no cmap is given, put default colors in crange */
- if (cmap == NULL) {
- ocolmap_set(crange, disp_GetDefColMapp());
- return;
- }
- image.maps = &pmap;
- image.nmaps = 1;
- image.cmap = cmap;
-
- /* If all colors are allocated, no need to squeeze */
- if (crange->nentries >= cmap->nentries) {
- if (crange->firstpix == cmap->firstpix) {
- /* Color range in place; just copy it */
- ocolmap_set(crange, cmap);
- }
- else {
- /* Color range can be slid to fit */
- pal_slide(&image, crange); /* slide color range into place */
- pal_match(&image, crange); /* match pmap to new colors */
- }
- }
- else { /* Must squeeze */
- if (crange->nentries >= dohist(&image)) {
- /* Can just shuffle by throwing out unused colors */
- pal_slide(&image, crange); /* slide color range into place */
- pal_match(&image, crange); /* match pmap to new colors */
- }
- else {
- /* Must really squeeze */
-
- /* Clear out top 2 bits of each rgb level - squeeze funcs handle 6 bit levels */
- dig_shiftcmap(cmap, 2);
-
- pal_pickcols(&image, crange); /* squeeze colors into smaller range */
- pal_match(&image, crange); /* match pmap to new colors */
-
- /* Restore levels to 8-bit values */
- dig_shiftcmap(cmap, -2);
- dig_shiftcmap(crange, -2);
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void DIGPRIV pal_slide(image, crange)
- IMAGE *image;
- ocolmap_type crange;
- /*
- slide color range into place
- (sets up image->picktab & crange rgb entries)
- */
- {
- int iscol, idcol, firstdcol, lastscol;
- boolean doall;
-
- /* If crange has room for even unused colors, take them along for the ride */
- doall = (crange->nentries >= image->cmap->nentries);
-
- iscol = (int) image->cmap->firstpix;
- firstdcol = (int) crange->firstpix;
- idcol = firstdcol;
- lastscol = iscol + image->cmap->nentries - 1;
-
- image->nopickval = (byte)firstdcol-1; /* this will not get picked */
- initbtab(image->picktab, image->nopickval);
-
- for ( ; iscol <= lastscol; iscol++) {
- /* If a color is used or if we have room for it, take it */
- if (doall || image->hist[iscol] != 0) {
- ocolmap_getcolor(image->cmap, (opixval)iscol,
- crange, (opixval)idcol);
- image->picktab[iscol] = (byte)idcol++;
- }
- else { /* If color is unused, skip it and mark it as picked by mapping it to first dcol */
- image->picktab[iscol] = (byte)firstdcol;
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void DIGPRIV pal_pickcols(image, crange)
- IMAGE *image;
- ocolmap_type crange;
- /*
- Squeeze colors from image cmap into smaller crange
- (sets up image->picktab & crange rgb entries)
- */
- {
- int next, last;
-
- /* If crange starts at 0, use nentries as place marker instead of 0 */
- if ((int)crange->firstpix != 0 || crange->nentries == 256)
- image->nopickval = 0;
- else image->nopickval = (byte)(((int)crange->firstpix) + crange->nentries);
-
- initbtab(image->picktab, image->nopickval);
-
- initpick(image);
-
- next = (int) crange->firstpix;
- last = next + crange->nentries - 1;
-
- for (;;) {
- if (pickcol(image, crange, next)) {
- if (++next > last) break;
- }
- else break; /* if no more can be picked, quit */
- }
- /* Set leftover colors to black */
- for ( ; next <= last; next++) {
- ocolmap_setpixrgb(crange, (opixval) next, OC_BLACK);
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void DIGPRIV pal_match(image, tcmap)
- IMAGE *image;
- ocolmap_type tcmap;
- /*
- Match image colors to target colormap
- (construct color swap translation table from image to target cmap
- and then do the swap on image pmap(s))
- */
- {
- int ipix, jpix, ifirst, ilast;
- int ipm;
- int first, last;
- orgb_struct *ifirstentry;
-
- first = (int)tcmap->firstpix;
- last = first + tcmap->nentries - 1;
-
- /* Map any image colors not defined in image cmap to first target color */
- initbtab(image->swaptab, first);
-
- ifirst = (int)image->cmap->firstpix;
- ilast = ifirst + image->cmap->nentries - 1;
- ifirstentry = ocolmap_entry(image->cmap, ifirst);
- for (ipix = ifirst ; ipix <= ilast; ipix++) {
-
- /* First check if we've picked this color */
- if (image->picktab[ipix] != image->nopickval) {
- image->swaptab[ipix] = image->picktab[ipix];
- goto LOOP;
- }
- /* Next check if we've already done it */
- for (jpix = ifirst; jpix < ipix; jpix++) {
- if (ocolmap_samecolor(image->cmap, (opixval) ipix,
- image->cmap, (opixval) jpix)) {
- image->swaptab[ipix] = image->swaptab[jpix];
- goto LOOP;
- }
- }
- /* Then check if we're already there */
- if (ipix >= first && ipix <= last) {
- if (ocolmap_samecolor(image->cmap, (opixval)ipix,
- tcmap, (opixval)ipix)) {
- image->swaptab[ipix] = (byte)ipix;
- goto LOOP;
- }
- }
- /* If those didn't work, do the search */
- image->swaptab[ipix] =
- (byte) ocolmap_nearestcol(ifirstentry + (ipix-ifirst), tcmap);
- LOOP: ;
- }
- /* Finally, do the color swap translation on the pmap image buffers */
- for (ipm = 0; ipm < image->nmaps; ipm++) {
- if (image->maps[ipm] != NULL) {
- pmap_cswap(image->maps[ipm], image->swaptab);
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void DIGPRIV initpick(image)
- IMAGE *image;
- {
- int ipix, firstpix, lastpix;
- /*
- Note- The image swaptab is used for a different purpose here than in
- pal_match. Here it is used to speed picking an unpicked color at random
- It is used by the matching algorithm, not the mixing one, so at this
- point it is ok to make alternate use of it.
- */
-
- /* Mark out unused colors by marking them as already picked */
- /* (Count down instead of up to avoid side effects of markpick) */
-
- image->nunpicked = 256;
- initcswap(image->swaptab);
-
- firstpix = (int)image->cmap->firstpix;
- lastpix = firstpix + image->cmap->nentries - 1;
-
- for (ipix = 256-1; ipix >= 0; ipix--) {
- if (ipix > lastpix || image->hist[ipix] == 0 || ipix < firstpix) {
- markpick(image, ipix);
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static boolean DIGPRIV pickcol(image, crange, next)
- IMAGE *image;
- ocolmap_type crange;
- int next;
- {
- byte pick;
- int ipix;
-
- LOOP:
- if (image->nunpicked == 0) return FALSE;
-
- /* Get remapped pick value and also mark that choice as picked */
- pick = markpick(image, rand());
-
- /* Check if we've already done it */
- for (ipix = (int)crange->firstpix; ipix < next; ipix++) {
- if (ocolmap_samecolor(crange, (opixval) ipix,
- image->cmap, (opixval) pick)) {
- goto LOOP; /* Already had that one; go get another */
- }
- }
- /* It's a new color; make an entry for it */
- ocolmap_getcolor(image->cmap, (opixval) pick, crange, (opixval) next);
- image->picktab[pick] = (byte) next;
- return(TRUE);
- }
- /* -------------------------------------------------------------------------- */
-
- static byte DIGPRIV markpick(image, pick)
- IMAGE *image;
- unsigned pick;
- /*
- Pick a value, make sure it never gets picked again
- (returns an unpicked value even though 'pick' may have been picked before)
- */
- {
- byte realpick;
-
- pick %= image->nunpicked;
-
- /* Get out value just picked */
- realpick = image->swaptab[pick];
- image->nunpicked--;
-
- /* Slide remaining unpicked values into space just vacated */
- if (pick < image->nunpicked) {
- memcpy(&image->swaptab[pick],
- &image->swaptab[pick+1],
- image->nunpicked - pick);
- }
- /* Zero out the space just slid out of */
- image->swaptab[image->nunpicked] = 0;
-
- return(realpick);
- }
- /* -------------------------------------------------------------------------- */
-
- static int DIGPRIV dohist(image)
- IMAGE *image;
- {
- int ipm, icol, nused, lastpix;
-
- inithist(image->hist);
- for (ipm = 0; ipm < image->nmaps; ipm++) {
- if (image->maps[ipm] != NULL) {
- bhist(pcpmap_pixbuf(image->maps[ipm]),
- (unsigned) pcpmap_GetPlaneSize(image->maps[ipm]),
- image->hist);
- }
- }
- icol = (int)image->cmap->firstpix;
- lastpix = icol + image->cmap->nentries - 1;
-
- nused = 0;
- for ( ; icol <= lastpix; icol++) {
- if (image->hist[icol] != 0) nused++;
- }
- return(nused);
- }
- /* -------------------------------------------------------------------------- */
-
- static void DIGPRIV initcswap(swaptab)
- byte *swaptab;
- {
- int ipix;
- if (swaptab) {
- for (ipix=0; ipix < 256; ipix++)
- swaptab[ipix] = (byte)ipix;
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void DIGPRIV pmap_cswap(pmap, swaptab)
- pmap_type pmap;
- byte *swaptab;
- {
- if (pcpmap_pixbits(pmap) == 8) {
- bxlat(pcpmap_pixbuf(pmap), (unsigned)pcpmap_GetPlaneSize(pmap), swaptab);
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void DIGPRIV bhist(buf, bufsize, histtab)
- byte *buf;
- unsigned bufsize;
- unsigned short *histtab;
- /*
- Histogram nbytes bytes at buf into word table 'histtab'.
- Table must be pre-initialized; bhist starts incrementing w/o zeroing.
- */
- {
- for ( ; bufsize > 0; bufsize--) {
- histtab[*(buf++)]++;
- }
- }
- /* -------------------------------------------------------------------------- */
-
-