Store/get the values.
The parameters specify the mode (Index, RGB, HSV), a strategy for allocating colors, a strategy for sharing resources, and extra parameters as needed for the color allocation strategy. This level of specification completely abstracts away the management and ideosyncrasies of those X constructs that most people would just as well not know about. I've found that in using this system it is easy to experiment with the color allocation without changing well-behaved application code.
X11 is quite a hairy system. The typical programmer has to know many details of their own system and about the X library, such as visuals, depths, and so on. He has to know what constraints the X library imposes, what visuals can be used and how. The X learning curve is way too high for someone who just wants to piece together a simple program. Then, if the program is supposed to be broadly used, it has to be written to recognize and use different hardware configurations.
The purpose of this class is to provide a model for handling color which is built using high-level concepts to be passed as an argument to an X11PixelCanvas as shown in the following example, which creates two canvases, the first builds an X11PixelCanvasColorTable configured as an RGB color cube using 67% of the available colors on the System X Colormap, and the second shares the hardware X Colormap the first one used and builds another X11PixelCanvsColorTable configured for Index mode.
// Display X11 implementation is Screen based, NOT Display based. The Display // can be obtained from the screen. Screen * screen = DefaultScreenOfDisplay(X11DefaultDisplay()); X11PixelCanvasColorTable pcctbl1(screen, Display::RGB, Display::Percent, Display::System, 67.0); X11PixelCanvasColorTable pcctbl2(screen, Display::Index, Display::Percent, pcctbl1, 100.0);
If you run your program and discover that you maybe don't care about flashing with other programs, but you don't want flashing within your own, simply replace the "Display::System" above with "Display::New". Display::New in the 4th position tells the constructor to create a new hardware colormap (See constructors below for complete information). Pcctbl 2 has already been told to use whatever map pcctbl1 is using, so they will share that table.
X11PixelCanvasColorTable pcctbl1(screen, Display::RGB, Display::Percent, Display::New, 67.0); X11PixelCanvasColorTable pcctbl2(screen, Display::Index, Display::Percent, pcctbl1, 100.0);
Now suppose you've got this great image you want to see, and you don't care about flashing between your to maps. You just want the map #1 to be the best RGB map it can be. And you have a special Colormap that contains 128 table entries. So switch strategies from percent available to best, and remove the extra parameter, and allocate both from new maps.
X11PixelCanvasColorTable pcctbl1(screen, Display::RGB, Display::Best, Display::New); X11PixelCanvasColorTable pcctbl2(screen, Display::Index, Display::Custom, Display::New, 128);
You can see that this is a simple way of piecing together hardware colormap arrangements according to your needs. 5 basic strategies, 3 color configurations, control over colortable sharing, and control over "flashing" make this quite a flexible system. Its simplicity means that it is easy to change the underlying color allocation arrangement. The design of the library encourages the construction of applications that can work with just about any color configuration.
The Display library handles the allocation and deletion of shared resources behind the scenes in the X11ResourceManager class.
Once constructed, a pointer to the X11PixelCanvasColorTable is sent to the constructor of a X11PixelCanvas and provides all the color handling functionality.
The X11PixelCanvasColorTable can be shared by several X11PixelCanvases if desired. This arrangement would provide several windows whose colors were liked together.
Another arrangement is more than one X11PixelCanvasColorTable on a the same X11 hardware colormap. This is done by passing an existing X11PixelCanvasColorTable in the refmap, or 3rd parameter of the constructor. This gives you independent, smaller colormaps without flashing.
The PixelCanvasColorTable is distinguished from the
If the map is in Display::Index mode, you can install one or more
If the map is in Display::RGB or Display::HSV mode, the PixelCanvases that use it
can map multichannel color arrays into a single color index array using mapToColor3
functions.
The levels of colormaps from an application programmer's perspective are as follows:
One common way of building X applications is to try to get some range of color allocation
from the system colormap, then fall back to using a private map if that fails. This multiple
attempt method can be implemented using the library in combination with catching exceptions:
If in Display::Index mode, the application program can get information about active
Colormaps using the PixelCanvas interface. Code to refresh the display often needs
to know the size of the colortables,
which could change between refreshes, to correctly map values to [0,size-1] and
on to colorIndices using PixelCanvas's
mapToColor functions.
If in Display::RGB or Display::HSV mode, the application can get color cube size
information if necessary, but should instead send normalized arrays to mapToColor3
functions.
Default constructor uses default INDEX mode and DEFAULT colormap on DEFAULT visual.
equiv to (DefaultScreenOfDisplay(DefaultDisplay), IL_INDEX, IL_DEFAULT, IL_SYSTEM);
Dtor
All of these constructors have 4 required parameters
Additional parameters may be required according to combination of variables:
An exception is thrown if the combination of parameters is invalid or if
the requested map cannot be created due to limited resources. A good strategy
is to make several constructor requests, starting with the constraints you
need using successive relaxation, until the constructor does not throw an
exception.
Most applications use the MinMax strategy because of its tolerance.
Additional constructors for use when an X colormap has already
been allocated. Only the strategies Display::Percent and
Display::MinMax are provided at present.
Get a PseudoColor Visual and map based on mapRef enum
use an existing map
allocate cells for colormaps
deallocate cells for colormaps
Functions to choose a visual.
Functions to build for Index colorModels
(Multichannel Color)
Merge separate channel data into an output image.
This function maps floating values between 0 and 1
into a output image suitable for PixelCanvas::drawImage().
Allocate the best color cube given the map
Convenience function
Merge separate channel data into an output image.
This function maps floating values between 0 and 1
into a output image suitable for PixelCanvas::drawImage().
This one maps values between 0 and the integer
maximum value for each channel into a single
output image suitable for PixelCanvas::drawImage().
(Multichannel Color)
Transform arrays from the passed color model into
the colormodel of the XPCCT.
Does nothing if colorModel is Display::Index.
It is assumed that input arrays are in the range of [0,1]
Functions for RGB mode
Build the best map you can on mapRef's colormap
Functions for RGB mode
Functions for HSV mode
map [0,N-1] into colorpixels, where N is the current colormap size
The values are returned as unsigned integers in their respective
array.
same as above except the matrix is operated on in place. Only unsigned
values make sense here. I don't really know what to include here. Maybe
ask the code cop.
print details of class to ostream
Is the hardware colormap resizeable? ie. is it write-only?
resize the map if allowed. Returns True if resize was accepted
Install colors into the color table. Offset is zero-based. Colors
are installed into the PixelCanvasColorTable until the Arrays run out
or until the end of the colortable is reached. This only has an
effect if the ColorModel is Index. Values are clamped to [0.0,1.0].
Return the best index for the RGB values given
in INDEX mode, this means an exact match unless we cannot resize to
accomodate XAllocColorCell if required.
in RGB mode, this means map to index according to makeup of the map
in HSV mode, this means convert to HSV and call HSV2Index()
Return the best index for the HSV values given
in INDEX mode, convert to RGB and call RGB2Index
in RGB mode, convert to RGB and call RGB2Index()
in HSV mode, map to index according to makeup of the map
Return the total number of RW colors currently in use.
Return the number of colors per component in the map. Throws
an exception if this is not an HSV or RGB ColorTable.
Return the depth in bits of the colors
Return the number of colors that are still unallocated
Return pointer to display that is being used
Return True if the table is in colorIndex mode
Return True if the table is in RGB mode
Return True if the table is in HSV mode
Return True if the colortable can be resized.
Return the color model for multichannel color
Return the number of currently unallocated cells that can be allocated RW.
(Multi-Channel) Return the index given r,g,b values
(Multi-Channel)
// returns 0 if can allocate anything.
X11PixelCanvasColorTable * pickXPCCT()
{
X11PixelCanvasColorTable * xpcct = 0;
try {
// first try - get some number between 40 and 64 colors
// using the system colormap
xpcct = new X11PixelCanvasColorTable(screen,
Display::Index,
Display::MinMax,
Display::System,
40,64);
} catch (AipsError x) {
xpcct = 0;
}
if (xpcct) return;
try {
// second try - get 64 from a private map
xpcct = new X11PixelCanvasColorTable(screen,
Display::Index,
Display::Custom,
Display::New,
64);
} catch (AipsError x) {
xpcct = 0;
}
return xpcct;
}
Motivation
Wanted to be able harness the power and flexibility of the X Color Resources
in a simple way and minimize the knowledge of X required to use this
power and flexibility.
Example
See the test directory
To Do
Member Description
X11PixelCanvasColorTable()
Thought about having a Motif-style varargs constructor, but this interface
is much cleaner from the perspective of application code. So I favor making
lots of constructors to make the code more readable, and this gives you tighter
compile-time checking.
~X11PixelCanvasColorTable()
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, Display::SpecialMap refMap)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, const X11PixelCanvasColorTable & refMap)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, Display::SpecialMap refMap, uInt parm)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, const X11PixelCanvasColorTable & refMap, uInt parm)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, Display::SpecialMap refMap, Float perecent)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, const X11PixelCanvasColorTable & refMap, Float percent)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, Display::SpecialMap refMap, uInt minCells, uInt maxCells)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, const X11PixelCanvasColorTable & refMap, uInt minCells, uInt maxCells)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, Display::SpecialMap refMap, uInt n1, uInt n2, uInt n3)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, const X11PixelCanvasColorTable & refMap, uInt n1, uInt n2, uInt n3)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, Display::SpecialMap refMap, uInt min1, uInt min2, uInt min3, uInt max1, uInt max2, uInt max3)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, const X11PixelCanvasColorTable & refMap, uInt min1, uInt min2, uInt min3, uInt max1, uInt max2, uInt max3)
If you use hard-coded numbers for uInts or Floats, be sure to
let the compiler know it is unsigned (e.g., "(uInt)32" or "32U", not "32"). Numbers
are normally treated as signed.
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, XColormap useXCmap, Visual *useVisual, uInt parm)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, XColormap useXCmap, Visual *useVisual, uInt minCells, uInt maxCells)
X11PixelCanvasColorTable(Screen * screen, Display::ColorModel mapType, Display::Strategy strategy, XColormap useXCmap, Visual *useVisual, uInt min1, uInt min2, uInt min3, uInt max1, uInt max2, uInt max3)
void setPCVisualXCmap(Display::SpecialMap mapRef)
void setPCVisualXCmap(XColormap useXCmap, Visual *useVisual)
Bool allocCells(uInt nCells)
Bool deallocCells()
Visual * bestRGBVisual()
Visual * bestRWRGBVisual()
void buildMapIndexBest()
void buildMapIndexDefault()
void buildMapIndexMinMax(uInt minCells, uInt maxCells)
void buildMapIndexCustom(uInt nCells)
void buildMapIndexPercent(Float percent)
Bool allocColorCube()
Bool allocColorCube(uInt n1, uInt n2, uInt n3)
Allocate a color cube of a specific size
Bool allocColorCubeMinMax(uInt n1min, uInt n2min, uInt n3min, uInt n1max, uInt n2max, uInt n3max)
Allocate a color cube within the ranges of sizes
void copyColorCube(const X11PixelCanvasColorTable & mapRef)
Copy color cube info from the mapRef
void fillColorCubeRGB()
Fill a color cube with an RGB spectrum
void fillColorCubeHSV()
Fill a color cube with an HSV spectrum
void buildMaxHSV()
void mapToColor3(Array<uLong> & out, const Array<Float> & chan1in, const Array<Float> & chan2in, const Array<Float> & chan3in)
void mapToColor3(Array<uLong> & out, const Array<Double> & chan1in, const Array<Double> & chan2in, const Array<Double> & chan3in)
void mapToColor3(Array<uLong> & out, const Array<uShort> & chan1in, const Array<uShort> & chan2in, const Array<uShort> & chan3in)
void mapToColor3(Array<uLong> & out, const Array<uInt> & chan1in, const Array<uInt> & chan2in, const Array<uInt> & chan3in)
Bool colorSpaceMap(Display::ColorModel, const Array<Float> & chan1in, const Array<Float> & chan2in, const Array<Float> & chan3in, Array<Float> & chan1out, Array<Float> & chan2out, Array<Float> & chan3out)
void buildMapRGBBest(const X11PixelCanvasColorTable & mapRef)
void buildMapRGBBest(Display::SpecialMap mapRef)
void buildMapRGBDefault(const X11PixelCanvasColorTable & mapRef)
void buildMapRGBDefault(Display::SpecialMap mapRef)
void buildMapRGBMinMax(const X11PixelCanvasColorTable & mapRef, uInt minReds, uInt minGreens, uInt minBlues, uInt maxReds, uInt maxGreens, uInt maxBlues)
void buildMapRGBMinMax(Display::SpecialMap mapRef, uInt minReds, uInt minGreens, uInt minBlues, uInt maxReds, uInt maxGreens, uInt maxBlues)
void buildMapRGBCustom(const X11PixelCanvasColorTable & mapRef, uInt nReds, uInt nGreens, uInt nBlues)
void buildMapRGBCustom(Display::SpecialMap mapRef, uInt nReds, uInt nGreens, uInt nBlues)
void buildMapRGBPercent(const X11PixelCanvasColorTable & mapRef, Float percent)
void buildMapRGBPercent(Display::SpecialMap mapRef, Float percent)
void buildMapHSVBest(const X11PixelCanvasColorTable & mapRef)
void buildMapHSVBest(Display::SpecialMap mapRef)
void buildMapHSVDefault(const X11PixelCanvasColorTable & mapRef)
void buildMapHSVDefault(Display::SpecialMap mapRef)
void buildMapHSVMinMax(const X11PixelCanvasColorTable & mapRef, uInt minHues, uInt minSats, uInt minVals, uInt maxHues, uInt maxSats, uInt maxVals)
void buildMapHSVMinMax(uInt minHues, uInt minSats, uInt minVals, uInt maxHues, uInt maxSats, uInt maxVals)
void buildMapHSVCustom(const X11PixelCanvasColorTable & mapRef, uInt nHues, uInt nSats, uInt nVals)
void buildMapHSVCustom(uInt nHues, uInt nSats, uInt nVals)
void buildMapHSVPercent(const X11PixelCanvasColorTable & mapRef, Float percent)
void buildMapHSVPercent(Display::SpecialMap mapRef, Float percent)
void mapToColor(const Colormap * map, Array<uChar> & outArray, const Array<uChar> & inArray, Bool rangeCheck = True) const
void mapToColor(const Colormap * map, Array<uShort> & outArray, const Array<uShort> & inArray, Bool rangeCheck = True) const
void mapToColor(const Colormap * map, Array<uInt> & outArray, const Array<uInt> & inArray, Bool rangeCheck = True) const
void mapToColor(const Colormap * map, Array<uLong> & outArray, const Array<uLong> & inArray, Bool rangeCheck = True) const
uChar type may not have enough bits
to hold the pixel index on some high-end graphics systems
uShort type may not have enough bits
to hold the pixel index on some high-end graphics systems
void mapToColor(const Colormap * map, Array<uChar> & inOutArray, Bool rangeCheck = True) const
void mapToColor(const Colormap * map, Array<uShort> & inOutArray, Bool rangeCheck = True) const
void mapToColor(const Colormap * map, Array<uInt> & inOutArray, Bool rangeCheck = True) const
void mapToColor(const Colormap * map, Array<uLong> & inOutArray, Bool rangeCheck = True) const
friend ostream & operator << (ostream & os, const X11PixelCanvasColorTable & pcc)
virtual Bool staticSize()
Bool resize(uInt newSize)
Bool resize(uInt nReds, uInt nGreens, uInt nBlues)
Bool installRGBColors(const Vector<Float> & r, const Vector<Float> & g, const Vector<Float> & b, uInt offset = 0)
uInt RGB2Index(float r, float g, float b)
uInt HSV2Index(float h, float s, float v)
uInt nColors() const
virtual void nColors(uInt &n1, uInt &n2, uInt &n3) const
uInt depth() const
uInt nSpareColors() const
::XDisplay * display() const
Screen * screen() const
Return pointer to screen that is being used
Visual * visual() const
Return pointer to visual that is being used
XColormap xcmap() const
Return XID of X "virtual colormap" being used
Bool indexMode() const
Bool rgbMode() const
Bool hsvMode() const
Bool rigid() const
Display::ColorModel colorModel() const
Bool readOnly()const
Bool decomposedIndex()const
uInt QueryColorsAvailable(const Bool contig)const
virtual uInt QueryHWColorsAvailable(const Bool contig)const
Bool virtualToPhysical(const unsigned long vindex, unsigned long &pindex)const
Convert a virtual index to a physical pixel.
void storeVColor(const uInt vindex, const float r, const float g, const float b)
Store an RGB value at virtual index.
Bool isPow2(uInt n, uInt & log2n)
Return the log power 2 of n and return True if n is
a power of two. Otherwise return false.
uInt tripletIndex(float r, float g, float b)
void setupColorCube(uLong n1, uLong n2, uLong n3, uLong n1m, uLong n2m, uLong n3m)
void setupStandardMapping(const XStandardColormap * mapInfo)
(Multi-Channel)
void checkVisual(Visual *v=0)
virtual void storeColor(const uLong pindex, const float r, const float g, const float b)
Write an RGB value to hardware colormap at physical index.
(Called by storeVColor()).
void HSV2RGB(const uLong H, const uLong S, const uLong V, uLong &R, uLong &G, uLong &B)
Convert from integer HSV components to RGB pixel components.