home *** CD-ROM | disk | FTP | other *** search
- /*
- digsqcm.c
-
- % Compress the color palette for given pixel maps into a given color range.
-
- 2/22/88 By Ted.
-
- OWL-DIG 1.2
- Copyright (c) 1988-1990 by Oakland Group, Inc.
- ALL RIGHTS RESERVED.
-
- Revision History:
- -----------------
- 2/14/90 ted Moved to dig from pc directory for access by pc & mgr code
- 2/29/90 ted Added OCDECL for assembly function
- 3/28/90 jmd ansi-fied
- 4/21/90 ted Worked around some M6 warnings
- 6/01/90 jmd preened, added some casts to hist macros
- */
-
- #include "oakhead.h"
- #include "disppriv.h"
- #include "digutil.h"
- /* -------------------------------------------------------------------------- */
-
- typedef struct image_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_type;
-
- #define inithist(hist) memset((VOID *)hist, 0, 256*sizeof(unsigned))
- #define initbtab(ptab, val) memset((VOID *)ptab, val, 256*sizeof(byte))
- #define OC_BLACK 0,0,0
-
- /* -------------------------------------------------------------------------- */
-
- OSTATIC void DIGPRIV pal_slide(image_type image, ocolmap_type crange);
- OSTATIC void DIGPRIV pal_pickcols(image_type image, ocolmap_type crange);
- OSTATIC void DIGPRIV pal_match(image_type image, ocolmap_type tcmap, pmcswap_fptr pmcswap, pmnearcol_fptr nearest);
- OSTATIC void DIGPRIV initpick(image_type image);
- OSTATIC boolean DIGPRIV pickcol(image_type image, ocolmap_type crange, int next);
- OSTATIC byte DIGPRIV markpick(image_type image, unsigned pick);
- OSTATIC unsigned DIGPRIV dohist(image_type image, pmhist_fptr pmhist);
- OSTATIC void DIGPRIV initcswap(byte *swaptab);
-
- /* -------------------------------------------------------------------------- */
-
- void DIGPRIV dig_squeezecmap(pmap_type pmap, ocolmap_type cmap, ocolmap_type crange, pmhist_fptr pmhist, pmcswap_fptr pmcswap, pmnearcol_fptr nearest)
- /*
- Compress the color palette for a given set of pixel maps into a
- given color range.
- NOTE: currently works only for 8 bit-per-pixel pmaps.
-
- 'cmap' cmap belonging to pmap
- 'crange' color range to be squeezed into
- 'pmhist' DIG - specific way to histogram a pmap ' s pixvals
- 'pmcswap' DIG - specific way to shuffle a pmap ' s pixvals
- 'nearest' DIG - specific nearest - color finder
- */
- {
- struct image_struct 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, pmcswap, nearest); /* match pmap to new colors */
- }
- }
- else { /* Must squeeze */
- if (crange->nentries >= dohist(&image, pmhist)) {
- /* Can just shuffle by throwing out unused colors */
- pal_slide(&image, crange); /* slide color range into place */
- pal_match(&image, crange, pmcswap, nearest); /* 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, pmcswap, nearest); /* 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_type 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_type 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_type image, ocolmap_type tcmap, pmcswap_fptr pmcswap, pmnearcol_fptr nearest)
- /*
- 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) (*nearest)(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) {
- (*pmcswap)(image->maps[ipm], image->swaptab);
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
- static void DIGPRIV initpick(image_type 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_type 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_type 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 unsigned DIGPRIV dohist(image_type image, pmhist_fptr pmhist)
- {
- int ipm, icol, lastpix;
- unsigned nused;
-
- inithist(image->hist);
- for (ipm = 0; ipm < image->nmaps; ipm++) {
- if (image->maps[ipm] != NULL) {
- (*pmhist)(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(byte *swaptab)
- {
- int ipix;
-
- if (swaptab) {
- for (ipix=0; ipix < 256; ipix++) {
- swaptab[ipix] = (byte)ipix;
- }
- }
- }
- /* -------------------------------------------------------------------------- */
-
-