view src/imgproc.c @ 5492:e82f5b7010fe

Merge some stuff in man, fix up Makefile -------------------- ChangeLog entries follow: -------------------- man/ChangeLog addition: 2010-02-19 Ben Wing <ben@xemacs.org> * widget.texi: * widget.texi (Top): * widget.texi (Introduction): * widget.texi (User Interface): * widget.texi (Programming Example): * widget.texi (Setting Up the Buffer): * widget.texi (Basic Types): * widget.texi (link): * widget.texi (url-link): * widget.texi (info-link): * widget.texi (push-button): * widget.texi (editable-field): * widget.texi (text): * widget.texi (menu-choice): * widget.texi (radio-button-choice): * widget.texi (item): * widget.texi (choice-item): * widget.texi (toggle): * widget.texi (checkbox): * widget.texi (checklist): * widget.texi (editable-list): * widget.texi (group): * widget.texi (Sexp Types): * widget.texi (constants): * widget.texi (generic): * widget.texi (atoms): * widget.texi (composite): * widget.texi (Widget Properties): * widget.texi (Defining New Widgets): * widget.texi (Widget Browser): * widget.texi (Widget Minor Mode): * widget.texi (Utilities): * widget.texi (Widget Wishlist): * widget.texi (Widget Internals): * widget.texi (GNU Free Documentation License): * widget.texi (Index): Sync with FSF 23.1.92. 2010-02-19 Ben Wing <ben@xemacs.org> * texinfo/fdl.texi: New file. * texinfo/texinfo.texi: * texinfo/texinfo.texi (Top): * texinfo/texinfo.texi (Copying Conditions): * texinfo/texinfo.texi (Overview): * texinfo/texinfo.texi (Reporting Bugs): * texinfo/texinfo.texi (Using Texinfo): * texinfo/texinfo.texi (Output Formats): * texinfo/texinfo.texi (Info Files): * texinfo/texinfo.texi (Printed Books): * texinfo/texinfo.texi (Formatting Commands): * texinfo/texinfo.texi (Conventions): * texinfo/texinfo.texi (Comments): * texinfo/texinfo.texi (Minimum): * texinfo/texinfo.texi (Six Parts): * texinfo/texinfo.texi (Short Sample): * texinfo/texinfo.texi (History): * texinfo/texinfo.texi (Texinfo Mode): * texinfo/texinfo.texi (Texinfo Mode Overview): * texinfo/texinfo.texi (XEmacs Editing): * texinfo/texinfo.texi (Inserting): * texinfo/texinfo.texi (Showing the Structure): * texinfo/texinfo.texi (Updating Nodes and Menus): * texinfo/texinfo.texi (Updating Commands): * texinfo/texinfo.texi (Updating Requirements): * texinfo/texinfo.texi (Other Updating Commands): * texinfo/texinfo.texi (Info Formatting): * texinfo/texinfo.texi (Printing): * texinfo/texinfo.texi (Texinfo Mode Summary): * texinfo/texinfo.texi (Beginning a File): * texinfo/texinfo.texi (Sample Beginning): * texinfo/texinfo.texi (Texinfo File Header): * texinfo/texinfo.texi (First Line): * texinfo/texinfo.texi (Start of Header): * texinfo/texinfo.texi (setfilename): * texinfo/texinfo.texi (settitle): * texinfo/texinfo.texi (End of Header): * texinfo/texinfo.texi (Document Permissions): * texinfo/texinfo.texi (copying): * texinfo/texinfo.texi (insertcopying): * texinfo/texinfo.texi (Titlepage & Copyright Page): * texinfo/texinfo.texi (titlepage): * texinfo/texinfo.texi (titlefont center sp): * texinfo/texinfo.texi (title subtitle author): * texinfo/texinfo.texi (Copyright): * texinfo/texinfo.texi (end titlepage): * texinfo/texinfo.texi (headings on off): * texinfo/texinfo.texi (Contents): * texinfo/texinfo.texi (The Top Node): * texinfo/texinfo.texi (Top Node Example): * texinfo/texinfo.texi (Master Menu Parts): * texinfo/texinfo.texi (Global Document Commands): * texinfo/texinfo.texi (documentdescription): * texinfo/texinfo.texi (setchapternewpage): * texinfo/texinfo.texi (paragraphindent): * texinfo/texinfo.texi (firstparagraphindent): * texinfo/texinfo.texi (exampleindent): * texinfo/texinfo.texi (Software Copying Permissions): * texinfo/texinfo.texi (Ending a File): * texinfo/texinfo.texi (Printing Indices & Menus): * texinfo/texinfo.texi (File End): * texinfo/texinfo.texi (Structuring): * texinfo/texinfo.texi (Tree Structuring): * texinfo/texinfo.texi (Structuring Command Types): * texinfo/texinfo.texi (makeinfo top): * texinfo/texinfo.texi (chapter): * texinfo/texinfo.texi (unnumbered & appendix): * texinfo/texinfo.texi (majorheading & chapheading): * texinfo/texinfo.texi (section): * texinfo/texinfo.texi (unnumberedsec appendixsec heading): * texinfo/texinfo.texi (subsection): * texinfo/texinfo.texi (unnumberedsubsec appendixsubsec subheading): * texinfo/texinfo.texi (subsubsection): * texinfo/texinfo.texi (Raise/lower sections): * texinfo/texinfo.texi (Nodes): * texinfo/texinfo.texi (Two Paths): * texinfo/texinfo.texi (Node Menu Illustration): * texinfo/texinfo.texi (node): * texinfo/texinfo.texi (Node Names): * texinfo/texinfo.texi (Writing a Node): * texinfo/texinfo.texi (Node Line Tips): * texinfo/texinfo.texi (Node Line Requirements): * texinfo/texinfo.texi (First Node): * texinfo/texinfo.texi (makeinfo top command): * texinfo/texinfo.texi (makeinfo Pointer Creation): * texinfo/texinfo.texi (anchor): * texinfo/texinfo.texi (Menus): * texinfo/texinfo.texi (Menu Location): * texinfo/texinfo.texi (Writing a Menu): * texinfo/texinfo.texi (Menu Parts): * texinfo/texinfo.texi (Less Cluttered Menu Entry): * texinfo/texinfo.texi (Menu Example): * texinfo/texinfo.texi (Other Info Files): * texinfo/texinfo.texi (Cross References): * texinfo/texinfo.texi (References): * texinfo/texinfo.texi (Cross Reference Commands): * texinfo/texinfo.texi (Cross Reference Parts): * texinfo/texinfo.texi (xref): * texinfo/texinfo.texi (Reference Syntax): * texinfo/texinfo.texi (One Argument): * texinfo/texinfo.texi (Two Arguments): * texinfo/texinfo.texi (Three Arguments): * texinfo/texinfo.texi (Four and Five Arguments): * texinfo/texinfo.texi (Top Node Naming): * texinfo/texinfo.texi (ref): * texinfo/texinfo.texi (pxref): * texinfo/texinfo.texi (inforef): * texinfo/texinfo.texi (uref): * texinfo/texinfo.texi (cite): * texinfo/texinfo.texi (Marking Text): * texinfo/texinfo.texi (Indicating): * texinfo/texinfo.texi (Useful Highlighting): * texinfo/texinfo.texi (code): * texinfo/texinfo.texi (kbd): * texinfo/texinfo.texi (key): * texinfo/texinfo.texi (samp): * texinfo/texinfo.texi (verb): * texinfo/texinfo.texi (var): * texinfo/texinfo.texi (env): * texinfo/texinfo.texi (file): * texinfo/texinfo.texi (command): * texinfo/texinfo.texi (option): * texinfo/texinfo.texi (dfn): * texinfo/texinfo.texi (abbr): * texinfo/texinfo.texi (acronym): * texinfo/texinfo.texi (indicateurl): * texinfo/texinfo.texi (email): * texinfo/texinfo.texi (Emphasis): * texinfo/texinfo.texi (emph & strong): * texinfo/texinfo.texi (Smallcaps): * texinfo/texinfo.texi (Fonts): * texinfo/texinfo.texi (Quotations and Examples): * texinfo/texinfo.texi (Block Enclosing Commands): * texinfo/texinfo.texi (quotation): * texinfo/texinfo.texi (example): * texinfo/texinfo.texi (verbatim): * texinfo/texinfo.texi (verbatiminclude): * texinfo/texinfo.texi (lisp): * texinfo/texinfo.texi (small): * texinfo/texinfo.texi (display): * texinfo/texinfo.texi (format): * texinfo/texinfo.texi (exdent): * texinfo/texinfo.texi (flushleft & flushright): * texinfo/texinfo.texi (noindent): * texinfo/texinfo.texi (indent): * texinfo/texinfo.texi (cartouche): * texinfo/texinfo.texi (Lists and Tables): * texinfo/texinfo.texi (Introducing Lists): * texinfo/texinfo.texi (itemize): * texinfo/texinfo.texi (enumerate): * texinfo/texinfo.texi (Two-column Tables): * texinfo/texinfo.texi (table): * texinfo/texinfo.texi (ftable vtable): * texinfo/texinfo.texi (itemx): * texinfo/texinfo.texi (Multi-column Tables): * texinfo/texinfo.texi (Multitable Column Widths): * texinfo/texinfo.texi (Multitable Rows): * texinfo/texinfo.texi (Special Displays): * texinfo/texinfo.texi (Floats): * texinfo/texinfo.texi (float): * texinfo/texinfo.texi (caption shortcaption): * texinfo/texinfo.texi (listoffloats): * texinfo/texinfo.texi (Images): * texinfo/texinfo.texi (Image Syntax): * texinfo/texinfo.texi (Image Scaling): * texinfo/texinfo.texi (Footnotes): * texinfo/texinfo.texi (Footnote Commands): * texinfo/texinfo.texi (Footnote Styles): * texinfo/texinfo.texi (Indices): * texinfo/texinfo.texi (Index Entries): * texinfo/texinfo.texi (Predefined Indices): * texinfo/texinfo.texi (Indexing Commands): * texinfo/texinfo.texi (Combining Indices): * texinfo/texinfo.texi (syncodeindex): * texinfo/texinfo.texi (synindex): * texinfo/texinfo.texi (New Indices): * texinfo/texinfo.texi (Insertions): * texinfo/texinfo.texi (Atsign Braces Comma): * texinfo/texinfo.texi (Inserting an Atsign): * texinfo/texinfo.texi (Inserting Braces): * texinfo/texinfo.texi (Inserting a Comma): * texinfo/texinfo.texi (Inserting Quote Characters): * texinfo/texinfo.texi (Inserting Space): * texinfo/texinfo.texi (Not Ending a Sentence): * texinfo/texinfo.texi (Ending a Sentence): * texinfo/texinfo.texi (Multiple Spaces): * texinfo/texinfo.texi (frenchspacing): * texinfo/texinfo.texi (dmn): * texinfo/texinfo.texi (Inserting Accents): * texinfo/texinfo.texi (Inserting Quotation Marks): * texinfo/texinfo.texi (Dots Bullets): * texinfo/texinfo.texi (dots): * texinfo/texinfo.texi (bullet): * texinfo/texinfo.texi (TeX and copyright): * texinfo/texinfo.texi (tex): * texinfo/texinfo.texi (copyright symbol): * texinfo/texinfo.texi (registered symbol): * texinfo/texinfo.texi (euro): * texinfo/texinfo.texi (pounds): * texinfo/texinfo.texi (textdegree): * texinfo/texinfo.texi (minus): * texinfo/texinfo.texi (geq leq): * texinfo/texinfo.texi (math): * texinfo/texinfo.texi (Click Sequences): * texinfo/texinfo.texi (Glyphs): * texinfo/texinfo.texi (Glyphs Summary): * texinfo/texinfo.texi (result): * texinfo/texinfo.texi (expansion): * texinfo/texinfo.texi (Print Glyph): * texinfo/texinfo.texi (Error Glyph): * texinfo/texinfo.texi (Equivalence): * texinfo/texinfo.texi (Point Glyph): * texinfo/texinfo.texi (Breaks): * texinfo/texinfo.texi (Break Commands): * texinfo/texinfo.texi (Line Breaks): * texinfo/texinfo.texi (- and hyphenation): * texinfo/texinfo.texi (allowcodebreaks): * texinfo/texinfo.texi (w): * texinfo/texinfo.texi (tie): * texinfo/texinfo.texi (sp): * texinfo/texinfo.texi (page): * texinfo/texinfo.texi (group): * texinfo/texinfo.texi (need): * texinfo/texinfo.texi (Definition Commands): * texinfo/texinfo.texi (Def Cmd Template): * texinfo/texinfo.texi (Def Cmd Continuation Lines): * texinfo/texinfo.texi (Optional Arguments): * texinfo/texinfo.texi (deffnx): * texinfo/texinfo.texi (Def Cmds in Detail): * texinfo/texinfo.texi (Functions Commands): * texinfo/texinfo.texi (Variables Commands): * texinfo/texinfo.texi (Typed Functions): * texinfo/texinfo.texi (Typed Variables): * texinfo/texinfo.texi (Data Types): * texinfo/texinfo.texi (Abstract Objects): * texinfo/texinfo.texi (Object-Oriented Variables): * texinfo/texinfo.texi (Object-Oriented Methods): * texinfo/texinfo.texi (Defining Macros): * texinfo/texinfo.texi (Invoking Macros): * texinfo/texinfo.texi (Macro Details): * texinfo/texinfo.texi (alias): * texinfo/texinfo.texi (definfoenclose): * texinfo/texinfo.texi (Hardcopy): * texinfo/texinfo.texi (Use TeX): * texinfo/texinfo.texi (Format with tex/texindex): * texinfo/texinfo.texi (Format with texi2dvi): * texinfo/texinfo.texi (Print with lpr): * texinfo/texinfo.texi (Within XEmacs): * texinfo/texinfo.texi (Texinfo Mode Printing): * texinfo/texinfo.texi (Compile-Command): * texinfo/texinfo.texi (Requirements Summary): * texinfo/texinfo.texi (Preparing for TeX): * texinfo/texinfo.texi (Overfull hboxes): * texinfo/texinfo.texi (smallbook): * texinfo/texinfo.texi (A4 Paper): * texinfo/texinfo.texi (pagesizes): * texinfo/texinfo.texi (Cropmarks and Magnification): * texinfo/texinfo.texi (PDF Output): * texinfo/texinfo.texi (Obtaining TeX): * texinfo/texinfo.texi (Creating and Installing Info Files): * texinfo/texinfo.texi (Creating an Info File): * texinfo/texinfo.texi (makeinfo advantages): * texinfo/texinfo.texi (Invoking makeinfo): * texinfo/texinfo.texi (makeinfo options): * texinfo/texinfo.texi (Pointer Validation): * texinfo/texinfo.texi (makeinfo in XEmacs): * texinfo/texinfo.texi (texinfo-format commands): * texinfo/texinfo.texi (Batch Formatting): * texinfo/texinfo.texi (Tag and Split Files): * texinfo/texinfo.texi (Installing an Info File): * texinfo/texinfo.texi (Directory File): * texinfo/texinfo.texi (New Info File): * texinfo/texinfo.texi (Other Info Directories): * texinfo/texinfo.texi (Installing Dir Entries): * texinfo/texinfo.texi (Invoking install-info): * texinfo/texinfo.texi (Generating HTML): * texinfo/texinfo.texi (HTML Translation): * texinfo/texinfo.texi (HTML Splitting): * texinfo/texinfo.texi (HTML CSS): * texinfo/texinfo.texi (HTML Xref): * texinfo/texinfo.texi (HTML Xref Link Basics): * texinfo/texinfo.texi (HTML Xref Node Name Expansion): * texinfo/texinfo.texi (HTML Xref Command Expansion): * texinfo/texinfo.texi (HTML Xref 8-bit Character Expansion): * texinfo/texinfo.texi (HTML Xref Mismatch): * texinfo/texinfo.texi (Command List): * texinfo/texinfo.texi (Command Syntax): * texinfo/texinfo.texi (Tips): * texinfo/texinfo.texi (Sample Texinfo Files): * texinfo/texinfo.texi (Short Sample Texinfo File): * texinfo/texinfo.texi (GNU Sample Texts): * texinfo/texinfo.texi (Invoking sample): * texinfo/texinfo.texi (GNU Free Documentation License): * texinfo/texinfo.texi (Index): * texinfo/texinfo.texi (Verbatim Copying License): * texinfo/texinfo.texi (All-permissive Copying License): * texinfo/texinfo.texi (Include Files): * texinfo/texinfo.texi (Using Include Files): * texinfo/texinfo.texi (texinfo-multiple-files-update): * texinfo/texinfo.texi (Include Files Requirements): * texinfo/texinfo.texi (Sample Include File): * texinfo/texinfo.texi (Include Files Evolution): * texinfo/texinfo.texi (Headings): * texinfo/texinfo.texi (Headings Introduced): * texinfo/texinfo.texi (Heading Format): * texinfo/texinfo.texi (Heading Choice): * texinfo/texinfo.texi (Custom Headings): * texinfo/texinfo.texi (Catching Mistakes): * texinfo/texinfo.texi (makeinfo Preferred): * texinfo/texinfo.texi (Debugging with Info): * texinfo/texinfo.texi (Debugging with TeX): * texinfo/texinfo.texi (Using texinfo-show-structure): * texinfo/texinfo.texi (Using occur): * texinfo/texinfo.texi (Running Info-Validate): * texinfo/texinfo.texi (Using Info-validate): * texinfo/texinfo.texi (Unsplit): * texinfo/texinfo.texi (Tagifying): * texinfo/texinfo.texi (Splitting): * texinfo/texinfo.texi (Refilling Paragraphs): * texinfo/texinfo.texi (Command and Variable Index): * texinfo/texinfo.texi (General Index): * texinfo/version.texi: New file. Sync with FSF 23.1.92. Make new directory to hold the files needed to generate texinfo.info, since there are three such files now. 2010-02-19 Ben Wing <ben@xemacs.org> * Makefile: * Makefile (src_files1): * Makefile (DIR): * Makefile (texinfo-srcs): * Makefile ($(INFODIR)/widget.info): * Makefile ($(INFODIR)/texinfo.info): * Makefile (.PHONY): * Makefile (texinfo.dvi): * Makefile (texinfo.pdf): * Makefile ($(HTMLDIR)/widget.html): * Makefile ($(HTMLDIR)/texinfo.html): Incorporate texinfo.texi moving to a subdirectory texinfo/. Do some tricks to reduce the amount of duplication while still maintaining compatible with non-GNU make (at least, with Solaris make). * doclicense.texi: New file. * info.texi: * info.texi (Top): * info.texi (Getting Started): * info.texi (Help-Small-Screen): * info.texi (Help): * info.texi (Help-P): * info.texi (Help-^L): * info.texi (Help-Inv): * info.texi (Help-]): * info.texi (Help-M): * info.texi (Help-FOO): * info.texi (Help-Xref): * info.texi (Help-Int): * info.texi (Help-Q): * info.texi (Advanced): * info.texi (Search Text): * info.texi (Search Index): * info.texi (Go to node): * info.texi (Choose menu subtopic): * info.texi (Create Info buffer): * info.texi (XEmacs Info Variables): * info.texi (Expert Info): * info.texi (Add): * info.texi (Menus): * info.texi (Cross-refs): * info.texi (Help-Cross): * info.texi (Tags): * info.texi (Checking): * info.texi (Index): * texinfo.tex: * texinfo.tex (paragraphindent{%): * texinfo.tex (sectionheading will have): * texinfo.tex (chapterzzz{#3}%): * texinfo.tex (subsubsection = \numberedsubsubsec): * texinfo.tex (subsubsection = \appendixsubsubsec): * texinfo.tex (subsubsection = \unnumberedsubsubsec): * texinfo.tex (sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}%): * texinfo.tex (sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}%): * texinfo.tex (sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}%): * texinfo.tex (sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}%): * texinfo.tex (sectionheading{#1}{subsec}{Yappendix}%): * texinfo.tex (sectionheading{#1}{subsec}{Ynothing}%): * texinfo.tex (sectionheading{#1}{subsubsec}{Ynumbered}%): * texinfo.tex (sectionheading{#1}{subsubsec}{Yappendix}%): * texinfo.tex (sectionheading{#1}{subsubsec}{Ynothing}%): * texinfo.tex (sectionheading{#1}{subsubsec}{Yomitfromtoc}{}): * texinfo.tex (sectionheading to do the printing.): * texinfo.tex (sectionlevel}{#1}{#4}%): * texinfo.tex (sectionheading, q.v.): Sync with FSF 23.1.92.
author Ben Wing <ben@xemacs.org>
date Fri, 19 Feb 2010 22:39:19 -0600
parents 16112448d484
children 6c6d78781d59
line wrap: on
line source

/* Image processing functions
   Copyright (C) 1998 Jareth Hein

This file is a part of XEmacs

XEmacs is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.

XEmacs is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with XEmacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

/* Synched up with: Not in FSF. */

/* Original author: Jareth Hein */

/* Parts of this file are based on code from Sam Leffler's tiff library,
   with the original copyright displayed here:

   Copyright (c) 1988-1997 Sam Leffler
   Copyright (c) 1991-1997 Silicon Graphics, Inc.
   
   Permission to use, copy, modify, distribute, and sell this software and 
   its documentation for any purpose is hereby granted without fee, provided
   that (i) the above copyright notices and this permission notice appear in
   all copies of the software and related documentation, and (ii) the names of
   Sam Leffler and Silicon Graphics may not be used in any advertising or
   publicity relating to the software without the specific, prior written
   permission of Sam Leffler and Silicon Graphics. */

/* Quantizing code based off of the paper 
   Color Image Quantization for Frame Buffer Display, Paul Heckbert,
   Siggraph '82 proceedings, pp. 297-307 */

#include <config.h>
#include "lisp.h"
#include "imgproc.h"

static void
get_histogram(quant_table *qt, Binbyte *pic,
	      int width, int height, Colorbox* box)
{
  register Binbyte *inptr;
  register int red, green, blue;
  register int j, i;

  box->rmin = box->gmin = box->bmin = 999;
  box->rmax = box->gmax = box->bmax = -1;
  box->total = width * height;

  inptr = pic;
  for (i = 0; i < height; i++)
    {
      for (j = width; j-- > 0;)
	{
	  red = *inptr++ >> COLOR_SHIFT;
	  green = *inptr++ >> COLOR_SHIFT;
	  blue = *inptr++ >> COLOR_SHIFT;
	  if (red < box->rmin)
	    box->rmin = red;
	  if (red > box->rmax)
	    box->rmax = red;
	  if (green < box->gmin)
	    box->gmin = green;
	  if (green > box->gmax)
	    box->gmax = green;
	  if (blue < box->bmin)
	    box->bmin = blue;
	  if (blue > box->bmax)
	    box->bmax = blue;
	  qt->histogram[red][green][blue]++;
	}
    }
}

static Colorbox *
largest_box(quant_table *qt)
{
  register Colorbox *p, *b;
  register int size;

  b = NULL;
  size = -1;
  for (p = qt->usedboxes; p != NULL; p = p->next)
    if ((p->rmax > p->rmin || p->gmax > p->gmin ||
	 p->bmax > p->bmin) &&  p->total > size)
      size = (b = p)->total;
  return (b);
}

static void
shrinkbox(quant_table *qt, Colorbox* box)
{
  register int *histp, ir, ig, ib;

  if (box->rmax > box->rmin)
    {
      for (ir = box->rmin; ir <= box->rmax; ++ir)
	for (ig = box->gmin; ig <= box->gmax; ++ig)
	  {
	    histp = &(qt->histogram[ir][ig][box->bmin]);
	    for (ib = box->bmin; ib <= box->bmax; ++ib)
	      if (*histp++ != 0)
		{
		  box->rmin = ir;
		  goto have_rmin;
		}
	  }
    have_rmin:
      if (box->rmax > box->rmin)
	for (ir = box->rmax; ir >= box->rmin; --ir)
	  for (ig = box->gmin; ig <= box->gmax; ++ig)
	    {
	      histp = &(qt->histogram[ir][ig][box->bmin]);
	      ib = box->bmin;
	      for (; ib <= box->bmax; ++ib)
		if (*histp++ != 0)
		  {
		    box->rmax = ir;
		    goto have_rmax;
		  }
	    }
    }
 have_rmax:
  if (box->gmax > box->gmin)
    {
      for (ig = box->gmin; ig <= box->gmax; ++ig)
	for (ir = box->rmin; ir <= box->rmax; ++ir)
	  {
	    histp = &(qt->histogram[ir][ig][box->bmin]);
	    for (ib = box->bmin; ib <= box->bmax; ++ib)
	      if (*histp++ != 0)
		{
		  box->gmin = ig;
		  goto have_gmin;
		}
	  }
    have_gmin:
      if (box->gmax > box->gmin)
	for (ig = box->gmax; ig >= box->gmin; --ig)
	  for (ir = box->rmin; ir <= box->rmax; ++ir)
	    {
	      histp = &(qt->histogram[ir][ig][box->bmin]);
	      ib = box->bmin;
	      for (; ib <= box->bmax; ++ib)
		if (*histp++ != 0)
		  {
		    box->gmax = ig;
		    goto have_gmax;
		  }
	    }
    }
 have_gmax:
  if (box->bmax > box->bmin)
    {
      for (ib = box->bmin; ib <= box->bmax; ++ib)
	for (ir = box->rmin; ir <= box->rmax; ++ir)
	  {
	    histp = &(qt->histogram[ir][box->gmin][ib]);
	    for (ig = box->gmin; ig <= box->gmax; ++ig)
	      {
		if (*histp != 0)
		  {
		    box->bmin = ib;
		    goto have_bmin;
		  }
		histp += B_LEN;
	      }
	  }
    have_bmin:
      if (box->bmax > box->bmin)
	for (ib = box->bmax; ib >= box->bmin; --ib)
	  for (ir = box->rmin; ir <= box->rmax; ++ir)
	    {
	      histp = &(qt->histogram[ir][box->gmin][ib]);
	      ig = box->gmin;
	      for (; ig <= box->gmax; ++ig)
		{
		  if (*histp != 0)
		    {
		      box->bmax = ib;
		      goto have_bmax;
		    }
		  histp += B_LEN;
		}
	    }
    }
 have_bmax:
  ;
}

static void
splitbox(quant_table *qt, Colorbox* ptr)
{
  int		hist2[B_LEN];
  int		first = 0, last = 0;
  register Colorbox	*new_;
  register int	*iptr, *histp;
  register int	i, j;
  register int	ir,ig,ib;
  register int sum, sum1, sum2;
  enum { RED, GREEN, BLUE } axis;

  /*
   * See which axis is the largest, do a histogram along that
   * axis.  Split at median point.  Contract both new boxes to
   * fit points and return
   */
  i = ptr->rmax - ptr->rmin;
  if (i >= ptr->gmax - ptr->gmin  && i >= ptr->bmax - ptr->bmin)
    axis = RED;
  else if (ptr->gmax - ptr->gmin >= ptr->bmax - ptr->bmin)
    axis = GREEN;
  else
    axis = BLUE;
  /* get histogram along longest axis */
  switch (axis)
    {
    case RED:
      histp = &hist2[ptr->rmin];
      for (ir = ptr->rmin; ir <= ptr->rmax; ++ir)
	{
	  *histp = 0;
	  for (ig = ptr->gmin; ig <= ptr->gmax; ++ig)
	    {
	      iptr = &(qt->histogram[ir][ig][ptr->bmin]);
	      for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
		*histp += *iptr++;
	    }
	  histp++;
	}
      first = ptr->rmin;
      last = ptr->rmax;
      break;
    case GREEN:
      histp = &hist2[ptr->gmin];
      for (ig = ptr->gmin; ig <= ptr->gmax; ++ig)
	{
	  *histp = 0;
	  for (ir = ptr->rmin; ir <= ptr->rmax; ++ir)
	    {
	      iptr = &(qt->histogram[ir][ig][ptr->bmin]);
	      for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
		*histp += *iptr++;
	    }
	  histp++;
	}
      first = ptr->gmin;
      last = ptr->gmax;
      break;
    case BLUE:
      histp = &hist2[ptr->bmin];
      for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
	{
	  *histp = 0;
	  for (ir = ptr->rmin; ir <= ptr->rmax; ++ir)
	    {
	      iptr = &(qt->histogram[ir][ptr->gmin][ib]);
	      for (ig = ptr->gmin; ig <= ptr->gmax; ++ig)
		{
		  *histp += *iptr;
		  iptr += B_LEN;
		}
	    }
	  histp++;
	}
      first = ptr->bmin;
      last = ptr->bmax;
      break;
    }
  /* find median point */
  sum2 = ptr->total / 2;
  histp = &hist2[first];
  sum = 0;
  for (i = first; i <= last && (sum += *histp++) < sum2; ++i)
    ;
  if (i == first)
    i++;

  /* Create new box, re-allocate points */
  new_ = qt->freeboxes;
  qt->freeboxes = new_->next;
  if (qt->freeboxes)
    qt->freeboxes->prev = NULL;
  if (qt->usedboxes)
    qt->usedboxes->prev = new_;
  new_->next = qt->usedboxes;
  qt->usedboxes = new_;

  histp = &hist2[first];
  for (sum1 = 0, j = first; j < i; j++)
    sum1 += *histp++;
  for (sum2 = 0, j = i; j <= last; j++)
    sum2 += *histp++;
  new_->total = sum1;
  ptr->total = sum2;

  new_->rmin = ptr->rmin;
  new_->rmax = ptr->rmax;
  new_->gmin = ptr->gmin;
  new_->gmax = ptr->gmax;
  new_->bmin = ptr->bmin;
  new_->bmax = ptr->bmax;
  switch (axis)
    {
    case RED:
      new_->rmax = i-1;
      ptr->rmin = i;
      break;
    case GREEN:
      new_->gmax = i-1;
      ptr->gmin = i;
      break;
    case BLUE:
      new_->bmax = i-1;
      ptr->bmin = i;
      break;
    }
  shrinkbox (qt, new_);
  shrinkbox (qt, ptr);
}


static C_cell *
create_colorcell(quant_table *qt, int num_colors, int red, int green, int blue)
{
  register int ir, ig, ib, i;
  register C_cell *ptr;
  int mindist, next_n;
  register int tmp, dist, n;

  ir = red >> (COLOR_DEPTH-C_DEPTH);
  ig = green >> (COLOR_DEPTH-C_DEPTH);
  ib = blue >> (COLOR_DEPTH-C_DEPTH);
  ptr = xnew (C_cell);
  *(qt->ColorCells + ir*C_LEN*C_LEN + ig*C_LEN + ib) = ptr;
  ptr->num_ents = 0;

  /*
   * Step 1: find all colors inside this cell, while we're at
   *	   it, find distance of centermost point to furthest corner
   */
  mindist = 99999999;
  for (i = 0; i < num_colors; ++i)
    {
      if (qt->rm[i]>>(COLOR_DEPTH-C_DEPTH) != ir  ||
	  qt->gm[i]>>(COLOR_DEPTH-C_DEPTH) != ig  ||
	  qt->bm[i]>>(COLOR_DEPTH-C_DEPTH) != ib)
	continue;
      ptr->entries[ptr->num_ents][0] = i;
      ptr->entries[ptr->num_ents][1] = 0;
      ++ptr->num_ents;
      tmp = qt->rm[i] - red;
      if (tmp < (MAX_COLOR/C_LEN/2))
	tmp = MAX_COLOR/C_LEN-1 - tmp;
      dist = tmp*tmp;
      tmp = qt->gm[i] - green;
      if (tmp < (MAX_COLOR/C_LEN/2))
	tmp = MAX_COLOR/C_LEN-1 - tmp;
      dist += tmp*tmp;
      tmp = qt->bm[i] - blue;
      if (tmp < (MAX_COLOR/C_LEN/2))
	tmp = MAX_COLOR/C_LEN-1 - tmp;
      dist += tmp*tmp;
      if (dist < mindist)
	mindist = dist;
    }

  /*
   * Step 3: find all points within that distance to cell.
   */
  for (i = 0; i < num_colors; ++i)
    {
      if (qt->rm[i] >> (COLOR_DEPTH-C_DEPTH) == ir  &&
	  qt->gm[i] >> (COLOR_DEPTH-C_DEPTH) == ig  &&
	  qt->bm[i] >> (COLOR_DEPTH-C_DEPTH) == ib)
	continue;
      dist = 0;
      if ((tmp = red - qt->rm[i]) > 0 ||
	  (tmp = qt->rm[i] - (red + MAX_COLOR/C_LEN-1)) > 0 )
	dist += tmp*tmp;
      if ((tmp = green - qt->gm[i]) > 0 ||
	  (tmp = qt->gm[i] - (green + MAX_COLOR/C_LEN-1)) > 0 )
	dist += tmp*tmp;
      if ((tmp = blue - qt->bm[i]) > 0 ||
	  (tmp = qt->bm[i] - (blue + MAX_COLOR/C_LEN-1)) > 0 )
	dist += tmp*tmp;
      if (dist < mindist)
	{
	  ptr->entries[ptr->num_ents][0] = i;
	  ptr->entries[ptr->num_ents][1] = dist;
	  ++ptr->num_ents;
	}
    }

  /*
   * Sort color cells by distance, use cheap exchange sort
   */
  for (n = ptr->num_ents - 1; n > 0; n = next_n)
    {
      next_n = 0;
      for (i = 0; i < n; ++i)
	if (ptr->entries[i][1] > ptr->entries[i+1][1])
	  {
	    tmp = ptr->entries[i][0];
	    ptr->entries[i][0] = ptr->entries[i+1][0];
	    ptr->entries[i+1][0] = tmp;
	    tmp = ptr->entries[i][1];
	    ptr->entries[i][1] = ptr->entries[i+1][1];
	    ptr->entries[i+1][1] = tmp;
	    next_n = i;
	  }
    }
  return (ptr);
}

static int
map_colortable(quant_table *qt, int num_colors)
{
  register int *histp = &(qt->histogram[0][0][0]);
  register C_cell *cell;
  register int j, tmp, d2, dist;
  int ir, ig, ib, i;

  for (ir = 0; ir < B_LEN; ++ir)
    for (ig = 0; ig < B_LEN; ++ig)
      for (ib = 0; ib < B_LEN; ++ib, histp++)
	{
	  if (*histp == 0)
	    {
	      *histp = -1;
	      continue;
	    }
	  cell = *(qt->ColorCells +
		   (((ir>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2) +
		    ((ig>>(B_DEPTH-C_DEPTH)) << C_DEPTH) +
		    (ib>>(B_DEPTH-C_DEPTH))));
	  if (cell == NULL )
	    cell = create_colorcell (qt, num_colors,
				     ir << COLOR_SHIFT,
				     ig << COLOR_SHIFT,
				     ib << COLOR_SHIFT);
	  if (cell == NULL) /* memory exhausted! punt! */
	    return -1;
	  dist = 9999999;
	  for (i = 0; i < cell->num_ents &&
		 dist > cell->entries[i][1]; ++i)
	    {
	      j = cell->entries[i][0];
	      d2 = qt->rm[j] - (ir << COLOR_SHIFT);
	      d2 *= d2;
	      tmp = qt->gm[j] - (ig << COLOR_SHIFT);
	      d2 += tmp*tmp;
	      tmp = qt->bm[j] - (ib << COLOR_SHIFT);
	      d2 += tmp*tmp;
	      if (d2 < dist)
		{
		  dist = d2;
		  *histp = j;
		}
	    }
	}
  return 0;
}

quant_table *
build_EImage_quantable(Binbyte *eimage, int width, int height, int num_colors)
{
  quant_table *qt;
  Colorbox *box_list, *ptr;
  int i,res;

  qt = (quant_table*)xmalloc_and_zero (sizeof(quant_table));
  if (qt == NULL) return NULL;

  assert (num_colors < 257 && num_colors > 2);
  /*
   * STEP 1:  create empty boxes
   */
  qt->usedboxes = NULL;
  box_list = qt->freeboxes = xnew_array (Colorbox, num_colors);
  qt->freeboxes[0].next = &(qt->freeboxes[1]);
  qt->freeboxes[0].prev = NULL;
  for (i = 1; i < num_colors-1; ++i)
    {
      qt->freeboxes[i].next = &(qt->freeboxes[i+1]);
      qt->freeboxes[i].prev = &(qt->freeboxes[i-1]);
    }
  qt->freeboxes[num_colors-1].next = NULL;
  qt->freeboxes[num_colors-1].prev = &(qt->freeboxes[num_colors-2]);

  /*
   * STEP 2: get histogram, initialize first box
   */
  ptr = qt->freeboxes;
  qt->freeboxes = ptr->next;
  if (qt->freeboxes)
    qt->freeboxes->prev = NULL;
  ptr->next = qt->usedboxes;
  qt->usedboxes = ptr;
  if (ptr->next)
    ptr->next->prev = ptr;
  get_histogram (qt, eimage, width, height, ptr);

  /*
   * STEP 3: continually subdivide boxes until no more free
   * boxes remain or until all colors assigned.
   */
  while (qt->freeboxes != NULL)
    {
      ptr = largest_box(qt);
      if (ptr != NULL)
	splitbox (qt, ptr);
      else
	qt->freeboxes = NULL;
    }

  /*
   * STEP 4: assign colors to all boxes
   */
  for (i = 0, ptr = qt->usedboxes; ptr != NULL; ++i, ptr = ptr->next)
    {
      qt->rm[i] = ((ptr->rmin + ptr->rmax) << COLOR_SHIFT) / 2;
      qt->gm[i] = ((ptr->gmin + ptr->gmax) << COLOR_SHIFT) / 2;
      qt->bm[i] = ((ptr->bmin + ptr->bmax) << COLOR_SHIFT) / 2;
      qt->um[i] = ptr->total;
    }
  qt->num_active_colors = i;

  /* We're done with the boxes now */
  xfree (box_list);
  qt->freeboxes = qt->usedboxes = NULL;

  /*
   * STEP 5: scan histogram and map all values to closest color
   */
  /* 5a: create cell list as described in Heckbert */
  qt->ColorCells = (C_cell **)xmalloc_and_zero (C_LEN*C_LEN*C_LEN*sizeof (C_cell*));
  /* 5b: create mapping from truncated pixel space to color
     table entries */
  res = map_colortable (qt, num_colors);

  /* 5c: done with ColorCells */
  for (i = 0; i < C_LEN*C_LEN*C_LEN; i++)
    if (qt->ColorCells[i])
      xfree (qt->ColorCells[i]);
  xfree (qt->ColorCells);
  
  if (res)
    {
      /* we failed in memory allocation, so clean up and leave */
      xfree (qt);
      return NULL;
    }
  
  return qt;
}