This is xttools.c in view mode; [Download] [Up]
/* xttools - Color conversion routines and other low-level X support
Copyright (C) 1995 Free Software Foundation, Inc.
Written by: Adam Fedor <fedor@boulder.colorado.edu>
Date: Nov 1994
This file is part of the GNU Objective C User Interface Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <X11/Xatom.h>
#include "xttools.h"
#include "appkit/stdmacros.h"
#define XW_STD_COLORMAP_STR "XWStdColormap"
#define XW_GRAY_COLORMAP_STR "XWGrayColormap"
#define XW_RGB_COLORMAP_STR "XWRGBColormap"
/*
static Atom XW_GRAY_COLORMAP = 0;
static Atom XW_RGB_COLORMAP = 0;
*/
/* Right now we define the colormaps to be X default colormaps, since
maybe the window manager might actually have one of these */
static Atom XW_GRAY_COLORMAP = XA_RGB_GRAY_MAP;
static Atom XW_RGB_COLORMAP = XA_RGB_BEST_MAP;
static Atom XW_STD_COLORMAP = 0;
static void
xtInitAtoms(XWContext context)
{
if (XW_GRAY_COLORMAP == 0) {
XW_GRAY_COLORMAP = XInternAtom(context->display,
XW_GRAY_COLORMAP_STR, 0);
XW_RGB_COLORMAP = XInternAtom(context->display,
XW_RGB_COLORMAP_STR, 0);
}
}
/* Maintaining and using colormaps */
int
xtSetGrayColormap(XWContext context, XStandardColormap *stdmap,
unsigned long *cells, unsigned int colors)
{
int i;
XColor color;
for (i=0; i < colors; i++) {
/* Careful to scale color from 0 to 65536 */
color.red = color.green = color.blue = i * 256 * (256.0 / colors);
color.flags = DoRed | DoGreen | DoBlue;
if (cells)
color.pixel = cells[i];
else
color.pixel = i;
XStoreColor(context->display, stdmap->colormap, &color);
}
stdmap->red_max = colors - 1;
stdmap->red_mult = 1;
stdmap->green_max = 0;
stdmap->green_mult = 0;
stdmap->blue_max = 0;
stdmap->blue_mult = 0;
stdmap->base_pixel = 0;
if (cells)
stdmap->base_pixel = cells[0];
return 0;
}
/* Not implemented. FIXME */
int
xtSetRGBColormap(XWContext context, XStandardColormap *stdmap,
unsigned long *cells, unsigned int colors)
{
return 0;
}
/* Given a mask, find the minimum value where (number & mask) != 0 */
unsigned long
mask_min(unsigned long mask)
{
unsigned long number = 1;
if (mask == 0)
return 0;
while ((number & mask) == 0)
number = (number << 1L);
return number;
}
/* Gets and or creates a standard colormap for the visual type of the
display. On some displays, there is no need for a color map, so we
just store the characteristics of the display. On PseudoColor
displays we try to allocate as many colors as possible in a shared
colormap. If no colors are availible, use the default Black/White
pixel.
Use (or will use) the following hints:
NSStdColormap - (best or gray) will look for the specified standard
colomap and use it instead of creating a colormap.
NSMaxColors - Will allocate less than the specified number of colors.
NSPrivateColormap - Will allocate a private map if needed.
*/
XStandardColormap *
xtDefaultColormap(XWContext context)
{
int i, map_count;
unsigned int colors;
unsigned long *cells;
XStandardColormap *stdmap;
int NSMaxColors, NSPrivateColormap;
if (context->map)
return context->map;
/* Did the window manager already create a colormap for us? */
xtInitAtoms(context);
if (XW_STD_COLORMAP == 0) {
const char *NSStdColormap = getenv("COLORMAP");
if (NSStdColormap && NSStdColormap[0] == 'b')
XW_STD_COLORMAP = XW_RGB_COLORMAP;
else if (NSStdColormap && NSStdColormap[0] == 'g')
XW_STD_COLORMAP = XW_GRAY_COLORMAP;
else if (context->vinfo.class == DirectColor
|| context->vinfo.class == TrueColor)
XW_STD_COLORMAP = XW_RGB_COLORMAP;
else
XW_STD_COLORMAP = XW_GRAY_COLORMAP;
}
i = XGetRGBColormaps(context->display,
DefaultRootWindow(context->display),
&stdmap,
&map_count,
XW_STD_COLORMAP);
if (i) {
context->map = stdmap;
return stdmap;
}
/* Didn't find the standard map, create our own */
NX_MALLOC(stdmap, XStandardColormap, 1);
/* Note: in many cases we just set stdmap->colormap to 0, since this is
only needed to tell the Window which colormap to install, if colormap
== 0, then we're using the DefaultColormap, and there is no need to
install it.
*/
if (context->vinfo.class == DirectColor
|| context->vinfo.class == TrueColor) {
stdmap->colormap = 0;
stdmap->red_mult = mask_min(context->vinfo.red_mask);
stdmap->red_max = context->vinfo.red_mask / stdmap->red_mult;
stdmap->green_mult = mask_min(context->vinfo.green_mask);
stdmap->green_max = context->vinfo.green_mask / stdmap->green_mult;
stdmap->blue_mult = mask_min(context->vinfo.blue_mask);
stdmap->blue_max = context->vinfo.blue_mask / stdmap->blue_mult;
stdmap->base_pixel = 0;
context->map = stdmap;
return stdmap;
} else if (context->vinfo.class == StaticGray) {
stdmap->colormap = 0;
stdmap->red_max = context->vinfo.colormap_size - 1;
stdmap->red_mult = 1;
stdmap->green_max = 0;
stdmap->green_mult = 0;
stdmap->blue_max = 0;
stdmap->blue_mult = 0;
stdmap->base_pixel = 0;
context->map = stdmap;
return stdmap;
}
/* How do you figure out the colormap structure for StaticColor? Punt */
/* FIXME */
if (context->vinfo.class == StaticColor) {
fprintf(stderr, "Error (xttools): Can't determine colormap for StaticColor displays\n");
return NULL;
}
/* Only thing left is PseudoColor and GrayScale, which can be handled the
same */
if (context->vinfo.class != PseudoColor
&& context->vinfo.class != GrayScale) {
fprintf(stderr, "Error (xttools): Unknown visual class \n");
return NULL;
}
/* FIXME: Get these defaults */
NSMaxColors = context->vinfo.colormap_size - 8;
NSPrivateColormap = 0;
colors = NSMaxColors;
stdmap->colormap = DefaultColormap(context->display,
DefaultScreen(context->display));
i = 0;
while (i == 0 && colors >= 4) {
NX_MALLOC(cells, unsigned long, colors);
i = XAllocColorCells(context->display,
stdmap->colormap,
TRUE,
NULL,
0,
cells,
colors);
if (i == 0) {
NX_FREE(cells);
cells = NULL;
colors = colors - 4;
}
}
if (i == 0)
{
NX_FREE(cells);
cells = NULL;
if (NSPrivateColormap)
{
fprintf(stderr, "Warning (xttools): No colors available, creating private map\n");
colors = NSMaxColors;
stdmap->colormap = XCreateColormap(context->display,
DefaultRootWindow(context->display),
context->vinfo.visual,
AllocAll);
}
else
{
fprintf(stderr, "Warning (xttools): No colors available,
using standard BlackPixel/WhitePixel\n");
context->map = NULL;
return NULL;
}
}
else if (colors < 64)
fprintf(stderr,
"Warning: (xttools): Degraded colormap, only %d colors\n",
colors);
/* Now set up the cells */
if (XW_STD_COLORMAP == XW_RGB_COLORMAP)
xtSetRGBColormap(context, stdmap, cells, colors);
else
xtSetGrayColormap(context, stdmap, cells, colors);
/* Need to change the GC so that Background and Foreground
pixels are properly set. This is down in xmView when creating
the gstate.
*/
context->map = stdmap;
return stdmap;
}
/* Internal conversion of colors to pixels values */
u_long
xtGrayToPixel(XWContext context, float gray)
{
XStandardColormap *map;
u_long color;
map = context->map;
if (map == NULL) {
int screen = DefaultScreen(context->display);
return (gray < 0.5) ? BlackPixel(context->display, screen)
: WhitePixel(context->display, screen);
}
color = ((u_long)(0.5 + (gray * map->red_max)) * map->red_mult)
+ ((u_long)(0.5 + (gray*map->green_max)) * map->green_mult)
+ ((u_long)(0.5 + (gray*map->blue_max)) * map->blue_mult)
+ map->base_pixel;
return color;
}
u_long
xtRGBToPixel(XWContext context, float red, float green, float blue)
{
XStandardColormap *map;
u_long color;
map = context->map;
if (map == NULL) {
int gray = ((0.3*red) + (0.59*green) + (0.11*blue));
int screen = DefaultScreen(context->display);
return (gray < 0.5) ? BlackPixel(context->display, screen)
: WhitePixel(context->display, screen);
}
color = ((u_long)(0.5 + (red * map->red_max)) * map->red_mult)
+ ((u_long)(0.5 + (green * map->green_max)) * map->green_mult)
+ ((u_long)(0.5 + (blue * map->blue_max)) * map->blue_mult)
+ map->base_pixel;
return color;
}
/* Not implemented. FIXME */
u_long
xtHSBToPixel(XWContext context, float h, float s, float b)
{
return 0;
}
/* Not implemented. FIXME */
u_long
xtCMYKToPixel(XWContext context, float c, float m, float y, float k)
{
return 0;
}
u_long
xtColorToPixel(XWContext context, device_color_t color)
{
u_long pix;
switch(color.space)
{
case gray_colorspace:
pix = xtGrayToPixel(context, color.field[0]);
break;
case rgb_colorspace:
pix = xtRGBToPixel(context, color.field[0],
color.field[1], color.field[2]);
break;
case hsb_colorspace:
pix = xtHSBToPixel(context, color.field[0],
color.field[1], color.field[2]);
break;
case cmyk_colorspace:
pix = xtCMYKToPixel(context, color.field[0], color.field[1],
color.field[2], color.field[3]);
break;
default:
break;
}
return pix;
}
device_color_t
xtConvertToGray(device_color_t color)
{
device_color_t new;
new.space = gray_colorspace;
switch(color.space)
{
case gray_colorspace:
new = color;
break;
case hsb_colorspace:
case cmyk_colorspace:
color = xtConvertToRGB(color);
/* NO BREAK */
case rgb_colorspace:
new.field[0] =
((0.3*color.field[0]) + (0.59*color.field[1]) + (0.11*color.field[2]));
break;
default:
break;
}
return new;
}
device_color_t
xtConvertToRGB(device_color_t color)
{
device_color_t new;
new.space = rgb_colorspace;
switch(color.space)
{
case gray_colorspace:
new.field[0] = color.field[0];
new.field[1] = color.field[0];
new.field[2] = color.field[0];
break;
case rgb_colorspace:
new = color;
break;
case hsb_colorspace:
case cmyk_colorspace:
break;
default:
break;
}
return new;
}
device_color_t
xtConvertToHSB(device_color_t color)
{
device_color_t new;
new.space = hsb_colorspace;
switch(color.space)
{
case gray_colorspace:
break;
case rgb_colorspace:
break;
case hsb_colorspace:
new = color;
break;
case cmyk_colorspace:
break;
default:
break;
}
return new;
}
device_color_t
xtConvertToCMYK(device_color_t color)
{
device_color_t new;
new.space = gray_colorspace;
switch(color.space)
{
case gray_colorspace:
break;
case rgb_colorspace:
break;
case hsb_colorspace:
break;
case cmyk_colorspace:
new = color;
break;
default:
break;
}
return new;
}
/* Internal conversion of image data to pixel values
These routines are here for consistency, but are really only used by
xtNXBitmapImageRep. Look at that file for more information on how these
routines are used.
*/
u_char *
xtMapGrays(XWContext context, u_char **src, int colorspace, int bps, int spp,
int ncolors, int planar, u_char *dest)
{
int i;
XStandardColormap *map;
u_int max;
u_long color;
u_char *gray;
map = context->map;
gray = src[0]; /* Ignore alpha */
if (map == NULL)
return 0;
max = (1 << bps);
for (i=0; i < ncolors; i++) {
/* Just skip the Alpha if there is one */
if (planar)
color = (gray[i*bps/8] << ((i * bps) % 8)) % max;
else
color = (gray[i*spp*bps/8] << ((i * bps) % 8)) % max;
color = ((color * map->red_max / max) * map->red_mult
+ (color * map->green_max / max) * map->green_mult
+ (color * map->blue_max / max) * map->blue_mult
+ map->base_pixel) & 0xFFFFFFFF;
/* FIXME: Need to pack bits for displays with depth < 8 */
dest[i] = color;
}
return dest;
}
/* FIXME: Only handles RGB images (no CMYK) */
u_char *
xtMapColors(XWContext context, u_char **src, int colorspace, int bps, int spp,
int ncolors, int planar, u_char *dest)
{
int i;
XStandardColormap *map;
u_int max;
u_long color;
u_char *red, *green, *blue;
u_char r, g, b;
if (spp <= 2)
return xtMapGrays(context, src, colorspace, bps,
spp, ncolors, planar, dest);
map = context->map;
if (map == NULL)
return 0;
max = (1 << bps);
red = src[0];
if (planar) {
green = src[1];
blue = src[2];
}
for (i=0; i < ncolors; i++) {
u_int shift;
shift = i * bps / 8;
if (planar) {
r = (red[shift] << ((i * bps) % 8)) % max;
g = (green[shift] << ((i * bps) % 8)) % max;
b = (blue[shift] << ((i * bps) % 8)) % max;
/* Translate values for gray-scale display */
if ( map->green_max == 0 && map->blue_max == 0)
r = (u_long)((0.3*r) + (0.59*g) + (0.11*b));
color = ((r * map->red_max / max) * map->red_mult
+ (g * map->green_max / max)*map->green_mult
+ (b * map->blue_max / max)*map->blue_mult
+ map->base_pixel) & 0xFFFFFFFF;
} else {
r = (red[i*spp*bps/8] << ((i * bps) % 8)) % max;
g = (red[(i*spp+1)*bps/8] << (((i+1) * bps) % 8)) % max;
b = (red[(i*spp+2)*bps/8] << (((i+2) * bps) % 8)) % max;
/* Translate values for gray-scale display */
if ( map->green_max == 0 && map->blue_max == 0)
r = (u_long)((0.3*r) + (0.59*g) + (0.11*b));
color = ((r * map->red_max / max) * map->red_mult
+ (g * map->green_max / max) * map->green_mult
+ (b * map->blue_max / max) * map->blue_mult
+ map->base_pixel) & 0xFFFFFFFF;
}
/* FIXME: Need to pack bits for displays with depth < 8 */
dest[i] = color;
}
return dest;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.