/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "MPL"); you may not use this file except in
* compliance with the MPL. You may obtain a copy of the MPL at
* http://www.mozilla.org/MPL/
*
* Software distributed under the MPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
* for the specific language governing rights and limitations under the
* MPL.
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Library General Public License (the "LGPL"), in
* which case the provisions of the LGPL are applicable instead of
* those above. If you wish to allow use of your version of this file
* only under the terms of the LGPL and not to allow others to use
* your version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the LGPL. If you do not delete the
* provisions above, a recipient may use your version of this file
* under either the MPL or the LGPL.
*/
/*
* This code is derived from GdkRgb.
* For more information on GdkRgb, see http://www.levien.com/gdkrgb/
* Raph Levien <raph@acm.org>
*/
/* Ported by Christopher Blizzard to Xlib. With permission from the
* original authors and the copyright holders of this file, the
* contents of this file are also redistributable under the terms of
* the Mozilla Public license. For information about the Mozilla
* Public License, please see the license information at
* http://www.mozilla.org/MPL/ */
/* This code is copyright the following authors:
* Raph Levien <raph@acm.org>
* Manish Singh <manish@gtk.org>
* Tim Janik <timj@gtk.org>
* Peter Mattis <petm@xcf.berkeley.edu>
* Spencer Kimball <spencer@xcf.berkeley.edu>
* Josh MacDonald <jmacd@xcf.berkeley.edu>
* Christopher Blizzard <blizzard@redhat.com>
* Owen Taylor <otaylor@redhat.com>
* Shawn T. Amundson <amundson@gtk.org>
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_CONFIG_H
# include "scconfig.h"
#endif
#define ENABLE_GRAYSCALE
/* include this before so that we can get endian definitions if
they are there... */
#include "gdk-pixbuf-xlibrgb.h"
#include "gdk-pixbuf-xlib-private.h"
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
typedef enum {
LSB_FIRST
,
MSB_FIRST
} ByteOrder
;
typedef struct _XlibRgbInfo XlibRgbInfo
;
typedef void (*XlibRgbConvFunc
) (XImage
*image
,
int ax
, int ay
,
int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
,
XlibRgbCmap
*cmap
);
/* Some of these fields should go, as they're not being used at all.
Globals should generally migrate into here - it's very likely that
we'll want to run more than one GdkRgbInfo context at the same time
(i.e. some but not all windows have privately installed
colormaps). */
struct _XlibRgbInfo
{
Display
*display
;
Screen
*screen
;
int screen_num
;
XVisualInfo
*x_visual_info
;
Colormap cmap
;
XColor
*cmap_colors
;
Visual
*default_visualid
;
Colormap default_colormap
;
unsigned long *color_pixels
;
unsigned long *gray_pixels
;
unsigned long *reserved_pixels
;
unsigned long red_shift
;
unsigned long red_prec
;
unsigned long blue_shift
;
unsigned long blue_prec
;
unsigned long green_shift
;
unsigned long green_prec
;
unsigned int nred_shades
;
unsigned int ngreen_shades
;
unsigned int nblue_shades
;
unsigned int ngray_shades
;
unsigned int nreserved
;
unsigned int bpp
;
unsigned int cmap_alloced
;
double gamma_val
;
/* Generally, the stage buffer is used to convert 32bit RGB, gray,
and indexed images into 24 bit packed RGB. */
unsigned char *stage_buf
;
XlibRgbCmap
*gray_cmap
;
Bool dith_default
;
Bool bitmap
; /* set true if in 1 bit per pixel mode */
GC own_gc
;
/* Convert functions */
XlibRgbConvFunc conv
;
XlibRgbConvFunc conv_d
;
XlibRgbConvFunc conv_32
;
XlibRgbConvFunc conv_32_d
;
XlibRgbConvFunc conv_gray
;
XlibRgbConvFunc conv_gray_d
;
XlibRgbConvFunc conv_indexed
;
XlibRgbConvFunc conv_indexed_d
;
};
static Bool xlib_rgb_install_cmap
= FALSE
;
static int xlib_rgb_min_colors
= 5 * 5 * 5;
static Bool xlib_rgb_verbose
= FALSE
;
#define IMAGE_WIDTH 256
#define STAGE_ROWSTRIDE (IMAGE_WIDTH * 3)
#define IMAGE_HEIGHT 64
#define N_IMAGES 6
static XlibRgbInfo
*image_info
= NULL
;
static XImage
*static_image
[N_IMAGES
];
static int static_image_idx
;
static unsigned char *colorcube
;
static unsigned char *colorcube_d
;
static unsigned long
xlib_get_prec_from_mask
(unsigned long val
)
{
unsigned long retval
= 0;
unsigned int cur_bit
= 0;
/* walk through the number, incrementing the value if
the bit in question is set. */
while (cur_bit
< (sizeof(unsigned long) * 8)) {
if ((val
>> cur_bit
) & 0x1) {
retval
++;
}
cur_bit
++;
}
return retval
;
}
static unsigned long
xlib_get_shift_from_mask
(unsigned long val
)
{
unsigned long cur_bit
= 0;
/* walk through the number, looking for the first 1 */
while (cur_bit
< (sizeof(unsigned long) * 8)) {
if ((val
>> cur_bit
) & 0x1) {
return cur_bit
;
}
cur_bit
++;
}
return cur_bit
;
}
static int
xlib_rgb_cmap_fail
(const char *msg
, Colormap cmap
, unsigned long *pixels
)
{
unsigned long free_pixels
[256];
int n_free
;
int i
;
#ifdef VERBOSE
printf ("%s", msg
);
#endif
n_free
= 0;
for (i
= 0; i
< 256; i
++)
if (pixels
[i
] < 256)
free_pixels
[n_free
++] = pixels
[i
];
if (n_free
)
XFreeColors
(image_info
->display
,
cmap
,
free_pixels
,
n_free
,
0);
return 0;
}
static void
xlib_rgb_make_colorcube
(unsigned long *pixels
, int nr
, int ng
, int nb
)
{
unsigned char rt
[16], gt
[16], bt
[16];
int i
;
colorcube
= (unsigned char *) malloc
(sizeof(unsigned char) * 4096);
memset
(colorcube
, 0, (sizeof(unsigned char) * 4096));
for (i
= 0; i
< 16; i
++)
{
rt
[i
] = ng
* nb
* ((i
* 17 * (nr
- 1) + 128) >> 8);
gt
[i
] = nb
* ((i
* 17 * (ng
- 1) + 128) >> 8);
bt
[i
] = ((i
* 17 * (nb
- 1) + 128) >> 8);
}
for (i
= 0; i
< 4096; i
++)
{
colorcube
[i
] = pixels
[rt
[i
>> 8] + gt
[(i
>> 4) & 0x0f] + bt
[i
& 0x0f]];
#ifdef VERBOSE
printf ("%03x %02x %x %x %x\n", i
, colorcube
[i
], rt
[i
>> 8], gt
[(i
>> 4) & 0x0f], bt
[i
& 0x0f]);
#endif
}
}
/* this is the colorcube suitable for dithering */
static void
xlib_rgb_make_colorcube_d
(unsigned long *pixels
, int nr
, int ng
, int nb
)
{
int r
, g
, b
;
int i
;
colorcube_d
= (unsigned char *) malloc
(sizeof(unsigned char) * 512);
memset
(colorcube_d
, 0, (sizeof(unsigned char) * 512));
for (i
= 0; i
< 512; i
++)
{
r
= MIN
(nr
- 1, i
>> 6);
g
= MIN
(ng
- 1, (i
>> 3) & 7);
b
= MIN
(nb
- 1, i
& 7);
colorcube_d
[i
] = pixels
[(r
* ng
+ g
) * nb
+ b
];
}
}
/* Try installing a color cube of the specified size.
Make the colorcube and return TRUE on success */
static int
xlib_rgb_try_colormap
(int nr
, int ng
, int nb
)
{
int r
, g
, b
;
int ri
, gi
, bi
;
int r0
, g0
, b0
;
Colormap cmap
;
XVisualInfo
*visual
;
XColor
*colors
= NULL
;
XColor color
;
unsigned long pixels
[256];
unsigned long junk
[256];
int i
;
int d2
;
unsigned int colors_needed
;
int idx
;
int best
[256];
if (nr
* ng
* nb
< xlib_rgb_min_colors
)
return FALSE
;
if (image_info
->cmap_alloced
) {
cmap
= image_info
->cmap
;
visual
= image_info
->x_visual_info
;
}
else {
cmap
= image_info
->default_colormap
;
visual
= image_info
->x_visual_info
;
}
colors_needed
= nr
* ng
* nb
;
for (i
= 0; i
< 256; i
++)
{
best
[i
] = 192;
pixels
[i
] = 256;
}
#ifndef GAMMA
if (!xlib_rgb_install_cmap
) {
/* go out and get the colors for this colormap. */
colors
= (XColor
*) malloc
(sizeof(XColor
) * visual
->colormap_size
);
for (i
=0; i
< visual
->colormap_size
; i
++){
colors
[i
].
pixel = i
;
}
XQueryColors
(image_info
->display
,
cmap
,
colors
, visual
->colormap_size
);
/* find color cube colors that are already present */
for (i
= 0; i
< MIN
(256, visual
->colormap_size
); i
++)
{
r
= colors
[i
].
red >> 8;
g
= colors
[i
].
green >> 8;
b
= colors
[i
].
blue >> 8;
ri
= (r
* (nr
- 1) + 128) >> 8;
gi
= (g
* (ng
- 1) + 128) >> 8;
bi
= (b
* (nb
- 1) + 128) >> 8;
r0
= ri
* 255 / (nr
- 1);
g0
= gi
* 255 / (ng
- 1);
b0
= bi
* 255 / (nb
- 1);
idx
= ((ri
* nr
) + gi
) * nb
+ bi
;
d2
= (r
- r0
) * (r
- r0
) + (g
- g0
) * (g
- g0
) + (b
- b0
) * (b
- b0
);
if (d2
< best
[idx
]) {
if (pixels
[idx
] < 256)
XFreeColors
(image_info
->display
,
cmap
,
pixels
+ idx
,
1, 0);
else
colors_needed
--;
color.
pixel = colors
[i
].
pixel;
color.
red = colors
[i
].
red;
color.
green = colors
[i
].
green;
color.
blue = colors
[i
].
blue;
color.
flags = 0;
if (!XAllocColor
(image_info
->display
, cmap
, &color
))
return xlib_rgb_cmap_fail
("error allocating system color\n",
cmap
, pixels
);
pixels
[idx
] = color.
pixel; /* which is almost certainly i */
best
[idx
] = d2
;
}
}
}
#endif
if (colors_needed
)
{
if (!XAllocColorCells
(image_info
->display
, cmap
, 0, NULL
, 0, junk
, colors_needed
))
{
char tmp_str
[80];
sprintf
(tmp_str
,
"%d %d %d colormap failed (in XAllocColorCells)\n",
nr
, ng
, nb
);
return xlib_rgb_cmap_fail
(tmp_str
, cmap
, pixels
);
}
XFreeColors
(image_info
->display
, cmap
, junk
, (int)colors_needed
, 0);
}
for (r
= 0, i
= 0; r
< nr
; r
++)
for (g
= 0; g
< ng
; g
++)
for (b
= 0; b
< nb
; b
++, i
++)
{
if (pixels
[i
] == 256)
{
color.
red = r
* 65535 / (nr
- 1);
color.
green = g
* 65535 / (ng
- 1);
color.
blue = b
* 65535 / (nb
- 1);
#ifdef GAMMA
color.
red = 65535 * pow
(color.
red / 65535.0, 0.5);
color.
green = 65535 * pow
(color.
green / 65535.0, 0.5);
color.
blue = 65535 * pow
(color.
blue / 65535.0, 0.5);
#endif
/* This should be a raw XAllocColor call */
if (!XAllocColor
(image_info
->display
, cmap
, &color
))
{
char tmp_str
[80];
sprintf
(tmp_str
, "%d %d %d colormap failed\n",
nr
, ng
, nb
);
return xlib_rgb_cmap_fail
(tmp_str
,
cmap
, pixels
);
}
pixels
[i
] = color.
pixel;
}
#ifdef VERBOSE
printf ("%d: %lx\n", i
, pixels
[i
]);
#endif
}
image_info
->nred_shades
= nr
;
image_info
->ngreen_shades
= ng
;
image_info
->nblue_shades
= nb
;
xlib_rgb_make_colorcube
(pixels
, nr
, ng
, nb
);
xlib_rgb_make_colorcube_d
(pixels
, nr
, ng
, nb
);
if (colors
)
free
(colors
);
return TRUE
;
}
/* Return TRUE on success. */
static Bool
xlib_rgb_do_colormaps
(void)
{
static const int sizes
[][3] = {
/* { 6, 7, 6 }, */
{ 6, 6, 6 },
{ 6, 6, 5 },
{ 6, 6, 4 },
{ 5, 5, 5 },
{ 5, 5, 4 },
{ 4, 4, 4 },
{ 4, 4, 3 },
{ 3, 3, 3 },
{ 2, 2, 2 }
};
static const int n_sizes
= sizeof(sizes
) / (3 * sizeof(int));
int i
;
for (i
= 0; i
< n_sizes
; i
++)
if (xlib_rgb_try_colormap
(sizes
[i
][0], sizes
[i
][1], sizes
[i
][2]))
return TRUE
;
return FALSE
;
}
/* Make a 2 x 2 x 2 colorcube */
static void
xlib_rgb_colorcube_222
(void)
{
int i
;
XColor color
;
Colormap cmap
;
if (image_info
->cmap_alloced
)
cmap
= image_info
->cmap
;
else
cmap
= image_info
->default_colormap
;
colorcube_d
= (unsigned char *) malloc
(sizeof(unsigned char) * 512);
for (i
= 0; i
< 8; i
++)
{
color.
red = ((i
& 4) >> 2) * 65535;
color.
green = ((i
& 2) >> 1) * 65535;
color.
blue = (i
& 1) * 65535;
XAllocColor
(image_info
->display
, cmap
, &color
);
colorcube_d
[((i
& 4) << 4) | ((i
& 2) << 2) | (i
& 1)] = color.
pixel;
}
}
/**
* xlib_rgb_set_verbose:
* @verbose: %True to be verbose
*
* Enables/disables debug spew.
**/
void
xlib_rgb_set_verbose
(Bool verbose
)
{
xlib_rgb_verbose
= verbose
;
}
/**
* xlib_rgb_set_install:
* @install: %True to install a colormap
*
* Sets whether we install an RGB colormap.
**/
void
xlib_rgb_set_install
(Bool install
)
{
xlib_rgb_install_cmap
= install
;
}
/**
* xlib_rgb_set_min_colors:
* @min_colors: minimum colors to use
*
* Sets the minimum number of colors in the color cube.
**/
void
xlib_rgb_set_min_colors
(int min_colors
)
{
xlib_rgb_min_colors
= min_colors
;
}
/* Return a "score" based on the following criteria (in hex):
x000 is the quality - 1 is 1bpp, 2 is 4bpp,
4 is 8bpp,
7 is 15bpp truecolor, 8 is 16bpp truecolor,
9 is 24bpp truecolor.
0x00 is the speed - 1 is the normal case,
2 means faster than normal
00x0 gets a point for being the system visual
000x gets a point for being pseudocolor
A caveat: in the 8bpp modes, being the system visual seems to be
quite important. Thus, all of the 8bpp modes should be ranked at
the same speed.
*/
static unsigned int
xlib_rgb_score_visual
(XVisualInfo
*visual
)
{
unsigned int quality
, speed
, pseudo
, sys
;
static const char* visual_names
[] =
{
"static gray",
"grayscale",
"static color",
"pseudo color",
"true color",
"direct color",
};
quality
= 0;
speed
= 1;
sys
= 0;
if (visual
->class
== TrueColor
||
visual
->class
== DirectColor
)
{
if (visual
->depth
== 24)
{
quality
= 9;
/* Should test for MSB visual here, and set speed if so. */
}
else if (visual
->depth
== 16)
quality
= 8;
else if (visual
->depth
== 15)
quality
= 7;
else if (visual
->depth
== 8)
quality
= 4;
}
else if (visual
->class
== PseudoColor
||
visual
->class
== StaticColor
)
{
if (visual
->depth
== 8)
quality
= 4;
else if (visual
->depth
== 4)
quality
= 2;
else if (visual
->depth
== 1)
quality
= 1;
}
else if (visual
->class
== StaticGray
#ifdef ENABLE_GRAYSCALE
|| visual
->class
== GrayScale
#endif
)
{
if (visual
->depth
== 8)
quality
= 4;
else if (visual
->depth
== 4)
quality
= 2;
else if (visual
->depth
== 1)
quality
= 1;
}
if (quality
== 0)
return 0;
sys
= (visual
->visualid
== image_info
->default_visualid
->visualid
);
pseudo
= (visual
->class
== PseudoColor
|| visual
->class
== TrueColor
);
if (xlib_rgb_verbose
)
printf ("Visual 0x%x, type = %s, depth = %d, %ld:%ld:%ld%s; score=%x\n",
(int)visual
->visualid
,
visual_names
[visual
->class
],
visual
->depth
,
visual
->red_mask
,
visual
->green_mask
,
visual
->blue_mask
,
sys
? " (system)" : "",
(quality
<< 12) | (speed
<< 8) | (sys
<< 4) | pseudo
);
return (quality
<< 12) | (speed
<< 8) | (sys
<< 4) | pseudo
;
}
static void
xlib_rgb_choose_visual
(void)
{
XVisualInfo
*visuals
;
XVisualInfo
*visual
;
XVisualInfo
*best_visual
;
XVisualInfo
*final_visual
;
XVisualInfo template
;
int num_visuals
;
unsigned int score
, best_score
;
int cur_visual
= 1;
int i
;
template.
screen = image_info
->screen_num
;
visuals
= XGetVisualInfo
(image_info
->display
, VisualScreenMask
,
&template
, &num_visuals
);
best_visual
= visuals
;
best_score
= xlib_rgb_score_visual
(best_visual
);
for (i
= cur_visual
; i
< num_visuals
; i
++)
{
visual
= &visuals
[i
];
score
= xlib_rgb_score_visual
(visual
);
if (score
> best_score
)
{
best_score
= score
;
best_visual
= visual
;
}
}
/* make a copy of the visual so that we can free
the allocated visual list above. */
final_visual
= (XVisualInfo
*) malloc
(sizeof(XVisualInfo
));
memcpy
(final_visual
, best_visual
, sizeof(XVisualInfo
));
image_info
->x_visual_info
= final_visual
;
XFree
(visuals
);
/* set up the shift and the precision for the red, green and blue.
this only applies to cool visuals like true color and direct color. */
if (image_info
->x_visual_info
->class
== TrueColor
||
image_info
->x_visual_info
->class
== DirectColor
) {
image_info
->red_shift
= xlib_get_shift_from_mask
(image_info
->x_visual_info
->red_mask
);
image_info
->red_prec
= xlib_get_prec_from_mask
(image_info
->x_visual_info
->red_mask
);
image_info
->green_shift
= xlib_get_shift_from_mask
(image_info
->x_visual_info
->green_mask
);
image_info
->green_prec
= xlib_get_prec_from_mask
(image_info
->x_visual_info
->green_mask
);
image_info
->blue_shift
= xlib_get_shift_from_mask
(image_info
->x_visual_info
->blue_mask
);
image_info
->blue_prec
= xlib_get_prec_from_mask
(image_info
->x_visual_info
->blue_mask
);
}
}
static void
xlib_rgb_choose_visual_for_xprint
(int aDepth
)
{
XVisualInfo
*visuals
;
XVisualInfo
*visual
;
XVisualInfo
*best_visual
;
XVisualInfo
*final_visual
;
XVisualInfo template
;
int num_visuals
;
int cur_visual
= 1;
int i
;
XWindowAttributes win_att
;
Status ret_stat
;
Visual
*root_visual
;
ret_stat
= XGetWindowAttributes
(image_info
->display
,
RootWindow
(image_info
->display
, image_info
->screen_num
),
&win_att
);
root_visual
= win_att.
visual;
template.
screen = image_info
->screen_num
;
visuals
= XGetVisualInfo
(image_info
->display
, VisualScreenMask
,
&template
, &num_visuals
);
best_visual
= visuals
;
if (best_visual
->visual
!= root_visual
) {
for (i
= cur_visual
; i
< num_visuals
; i
++) {
visual
= &visuals
[i
];
if (visual
->visual
== root_visual
) {
best_visual
= visual
;
break;
}
}
}
/* make a copy of the visual so that we can free
the allocated visual list above. */
final_visual
= (XVisualInfo
*) malloc
(sizeof(XVisualInfo
));
memcpy
(final_visual
, best_visual
, sizeof(XVisualInfo
));
image_info
->x_visual_info
= final_visual
;
XFree
(visuals
);
/* set up the shift and the precision for the red, green and blue.
this only applies to cool visuals like true color and direct color. */
if (image_info
->x_visual_info
->class
== TrueColor
||
image_info
->x_visual_info
->class
== DirectColor
) {
image_info
->red_shift
= xlib_get_shift_from_mask
(image_info
->x_visual_info
->red_mask
);
image_info
->red_prec
= xlib_get_prec_from_mask
(image_info
->x_visual_info
->red_mask
);
image_info
->green_shift
= xlib_get_shift_from_mask
(image_info
->x_visual_info
->green_mask
);
image_info
->green_prec
= xlib_get_prec_from_mask
(image_info
->x_visual_info
->green_mask
);
image_info
->blue_shift
= xlib_get_shift_from_mask
(image_info
->x_visual_info
->blue_mask
);
image_info
->blue_prec
= xlib_get_prec_from_mask
(image_info
->x_visual_info
->blue_mask
);
}
}
static void xlib_rgb_select_conv
(XImage
*image
, ByteOrder byte_order
);
static void
xlib_rgb_set_gray_cmap
(Colormap cmap
)
{
int i
;
XColor color
;
int status
;
unsigned long pixels
[256];
int r
, g
, b
, gray
;
for (i
= 0; i
< 256; i
++)
{
color.
pixel = i
;
color.
red = i
* 257;
color.
green = i
* 257;
color.
blue = i
* 257;
status
= XAllocColor
(image_info
->display
, cmap
, &color
);
pixels
[i
] = color.
pixel;
#ifdef VERBOSE
printf ("allocating pixel %d, %x %x %x, result %d\n",
color.
pixel, color.
red, color.
green, color.
blue, status
);
#endif
}
/* Now, we make fake colorcubes - we ultimately just use the pseudocolor
methods. */
colorcube
= (unsigned char *) malloc
(sizeof(unsigned char) * 4096);
for (i
= 0; i
< 4096; i
++)
{
r
= (i
>> 4) & 0xf0;
r
= r
| r
>> 4;
g
= i
& 0xf0;
g
= g
| g
>> 4;
b
= (i
<< 4 & 0xf0);
b
= b
| b
>> 4;
gray
= (g
+ ((r
+ b
) >> 1)) >> 1;
colorcube
[i
] = pixels
[gray
];
}
}
/**
* xlib_rgb_init:
* @display: X Display to use.
* @screen: Screen to use.
*
* Initializes the XlibRGB machinery with the default depth. If you use this
* function XlibRGB will automatically pick the best visual available on your
* display. This function or xlib_rgb_init_with_depth() must be called before
* using any of the other functions in XlibRGB.
**/
void
xlib_rgb_init
(Display
*display
, Screen
*screen
)
{
int prefDepth
= -1; /* let the function do the visual scoring */
xlib_rgb_init_with_depth
(display
, screen
, prefDepth
);
}
/**
* xlib_rgb_init_with_depth:
* @display: X display to use.
* @screen: Screen to use.
* @prefDepth: Visual depth to use for color substitution tables. This must
* be one of the supported visual depths in the specified @display.
*
* Initializes the XlibRGB machinery with a particular depth you specify,
* instead of automatically picking the best depth in the display. This
* function or xlib_rgb_init() must be called before using any of the other
* functions in XlibRGB.
**/
void
xlib_rgb_init_with_depth
(Display
*display
, Screen
*screen
, int prefDepth
)
{
int i
;
static const int byte_order
[1] = { 1 };
static int initialized
= 0;
if (initialized
)
{
return;
}
initialized
= 1;
#ifdef WORDS_BIGENDIAN
if (((char *)byte_order
)[0] == 1) {
printf ("xlib_rgb_init: compiled for big endian, but this is a little endian machine.\n\n");
exit
(1);
}
#else
if (((char *)byte_order
)[0] != 1) {
printf ("xlib_rgb_init: compiled for little endian, but this is a big endian machine.\n\n");
exit
(1);
}
#endif
if (image_info
== NULL
)
{
image_info
= (XlibRgbInfo
*) malloc
(sizeof(XlibRgbInfo
));
memset
(image_info
, 0, sizeof(XlibRgbInfo
));
image_info
->display
= display
;
image_info
->screen
= screen
;
image_info
->screen_num
= XScreenNumberOfScreen
(screen
);
image_info
->x_visual_info
= NULL
;
image_info
->cmap
= 0;
image_info
->default_visualid
= DefaultVisual
(display
, image_info
->screen_num
);
image_info
->default_colormap
= DefaultColormap
(display
, image_info
->screen_num
);
image_info
->color_pixels
= NULL
;
image_info
->gray_pixels
= NULL
;
image_info
->reserved_pixels
= NULL
;
image_info
->nred_shades
= 6;
image_info
->ngreen_shades
= 6;
image_info
->nblue_shades
= 4;
image_info
->ngray_shades
= 24;
image_info
->nreserved
= 0;
image_info
->bpp
= 0;
image_info
->cmap_alloced
= FALSE
;
image_info
->gamma_val
= 1.0;
image_info
->stage_buf
= NULL
;
image_info
->own_gc
= 0;
image_info
->red_shift
= 0;
image_info
->red_prec
= 0;
image_info
->green_shift
= 0;
image_info
->green_prec
= 0;
image_info
->blue_shift
= 0;
image_info
->blue_prec
= 0;
if (prefDepth
!= -1)
xlib_rgb_choose_visual_for_xprint
(prefDepth
);
else
xlib_rgb_choose_visual
();
if ((image_info
->x_visual_info
->class
== PseudoColor
||
image_info
->x_visual_info
->class
== StaticColor
) &&
image_info
->x_visual_info
->depth
< 8 &&
image_info
->x_visual_info
->depth
>= 3)
{
image_info
->cmap
= image_info
->default_colormap
;
xlib_rgb_colorcube_222
();
}
else if (image_info
->x_visual_info
->class
== PseudoColor
)
{
if (xlib_rgb_install_cmap
||
image_info
->x_visual_info
->visualid
!= image_info
->default_visualid
->visualid
)
{
image_info
->cmap
= XCreateColormap
(image_info
->display
,
RootWindow
(image_info
->display
, image_info
->screen_num
),
image_info
->x_visual_info
->visual
,
AllocNone
);
image_info
->cmap_alloced
= TRUE
;
}
if (!xlib_rgb_do_colormaps
())
{
image_info
->cmap
= XCreateColormap
(image_info
->display
,
RootWindow
(image_info
->display
, image_info
->screen_num
),
image_info
->x_visual_info
->visual
,
AllocNone
);
image_info
->cmap_alloced
= TRUE
;
xlib_rgb_do_colormaps
();
}
if (xlib_rgb_verbose
)
printf ("color cube: %d x %d x %d\n",
image_info
->nred_shades
,
image_info
->ngreen_shades
,
image_info
->nblue_shades
);
if (!image_info
->cmap_alloced
)
image_info
->cmap
= image_info
->default_colormap
;
}
#ifdef ENABLE_GRAYSCALE
else if (image_info
->x_visual_info
->class
== GrayScale
)
{
image_info
->cmap
= XCreateColormap
(image_info
->display
,
RootWindow
(image_info
->display
, image_info
->screen_num
),
image_info
->x_visual_info
->visual
,
AllocNone
);
xlib_rgb_set_gray_cmap
(image_info
->cmap
);
image_info
->cmap_alloced
= TRUE
;
}
#endif
else
{
/* Always install colormap in direct color. */
if (image_info
->x_visual_info
->class
!= DirectColor
&&
image_info
->x_visual_info
->visualid
== image_info
->default_visualid
->visualid
)
image_info
->cmap
= image_info
->default_colormap
;
else
{
image_info
->cmap
= XCreateColormap
(image_info
->display
,
RootWindow
(image_info
->display
, image_info
->screen_num
),
image_info
->x_visual_info
->visual
,
AllocNone
);
image_info
->cmap_alloced
= TRUE
;
}
}
image_info
->bitmap
= (image_info
->x_visual_info
->depth
== 1);
for (i
= 0; i
< N_IMAGES
; i
++) {
if (image_info
->bitmap
) {
/* Use malloc() instead of g_malloc since X will free() this mem */
static_image
[i
] = XCreateImage
(image_info
->display
,
image_info
->x_visual_info
->visual
,
1,
XYBitmap
,
0, 0, IMAGE_WIDTH
, IMAGE_HEIGHT
,
8,
0);
static_image
[i
]->data
= (char *) malloc
(IMAGE_WIDTH
* IMAGE_HEIGHT
>> 3);
static_image
[i
]->bitmap_bit_order
= MSBFirst
;
static_image
[i
]->byte_order
= MSBFirst
;
}
else {
static_image
[i
] = XCreateImage
(image_info
->display
,
image_info
->x_visual_info
->visual
,
(unsigned int)image_info
->x_visual_info
->depth
,
ZPixmap
,
0, 0,
IMAGE_WIDTH
,
IMAGE_HEIGHT
,
32, 0);
/* remove this when we are using shared memory.. */
static_image
[i
]->data
= (char *) malloc
((size_t
)IMAGE_WIDTH
* IMAGE_HEIGHT
* image_info
->x_visual_info
->depth
);
static_image
[i
]->bitmap_bit_order
= MSBFirst
;
static_image
[i
]->byte_order
= MSBFirst
;
}
}
/* ok, so apparently, image_info->bpp is actually
BYTES per pixel. What fun! */
switch (static_image
[0]->bits_per_pixel
) {
case 1:
case 8:
image_info
->bpp
= 1;
break;
case 16:
image_info
->bpp
= 2;
break;
case 24:
image_info
->bpp
= 3;
break;
case 32:
image_info
->bpp
= 4;
break;
}
xlib_rgb_select_conv
(static_image
[0], MSB_FIRST
);
}
}
/**
* xlib_rgb_xpixel_from_rgb:
* @rgb: 32-bit representation of an RGB value, specified as 0x00RRGGBB.
*
* Converts an RGB triplet into the closest color that XlibRGB visual can
* handle.
*
* Return value: X pixel value that corresponds to the closest color in the
* XlibRGB visual and colormap.
**/
unsigned long
xlib_rgb_xpixel_from_rgb
(unsigned int rgb
)
{
unsigned long pixel
= 0;
if (image_info
->bitmap
)
{
return ((rgb
& 0xff0000) >> 16) +
((rgb
& 0xff00) >> 7) +
(rgb
& 0xff) > 510;
}
else if (image_info
->x_visual_info
->class
== PseudoColor
)
pixel
= colorcube
[((rgb
& 0xf00000) >> 12) |
((rgb
& 0xf000) >> 8) |
((rgb
& 0xf0) >> 4)];
else if (image_info
->x_visual_info
->depth
< 8 &&
image_info
->x_visual_info
->class
== StaticColor
)
{
pixel
= colorcube_d
[((rgb
& 0x800000) >> 17) |
((rgb
& 0x8000) >> 12) |
((rgb
& 0x80) >> 7)];
}
else if (image_info
->x_visual_info
->class
== TrueColor
||
image_info
->x_visual_info
->class
== DirectColor
)
{
#ifdef VERBOSE
printf ("shift, prec: r %d %d g %d %d b %d %d\n",
image_info
->red_shift
,
image_info
->red_prec
,
image_info
->green_shift
,
image_info
->green_prec
,
image_info
->blue_shift
,
image_info
->blue_prec
);
#endif
pixel
= (((((rgb
& 0xff0000) >> 16) >>
(8 - image_info
->red_prec
)) <<
image_info
->red_shift
) +
((((rgb
& 0xff00) >> 8) >>
(8 - image_info
->green_prec
)) <<
image_info
->green_shift
) +
(((rgb
& 0xff) >>
(8 - image_info
->blue_prec
)) <<
image_info
->blue_shift
));
}
else if (image_info
->x_visual_info
->class
== StaticGray
||
image_info
->x_visual_info
->class
== GrayScale
)
{
int gray
= ((rgb
& 0xff0000) >> 16) +
((rgb
& 0xff00) >> 7) +
(rgb
& 0xff);
return gray
>> (10 - image_info
->x_visual_info
->depth
);
}
return pixel
;
}
/**
* xlib_rgb_gc_set_foreground:
* @gc: A graphic context.
* @rgb: 32-bit representation of an RGB value, specified as 0x00RRGGBB.
*
* This is a convenience function to set the foreground of a GC from an RGB
* triplet. It calls xlib_rgb_xpixel_from_rgb() internally and uses the
* returned pixel value to set the GC's foreground.
**/
void
xlib_rgb_gc_set_foreground
(GC gc
, unsigned int rgb
)
{
unsigned long color
;
color
= xlib_rgb_xpixel_from_rgb
(rgb
);
XSetForeground
(image_info
->display
, gc
, color
);
}
/**
* xlib_rgb_gc_set_background:
* @gc: A graphic context.
* @rgb: 32-bit representation of an RGB value, specified as 0x00RRGGBB.
*
* This is a convenience function to set the background of a GC from an RGB
* triplet. It calls xlib_rgb_xpixel_from_rgb() internally and uses the
* returned pixel value to set the GC's background.
**/
void
xlib_rgb_gc_set_background
(GC gc
, unsigned int rgb
)
{
unsigned long color
;
color
= xlib_rgb_xpixel_from_rgb
(rgb
);
XSetBackground
(image_info
->display
, gc
, color
);
}
#ifndef WORDS_BIGENDIAN
#define HAIRY_CONVERT_8
#endif
#ifdef HAIRY_CONVERT_8
static void
xlib_rgb_convert_8
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
obptr
= obuf
;
if (((unsigned long)obuf
| (unsigned long) bp2
) & 3)
{
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
obptr
[0] = colorcube
[((r
& 0xf0) << 4) |
(g
& 0xf0) |
(b
>> 4)];
obptr
++;
}
}
else
{
for (x
= 0; x
< width
- 3; x
+= 4)
{
unsigned int r1b0g0r0
;
unsigned int g2r2b1g1
;
unsigned int b3g3r3b2
;
r1b0g0r0
= ((unsigned int *)bp2
)[0];
g2r2b1g1
= ((unsigned int *)bp2
)[1];
b3g3r3b2
= ((unsigned int *)bp2
)[2];
((unsigned int *)obptr
)[0] =
colorcube
[((r1b0g0r0
& 0xf0) << 4) |
((r1b0g0r0
& 0xf000) >> 8) |
((r1b0g0r0
& 0xf00000) >> 20)] |
(colorcube
[((r1b0g0r0
& 0xf0000000) >> 20) |
(g2r2b1g1
& 0xf0) |
((g2r2b1g1
& 0xf000) >> 12)] << 8) |
(colorcube
[((g2r2b1g1
& 0xf00000) >> 12) |
((g2r2b1g1
& 0xf0000000) >> 24) |
((b3g3r3b2
& 0xf0) >> 4)] << 16) |
(colorcube
[((b3g3r3b2
& 0xf000) >> 4) |
((b3g3r3b2
& 0xf00000) >> 16) |
(b3g3r3b2
>> 28)] << 24);
bp2
+= 12;
obptr
+= 4;
}
for (; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
obptr
[0] = colorcube
[((r
& 0xf0) << 4) |
(g
& 0xf0) |
(b
>> 4)];
obptr
++;
}
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
#else
static void
xlib_rgb_convert_8
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
obptr
= obuf
;
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
obptr
[0] = colorcube
[((r
& 0xf0) << 4) |
(g
& 0xf0) |
(b
>> 4)];
obptr
++;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
#endif
#if 1
/* This dither table was generated by Raph Levien using patented
technology (US Patent 5,276,535). The dither table itself is in the
public domain. */
#define DM_WIDTH 128
#define DM_WIDTH_SHIFT 7
#define DM_HEIGHT 128#else
#define DM_WIDTH 8
#define DM_WIDTH_SHIFT 3
#define DM_HEIGHT 8
static const unsigned char DM
[8][8] =
{
{ 0, 32, 8, 40, 2, 34, 10, 42 },
{ 48, 16, 56, 24, 50, 18, 58, 26 },
{ 12, 44, 4, 36, 14, 46, 6, 38 },
{ 60, 28, 52, 20, 62, 30, 54, 22 },
{ 3, 35, 11, 43, 1, 33, 9, 41 },
{ 51, 19, 59, 27, 49, 17, 57, 25 },
{ 15, 47, 7, 39, 13, 45, 5, 37 },
{ 63, 31, 55, 23, 61, 29, 53, 21 }
};
#endif
static unsigned int *DM_565
= NULL
;
static void
xlib_rgb_preprocess_dm_565
(void)
{
int i
;
unsigned int dith
;
if (DM_565
== NULL
)
{
DM_565
= (unsigned int *) malloc
(sizeof(unsigned int) * DM_WIDTH
* DM_HEIGHT
);
for (i
= 0; i
< DM_WIDTH
* DM_HEIGHT
; i
++)
{
dith
= DM
[0][i
] >> 3;
DM_565
[i
] = (dith
<< 20) | dith
| (((7 - dith
) >> 1) << 10);
#ifdef VERBOSE
printf ("%i %x %x\n", i
, dith
, DM_565
[i
]);
#endif
}
}
}
static void
xlib_rgb_convert_8_d666
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
const unsigned char *dmp
;
int dith
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
;
for (y
= 0; y
< height
; y
++)
{
dmp
= DM
[(y_align
+ y
) & (DM_HEIGHT
- 1)];
bp2
= bptr
;
obptr
= obuf
;
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
dith
= (dmp
[(x_align
+ x
) & (DM_WIDTH
- 1)] << 2) | 7;
r
= ((r
* 5) + dith
) >> 8;
g
= ((g
* 5) + (262 - dith
)) >> 8;
b
= ((b
* 5) + dith
) >> 8;
obptr
[0] = colorcube_d
[(r
<< 6) | (g
<< 3) | b
];
obptr
++;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_8_d
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
,
XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
const unsigned char *dmp
;
int dith
;
int rs
, gs
, bs
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
rs
= image_info
->nred_shades
- 1;
gs
= image_info
->ngreen_shades
- 1;
bs
= image_info
->nblue_shades
- 1;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
;
for (y
= 0; y
< height
; y
++)
{
dmp
= DM
[(y_align
+ y
) & (DM_HEIGHT
- 1)];
bp2
= bptr
;
obptr
= obuf
;
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
dith
= (dmp
[(x_align
+ x
) & (DM_WIDTH
- 1)] << 2) | 7;
r
= ((r
* rs
) + dith
) >> 8;
g
= ((g
* gs
) + (262 - dith
)) >> 8;
b
= ((b
* bs
) + dith
) >> 8;
obptr
[0] = colorcube_d
[(r
<< 6) | (g
<< 3) | b
];
obptr
++;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_8_indexed
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
unsigned char c
;
unsigned char *lut
;
lut
= cmap
->lut
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
obptr
= obuf
;
for (x
= 0; x
< width
; x
++)
{
c
= *bp2
++;
obptr
[0] = lut
[c
];
obptr
++;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_gray8
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
obptr
= obuf
;
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
obptr
[0] = (g
+ ((b
+ r
) >> 1)) >> 1;
obptr
++;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_gray8_gray
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int y
;
int bpl
;
unsigned char *obuf
;
unsigned char *bptr
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
;
for (y
= 0; y
< height
; y
++)
{
memcpy
(obuf
, bptr
, (unsigned int)width
);
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
#ifndef WORDS_BIGENDIAN
#define HAIRY_CONVERT_565
#endif
#ifdef HAIRY_CONVERT_565
/* Render a 24-bit RGB image in buf into the GdkImage, without dithering.
This assumes native byte ordering - what should really be done is to
check whether static_image->byte_order is consistent with the _ENDIAN
config flag, and if not, use a different function.
This one is even faster than the one below - its inner loop loads 3
words (i.e. 4 24-bit pixels), does a lot of shifting and masking,
then writes 2 words. */
static void
xlib_rgb_convert_565
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
, *obptr
;
int bpl
;
unsigned char *bptr
, *bp2
;
unsigned char r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 2;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
obptr
= obuf
;
if (((unsigned long)obuf
| (unsigned long) bp2
) & 3)
{
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
((unsigned short *)obptr
)[0] = ((r
& 0xf8) << 8) |
((g
& 0xfc) << 3) |
(b
>> 3);
obptr
+= 2;
}
}
else
{
for (x
= 0; x
< width
- 3; x
+= 4)
{
unsigned int r1b0g0r0
;
unsigned int g2r2b1g1
;
unsigned int b3g3r3b2
;
r1b0g0r0
= ((unsigned int *)bp2
)[0];
g2r2b1g1
= ((unsigned int *)bp2
)[1];
b3g3r3b2
= ((unsigned int *)bp2
)[2];
((unsigned int *)obptr
)[0] =
((r1b0g0r0
& 0xf8) << 8) |
((r1b0g0r0
& 0xfc00) >> 5) |
((r1b0g0r0
& 0xf80000) >> 19) |
(r1b0g0r0
& 0xf8000000) |
((g2r2b1g1
& 0xfc) << 19) |
((g2r2b1g1
& 0xf800) << 5);
((unsigned int *)obptr
)[1] =
((g2r2b1g1
& 0xf80000) >> 8) |
((g2r2b1g1
& 0xfc000000) >> 21) |
((b3g3r3b2
& 0xf8) >> 3) |
((b3g3r3b2
& 0xf800) << 16) |
((b3g3r3b2
& 0xfc0000) << 3) |
((b3g3r3b2
& 0xf8000000) >> 11);
bp2
+= 12;
obptr
+= 8;
}
for (; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
((unsigned short *)obptr
)[0] = ((r
& 0xf8) << 8) |
((g
& 0xfc) << 3) |
(b
>> 3);
obptr
+= 2;
}
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
#else
/* Render a 24-bit RGB image in buf into the GdkImage, without dithering.
This assumes native byte ordering - what should really be done is to
check whether static_image->byte_order is consistent with the _ENDIAN
config flag, and if not, use a different function.
This routine is faster than the one included with Gtk 1.0 for a number
of reasons:
1. Shifting instead of lookup tables (less memory traffic).
2. Much less register pressure, especially because shifts are
in the code.
3. A memcpy is avoided (i.e. the transfer function).
4. On big-endian architectures, byte swapping is avoided.
That said, it wouldn't be hard to make it even faster - just make an
inner loop that reads 3 words (i.e. 4 24-bit pixels), does a lot of
shifting and masking, then writes 2 words.
*/
static void
xlib_rgb_convert_565
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
;
int bpl
;
unsigned char *bptr
, *bp2
;
unsigned char r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 2;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
((unsigned short *)obuf
)[x
] = ((r
& 0xf8) << 8) |
((g
& 0xfc) << 3) |
(b
>> 3);
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
#endif
#ifdef HAIRY_CONVERT_565
static void
xlib_rgb_convert_565_gray
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
, *obptr
;
int bpl
;
unsigned char *bptr
, *bp2
;
unsigned char g
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 2;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
obptr
= obuf
;
if (((unsigned long)obuf
| (unsigned long) bp2
) & 3)
{
for (x
= 0; x
< width
; x
++)
{
g
= *bp2
++;
((unsigned short *)obptr
)[0] = ((g
& 0xf8) << 8) |
((g
& 0xfc) << 3) |
(g
>> 3);
obptr
+= 2;
}
}
else
{
for (x
= 0; x
< width
- 3; x
+= 4)
{
unsigned int g3g2g1g0
;
g3g2g1g0
= ((unsigned int *)bp2
)[0];
((unsigned int *)obptr
)[0] =
((g3g2g1g0
& 0xf8) << 8) |
((g3g2g1g0
& 0xfc) << 3) |
((g3g2g1g0
& 0xf8) >> 3) |
(g3g2g1g0
& 0xf800) << 16 |
((g3g2g1g0
& 0xfc00) << 11) |
((g3g2g1g0
& 0xf800) << 5);
((unsigned int *)obptr
)[1] =
((g3g2g1g0
& 0xf80000) >> 8) |
((g3g2g1g0
& 0xfc0000) >> 13) |
((g3g2g1g0
& 0xf80000) >> 19) |
(g3g2g1g0
& 0xf8000000) |
((g3g2g1g0
& 0xfc000000) >> 5) |
((g3g2g1g0
& 0xf8000000) >> 11);
bp2
+= 4;
obptr
+= 8;
}
for (; x
< width
; x
++)
{
g
= *bp2
++;
((unsigned short *)obptr
)[0] = ((g
& 0xf8) << 8) |
((g
& 0xfc) << 3) |
(g
>> 3);
obptr
+= 2;
}
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
#else
static void
xlib_rgb_convert_565_gray
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
;
int bpl
;
unsigned char *bptr
, *bp2
;
unsigned char g
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 2;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
g
= *bp2
++;
((unsigned short *)obuf
)[x
] = ((g
& 0xf8) << 8) |
((g
& 0xfc) << 3) |
(g
>> 3);
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
#endif
static void
xlib_rgb_convert_565_br
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
;
int bpl
;
unsigned char *bptr
, *bp2
;
unsigned char r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 2;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
/* final word is:
g4 g3 g2 b7 b6 b5 b4 b3 r7 r6 r5 r4 r3 g7 g6 g5
*/
((unsigned short *)obuf
)[x
] = (r
& 0xf8) |
((g
& 0xe0) >> 5) |
((g
& 0x1c) << 11) |
((b
& 0xf8) << 5);
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
/* Thanks to Ray Lehtiniemi for a patch that resulted in a ~25% speedup
in this mode. */
#ifdef HAIRY_CONVERT_565
static void
xlib_rgb_convert_565_d
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
/* Now this is what I'd call some highly tuned code! */
int x
, y
;
unsigned char *obuf
, *obptr
;
int bpl
;
unsigned char *bptr
, *bp2
;
width
+= x_align
;
height
+= y_align
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 2;
for (y
= y_align
; y
< height
; y
++)
{
unsigned int *dmp
= DM_565
+ ((y
& (DM_HEIGHT
- 1)) << DM_WIDTH_SHIFT
);
bp2
= bptr
;
obptr
= obuf
;
if (((unsigned long)obuf
| (unsigned long) bp2
) & 3)
{
for (x
= x_align
; x
< width
; x
++)
{
int rgb
= *bp2
++ << 20;
rgb
+= *bp2
++ << 10;
rgb
+= *bp2
++;
rgb
+= dmp
[x
& (DM_WIDTH
- 1)];
rgb
+= 0x10040100
- ((rgb
& 0x1e0001e0) >> 5)
- ((rgb
& 0x00070000) >> 6);
((unsigned short *)obptr
)[0] =
((rgb
& 0x0f800000) >> 12) |
((rgb
& 0x0003f000) >> 7) |
((rgb
& 0x000000f8) >> 3);
obptr
+= 2;
}
}
else
{
for (x
= x_align
; x
< width
- 3; x
+= 4)
{
unsigned int r1b0g0r0
;
unsigned int g2r2b1g1
;
unsigned int b3g3r3b2
;
unsigned int rgb02
, rgb13
;
r1b0g0r0
= ((unsigned int *)bp2
)[0];
g2r2b1g1
= ((unsigned int *)bp2
)[1];
b3g3r3b2
= ((unsigned int *)bp2
)[2];
rgb02
=
((r1b0g0r0
& 0xff) << 20) +
((r1b0g0r0
& 0xff00) << 2) +
((r1b0g0r0
& 0xff0000) >> 16) +
dmp
[x
& (DM_WIDTH
- 1)];
rgb02
+= 0x10040100
- ((rgb02
& 0x1e0001e0) >> 5)
- ((rgb02
& 0x00070000) >> 6);
rgb13
=
((r1b0g0r0
& 0xff000000) >> 4) +
((g2r2b1g1
& 0xff) << 10) +
((g2r2b1g1
& 0xff00) >> 8) +
dmp
[(x
+ 1) & (DM_WIDTH
- 1)];
rgb13
+= 0x10040100
- ((rgb13
& 0x1e0001e0) >> 5)
- ((rgb13
& 0x00070000) >> 6);
((unsigned int *)obptr
)[0] =
((rgb02
& 0x0f800000) >> 12) |
((rgb02
& 0x0003f000) >> 7) |
((rgb02
& 0x000000f8) >> 3) |
((rgb13
& 0x0f800000) << 4) |
((rgb13
& 0x0003f000) << 9) |
((rgb13
& 0x000000f8) << 13);
rgb02
=
((g2r2b1g1
& 0xff0000) << 4) +
((g2r2b1g1
& 0xff000000) >> 14) +
(b3g3r3b2
& 0xff) +
dmp
[(x
+ 2) & (DM_WIDTH
- 1)];
rgb02
+= 0x10040100
- ((rgb02
& 0x1e0001e0) >> 5)
- ((rgb02
& 0x00070000) >> 6);
rgb13
=
((b3g3r3b2
& 0xff00) << 12) +
((b3g3r3b2
& 0xff0000) >> 6) +
((b3g3r3b2
& 0xff000000) >> 24) +
dmp
[(x
+ 3) & (DM_WIDTH
- 1)];
rgb13
+= 0x10040100
- ((rgb13
& 0x1e0001e0) >> 5)
- ((rgb13
& 0x00070000) >> 6);
((unsigned int *)obptr
)[1] =
((rgb02
& 0x0f800000) >> 12) |
((rgb02
& 0x0003f000) >> 7) |
((rgb02
& 0x000000f8) >> 3) |
((rgb13
& 0x0f800000) << 4) |
((rgb13
& 0x0003f000) << 9) |
((rgb13
& 0x000000f8) << 13);
bp2
+= 12;
obptr
+= 8;
}
for (; x
< width
; x
++)
{
int rgb
= *bp2
++ << 20;
rgb
+= *bp2
++ << 10;
rgb
+= *bp2
++;
rgb
+= dmp
[x
& (DM_WIDTH
- 1)];
rgb
+= 0x10040100
- ((rgb
& 0x1e0001e0) >> 5)
- ((rgb
& 0x00070000) >> 6);
((unsigned short *)obptr
)[0] =
((rgb
& 0x0f800000) >> 12) |
((rgb
& 0x0003f000) >> 7) |
((rgb
& 0x000000f8) >> 3);
obptr
+= 2;
}
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
#else
static void
xlib_rgb_convert_565_d
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
;
int bpl
;
unsigned char *bptr
;
width
+= x_align
;
height
+= y_align
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ (ax
- x_align
) * 2;
for (y
= y_align
; y
< height
; y
++)
{
unsigned int *dmp
= DM_565
+ ((y
& (DM_HEIGHT
- 1)) << DM_WIDTH_SHIFT
);
unsigned char *bp2
= bptr
;
for (x
= x_align
; x
< width
; x
++)
{
int rgb
= *bp2
++ << 20;
rgb
+= *bp2
++ << 10;
rgb
+= *bp2
++;
rgb
+= dmp
[x
& (DM_WIDTH
- 1)];
rgb
+= 0x10040100
- ((rgb
& 0x1e0001e0) >> 5)
- ((rgb
& 0x00070000) >> 6);
((unsigned short *)obuf
)[x
] =
((rgb
& 0x0f800000) >> 12) |
((rgb
& 0x0003f000) >> 7) |
((rgb
& 0x000000f8) >> 3);
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
#endif
static void
xlib_rgb_convert_555
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
;
int bpl
;
unsigned char *bptr
, *bp2
;
unsigned char r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 2;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
((unsigned short *)obuf
)[x
] = ((r
& 0xf8) << 7) |
((g
& 0xf8) << 2) |
(b
>> 3);
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_555_br
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
;
int bpl
;
unsigned char *bptr
, *bp2
;
unsigned char r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 2;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
/* final word is:
g5 g4 g3 b7 b6 b5 b4 b3 0 r7 r6 r5 r4 r3 g7 g6
*/
((unsigned short *)obuf
)[x
] = ((r
& 0xf8) >> 1) |
((g
& 0xc0) >> 6) |
((g
& 0x18) << 10) |
((b
& 0xf8) << 5);
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_888_msb
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int y
;
unsigned char *obuf
;
int bpl
;
unsigned char *bptr
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 3;
for (y
= 0; y
< height
; y
++)
{
memcpy
(obuf
, bptr
, (unsigned int)(width
+ width
+ width
));
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
/* todo: optimize this */
#ifndef WORDS_BIGENDIAN
#define HAIRY_CONVERT_888
#endif
#ifdef HAIRY_CONVERT_888
static void
xlib_rgb_convert_888_lsb
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
, *obptr
;
int bpl
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 3;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
obptr
= obuf
;
if (((unsigned long)obuf
| (unsigned long) bp2
) & 3)
{
for (x
= 0; x
< width
; x
++)
{
r
= bp2
[0];
g
= bp2
[1];
b
= bp2
[2];
*obptr
++ = b
;
*obptr
++ = g
;
*obptr
++ = r
;
bp2
+= 3;
}
}
else
{
for (x
= 0; x
< width
- 3; x
+= 4)
{
unsigned int r1b0g0r0
;
unsigned int g2r2b1g1
;
unsigned int b3g3r3b2
;
r1b0g0r0
= ((unsigned int *)bp2
)[0];
g2r2b1g1
= ((unsigned int *)bp2
)[1];
b3g3r3b2
= ((unsigned int *)bp2
)[2];
((unsigned int *)obptr
)[0] =
(r1b0g0r0
& 0xff00) |
((r1b0g0r0
& 0xff0000) >> 16) |
(((g2r2b1g1
& 0xff00) | (r1b0g0r0
& 0xff)) << 16);
((unsigned int *)obptr
)[1] =
(g2r2b1g1
& 0xff0000ff) |
((r1b0g0r0
& 0xff000000) >> 16) |
((b3g3r3b2
& 0xff) << 16);
((unsigned int *)obptr
)[2] =
(((g2r2b1g1
& 0xff0000) | (b3g3r3b2
& 0xff000000)) >> 16) |
((b3g3r3b2
& 0xff00) << 16) |
((b3g3r3b2
& 0xff0000));
bp2
+= 12;
obptr
+= 12;
}
for (; x
< width
; x
++)
{
r
= bp2
[0];
g
= bp2
[1];
b
= bp2
[2];
*obptr
++ = b
;
*obptr
++ = g
;
*obptr
++ = r
;
bp2
+= 3;
}
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
#else
static void
xlib_rgb_convert_888_lsb
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
;
int bpl
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 3;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= bp2
[0];
g
= bp2
[1];
b
= bp2
[2];
obuf
[x
* 3] = b
;
obuf
[x
* 3 + 1] = g
;
obuf
[x
* 3 + 2] = r
;
bp2
+= 3;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
#endif
/* convert 24-bit packed to 32-bit unpacked */
/* todo: optimize this */
static void
xlib_rgb_convert_0888
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
;
int bpl
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 4;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= bp2
[0];
g
= bp2
[1];
b
= bp2
[2];
((unsigned int *)obuf
)[x
] = (r
<< 16) | (g
<< 8) | b
;
bp2
+= 3;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_0888_br
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
;
int bpl
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 4;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= bp2
[0];
g
= bp2
[1];
b
= bp2
[2];
((unsigned int *)obuf
)[x
] = (b
<< 24) | (g
<< 16) | (r
<< 8);
bp2
+= 3;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_8880_br
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
;
int bpl
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* 4;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= bp2
[0];
g
= bp2
[1];
b
= bp2
[2];
((unsigned int *)obuf
)[x
] = (b
<< 16) | (g
<< 8) | r
;
bp2
+= 3;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
/* Generic truecolor/directcolor conversion function. Slow, but these
are oddball modes. */
static void
xlib_rgb_convert_truecolor_lsb
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
,
XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
, *obptr
;
int bpl
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
int r_right
, r_left
;
int g_right
, g_left
;
int b_right
, b_left
;
int bpp
;
unsigned int pixel
;
int i
;
r_right
= 8 - image_info
->red_prec
;
r_left
= image_info
->red_shift
;
g_right
= 8 - image_info
->green_prec
;
g_left
= image_info
->green_shift
;
b_right
= 8 - image_info
->blue_prec
;
b_left
= image_info
->blue_shift
;
bpp
= image_info
->bpp
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* bpp
;
for (y
= 0; y
< height
; y
++)
{
obptr
= obuf
;
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= bp2
[0];
g
= bp2
[1];
b
= bp2
[2];
pixel
= ((r
>> r_right
) << r_left
) |
((g
>> g_right
) << g_left
) |
((b
>> b_right
) << b_left
);
for (i
= 0; i
< bpp
; i
++)
{
*obptr
++ = pixel
& 0xff;
pixel
>>= 8;
}
bp2
+= 3;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_truecolor_lsb_d
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
,
XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
, *obptr
;
int bpl
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
int r_right
, r_left
, r_prec
;
int g_right
, g_left
, g_prec
;
int b_right
, b_left
, b_prec
;
int bpp
;
unsigned int pixel
;
int i
;
int dith
;
int r1
, g1
, b1
;
const unsigned char *dmp
;
r_right
= 8 - image_info
->red_prec
;
r_left
= image_info
->red_shift
;
r_prec
= image_info
->red_prec
;
g_right
= 8 - image_info
->green_prec
;
g_left
= image_info
->green_shift
;
g_prec
= image_info
->green_prec
;
b_right
= 8 - image_info
->blue_prec
;
b_left
= image_info
->blue_shift
;
b_prec
= image_info
->blue_prec
;
bpp
= image_info
->bpp
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* bpp
;
for (y
= 0; y
< height
; y
++)
{
dmp
= DM
[(y_align
+ y
) & (DM_HEIGHT
- 1)];
obptr
= obuf
;
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= bp2
[0];
g
= bp2
[1];
b
= bp2
[2];
dith
= dmp
[(x_align
+ x
) & (DM_WIDTH
- 1)] << 2;
r1
= r
+ (dith
>> r_prec
);
g1
= g
+ ((252 - dith
) >> g_prec
);
b1
= b
+ (dith
>> b_prec
);
pixel
= (((r1
- (r1
>> r_prec
)) >> r_right
) << r_left
) |
(((g1
- (g1
>> g_prec
)) >> g_right
) << g_left
) |
(((b1
- (b1
>> b_prec
)) >> b_right
) << b_left
);
for (i
= 0; i
< bpp
; i
++)
{
*obptr
++ = pixel
& 0xff;
pixel
>>= 8;
}
bp2
+= 3;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_truecolor_msb
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
,
XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
, *obptr
;
int bpl
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
int r_right
, r_left
;
int g_right
, g_left
;
int b_right
, b_left
;
int bpp
;
unsigned int pixel
;
int shift
, shift_init
;
r_right
= 8 - image_info
->red_prec
;
r_left
= image_info
->red_shift
;
g_right
= 8 - image_info
->green_prec
;
g_left
= image_info
->green_shift
;
b_right
= 8 - image_info
->blue_prec
;
b_left
= image_info
->blue_shift
;
bpp
= image_info
->bpp
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* bpp
;
shift_init
= (bpp
- 1) << 3;
for (y
= 0; y
< height
; y
++)
{
obptr
= obuf
;
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= bp2
[0];
g
= bp2
[1];
b
= bp2
[2];
pixel
= ((r
>> r_right
) << r_left
) |
((g
>> g_right
) << g_left
) |
((b
>> b_right
) << b_left
);
for (shift
= shift_init
; shift
>= 0; shift
-= 8)
{
*obptr
++ = (pixel
>> shift
) & 0xff;
}
bp2
+= 3;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_truecolor_msb_d
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
,
XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *obuf
, *obptr
;
int bpl
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
int r_right
, r_left
, r_prec
;
int g_right
, g_left
, g_prec
;
int b_right
, b_left
, b_prec
;
int bpp
;
unsigned int pixel
;
int shift
, shift_init
;
int dith
;
int r1
, g1
, b1
;
const unsigned char *dmp
;
r_right
= 8 - image_info
->red_prec
;
r_left
= image_info
->red_shift
;
r_prec
= image_info
->red_prec
;
g_right
= 8 - image_info
->green_prec
;
g_left
= image_info
->green_shift
;
g_prec
= image_info
->green_prec
;
b_right
= 8 - image_info
->blue_prec
;
b_left
= image_info
->blue_shift
;
b_prec
= image_info
->blue_prec
;
bpp
= image_info
->bpp
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
* bpp
;
shift_init
= (bpp
- 1) << 3;
for (y
= 0; y
< height
; y
++)
{
dmp
= DM
[(y_align
+ y
) & (DM_HEIGHT
- 1)];
obptr
= obuf
;
bp2
= bptr
;
for (x
= 0; x
< width
; x
++)
{
r
= bp2
[0];
g
= bp2
[1];
b
= bp2
[2];
dith
= dmp
[(x_align
+ x
) & (DM_WIDTH
- 1)] << 2;
r1
= r
+ (dith
>> r_prec
);
g1
= g
+ ((252 - dith
) >> g_prec
);
b1
= b
+ (dith
>> b_prec
);
pixel
= (((r1
- (r1
>> r_prec
)) >> r_right
) << r_left
) |
(((g1
- (g1
>> g_prec
)) >> g_right
) << g_left
) |
(((b1
- (b1
>> b_prec
)) >> b_right
) << b_left
);
for (shift
= shift_init
; shift
>= 0; shift
-= 8)
{
*obptr
++ = (pixel
>> shift
) & 0xff;
}
bp2
+= 3;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
/* This actually works for depths from 3 to 7 */
static void
xlib_rgb_convert_4
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
,
XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
const unsigned char *dmp
;
int dith
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
;
for (y
= 0; y
< height
; y
++)
{
dmp
= DM
[(y_align
+ y
) & (DM_HEIGHT
- 1)];
bp2
= bptr
;
obptr
= obuf
;
for (x
= 0; x
< width
; x
+= 1)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
dith
= (dmp
[(x_align
+ x
) & (DM_WIDTH
- 1)] << 2) | 3;
obptr
[0] = colorcube_d
[(((r
+ dith
) & 0x100) >> 2) |
(((g
+ 258 - dith
) & 0x100) >> 5) |
(((b
+ dith
) & 0x100) >> 8)];
obptr
++;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
/* This actually works for depths from 3 to 7 */
static void
xlib_rgb_convert_gray4
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
int shift
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
;
shift
= 9 - image_info
->x_visual_info
->depth
;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
obptr
= obuf
;
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
obptr
[0] = (g
+ ((b
+ r
) >> 1)) >> shift
;
obptr
++;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_gray4_pack
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
int shift
;
unsigned char pix0
, pix1
;
/* todo: this is hardcoded to big-endian. Make endian-agile. */
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ (ax
>> 1);
shift
= 9 - image_info
->x_visual_info
->depth
;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
obptr
= obuf
;
for (x
= 0; x
< width
; x
+= 2)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
pix0
= (g
+ ((b
+ r
) >> 1)) >> shift
;
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
pix1
= (g
+ ((b
+ r
) >> 1)) >> shift
;
obptr
[0] = (pix0
<< 4) | pix1
;
obptr
++;
}
if (width
& 1)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
pix0
= (g
+ ((b
+ r
) >> 1)) >> shift
;
obptr
[0] = (pix0
<< 4);
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
/* This actually works for depths from 3 to 7 */
static void
xlib_rgb_convert_gray4_d
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
const unsigned char *dmp
;
int prec
, right
;
int gray
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ ax
;
prec
= image_info
->x_visual_info
->depth
;
right
= 8 - prec
;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
obptr
= obuf
;
dmp
= DM
[(y_align
+ y
) & (DM_HEIGHT
- 1)];
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
gray
= (g
+ ((b
+ r
) >> 1)) >> 1;
gray
+= (dmp
[(x_align
+ x
) & (DM_WIDTH
- 1)] << 2) >> prec
;
obptr
[0] = (gray
- (gray
>> prec
)) >> right
;
obptr
++;
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_gray4_d_pack
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
const unsigned char *dmp
;
int prec
, right
;
int gray
;
unsigned char pix0
, pix1
;
/* todo: this is hardcoded to big-endian. Make endian-agile. */
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ (ax
>> 1);
prec
= image_info
->x_visual_info
->depth
;
right
= 8 - prec
;
for (y
= 0; y
< height
; y
++)
{
bp2
= bptr
;
obptr
= obuf
;
dmp
= DM
[(y_align
+ y
) & (DM_HEIGHT
- 1)];
for (x
= 0; x
< width
; x
+= 2)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
gray
= (g
+ ((b
+ r
) >> 1)) >> 1;
gray
+= (dmp
[(x_align
+ x
) & (DM_WIDTH
- 1)] << 2) >> prec
;
pix0
= (gray
- (gray
>> prec
)) >> right
;
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
gray
= (g
+ ((b
+ r
) >> 1)) >> 1;
gray
+= (dmp
[(x_align
+ x
+ 1) & (DM_WIDTH
- 1)] << 2) >> prec
;
pix1
= (gray
- (gray
>> prec
)) >> right
;
obptr
[0] = (pix0
<< 4) | pix1
;
obptr
++;
}
if (width
& 1)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
gray
= (g
+ ((b
+ r
) >> 1)) >> 1;
gray
+= (dmp
[(x_align
+ x
+ 1) & (DM_WIDTH
- 1)] << 2) >> prec
;
pix0
= (gray
- (gray
>> prec
)) >> right
;
obptr
[0] = (pix0
<< 4);
}
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
static void
xlib_rgb_convert_1
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
,
XlibRgbCmap
*cmap
)
{
int x
, y
;
int bpl
;
unsigned char *obuf
, *obptr
;
unsigned char *bptr
, *bp2
;
int r
, g
, b
;
const unsigned char *dmp
;
int dith
;
unsigned char byte
;
bptr
= buf
;
bpl
= image
->bytes_per_line
;
obuf
= ((unsigned char *)image
->data
) + ay
* bpl
+ (ax
>> 3);
byte
= 0; /* unnecessary, but it keeps gcc from complaining */
for (y
= 0; y
< height
; y
++)
{
dmp
= DM
[(y_align
+ y
) & (DM_HEIGHT
- 1)];
bp2
= bptr
;
obptr
= obuf
;
for (x
= 0; x
< width
; x
++)
{
r
= *bp2
++;
g
= *bp2
++;
b
= *bp2
++;
dith
= (dmp
[(x_align
+ x
) & (DM_WIDTH
- 1)] << 4) | 4;
byte
+= byte
+ (r
+ g
+ g
+ b
+ dith
> 1020);
if ((x
& 7) == 7)
{
obptr
[0] = byte
;
obptr
++;
}
}
if (x
& 7)
obptr
[0] = byte
<< (8 - (x
& 7));
bptr
+= rowstride
;
obuf
+= bpl
;
}
}
/* Returns a pointer to the stage buffer. */
static unsigned char *
xlib_rgb_ensure_stage
(void)
{
if (image_info
->stage_buf
== NULL
)
image_info
->stage_buf
= (unsigned char *) malloc
(IMAGE_HEIGHT
* STAGE_ROWSTRIDE
);
return image_info
->stage_buf
;
}
/* This is slow. Speed me up, please. */
static void
xlib_rgb_32_to_stage
(unsigned char *buf
, int rowstride
, int width
, int height
)
{
int x
, y
;
unsigned char *pi_start
, *po_start
;
unsigned char *pi
, *po
;
pi_start
= buf
;
po_start
= xlib_rgb_ensure_stage
();
for (y
= 0; y
< height
; y
++)
{
pi
= pi_start
;
po
= po_start
;
for (x
= 0; x
< width
; x
++)
{
*po
++ = *pi
++;
*po
++ = *pi
++;
*po
++ = *pi
++;
pi
++;
}
pi_start
+= rowstride
;
po_start
+= STAGE_ROWSTRIDE
;
}
}
/* Generic 32bit RGB conversion function - convert to 24bit packed, then
go from there. */
static void
xlib_rgb_convert_32_generic
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
xlib_rgb_32_to_stage
(buf
, rowstride
, width
, height
);
(*image_info
->conv
) (image
, ax
, ay
, width
, height
,
image_info
->stage_buf
, STAGE_ROWSTRIDE
,
x_align
, y_align
, cmap
);
}
/* Generic 32bit RGB conversion function - convert to 24bit packed, then
go from there. */
static void
xlib_rgb_convert_32_generic_d
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
xlib_rgb_32_to_stage
(buf
, rowstride
, width
, height
);
(*image_info
->conv_d
) (image
, ax
, ay
, width
, height
,
image_info
->stage_buf
, STAGE_ROWSTRIDE
,
x_align
, y_align
, cmap
);
}
/* This is slow. Speed me up, please. */
static void
xlib_rgb_gray_to_stage
(unsigned char *buf
, int rowstride
, int width
, int height
)
{
int x
, y
;
unsigned char *pi_start
, *po_start
;
unsigned char *pi
, *po
;
unsigned char gray
;
pi_start
= buf
;
po_start
= xlib_rgb_ensure_stage
();
for (y
= 0; y
< height
; y
++)
{
pi
= pi_start
;
po
= po_start
;
for (x
= 0; x
< width
; x
++)
{
gray
= *pi
++;
*po
++ = gray
;
*po
++ = gray
;
*po
++ = gray
;
}
pi_start
+= rowstride
;
po_start
+= STAGE_ROWSTRIDE
;
}
}
/* Generic gray conversion function - convert to 24bit packed, then go
from there. */
static void
xlib_rgb_convert_gray_generic
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
xlib_rgb_gray_to_stage
(buf
, rowstride
, width
, height
);
(*image_info
->conv
) (image
, ax
, ay
, width
, height
,
image_info
->stage_buf
, STAGE_ROWSTRIDE
,
x_align
, y_align
, cmap
);
}
static void
xlib_rgb_convert_gray_generic_d
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
xlib_rgb_gray_to_stage
(buf
, rowstride
, width
, height
);
(*image_info
->conv_d
) (image
, ax
, ay
, width
, height
,
image_info
->stage_buf
, STAGE_ROWSTRIDE
,
x_align
, y_align
, cmap
);
}
/* Render grayscale using indexed method. */
static void
xlib_rgb_convert_gray_cmap
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
(*image_info
->conv_indexed
) (image
, ax
, ay
, width
, height
,
buf
, rowstride
,
x_align
, y_align
, image_info
->gray_cmap
);
}
#if 0
static void
xlib_rgb_convert_gray_cmap_d
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
(*image_info
->conv_indexed_d
) (image
, ax
, ay
, width
, height
,
buf
, rowstride
,
x_align
, y_align
, image_info
->gray_cmap
);
}
#endif
/* This is slow. Speed me up, please. */
static void
xlib_rgb_indexed_to_stage
(unsigned char *buf
, int rowstride
, int width
, int height
,
XlibRgbCmap
*cmap
)
{
int x
, y
;
unsigned char *pi_start
, *po_start
;
unsigned char *pi
, *po
;
int rgb
;
pi_start
= buf
;
po_start
= xlib_rgb_ensure_stage
();
for (y
= 0; y
< height
; y
++)
{
pi
= pi_start
;
po
= po_start
;
for (x
= 0; x
< width
; x
++)
{
rgb
= cmap
->colors
[*pi
++];
*po
++ = rgb
>> 16;
*po
++ = (rgb
>> 8) & 0xff;
*po
++ = rgb
& 0xff;
}
pi_start
+= rowstride
;
po_start
+= STAGE_ROWSTRIDE
;
}
}
/* Generic gray conversion function - convert to 24bit packed, then go
from there. */
static void
xlib_rgb_convert_indexed_generic
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
, XlibRgbCmap
*cmap
)
{
xlib_rgb_indexed_to_stage
(buf
, rowstride
, width
, height
, cmap
);
(*image_info
->conv
) (image
, ax
, ay
, width
, height
,
image_info
->stage_buf
, STAGE_ROWSTRIDE
,
x_align
, y_align
, cmap
);
}
static void
xlib_rgb_convert_indexed_generic_d
(XImage
*image
,
int ax
, int ay
, int width
, int height
,
unsigned char *buf
, int rowstride
,
int x_align
, int y_align
,
XlibRgbCmap
*cmap
)
{
xlib_rgb_indexed_to_stage
(buf
, rowstride
, width
, height
, cmap
);
(*image_info
->conv_d
) (image
, ax
, ay
, width
, height
,
image_info
->stage_buf
, STAGE_ROWSTRIDE
,
x_align
, y_align
, cmap
);
}
/* Select a conversion function based on the visual and a
representative image. */
static void
xlib_rgb_select_conv
(XImage
*image
, ByteOrder byte_order
)
{
int depth
, byterev
;
int vtype
; /* visual type */
int bpp
; /* bits per pixel - from the visual */
unsigned int red_mask
, green_mask
, blue_mask
;
XlibRgbConvFunc conv
, conv_d
;
XlibRgbConvFunc conv_32
, conv_32_d
;
XlibRgbConvFunc conv_gray
, conv_gray_d
;
XlibRgbConvFunc conv_indexed
, conv_indexed_d
;
Bool mask_rgb
, mask_bgr
;
depth
= image_info
->x_visual_info
->depth
;
bpp
= image
->bits_per_pixel
;
if (xlib_rgb_verbose
)
printf ("Chose visual 0x%x, image bpp=%d, %s first\n",
(int)image_info
->x_visual_info
->visual
->visualid
,
bpp
, byte_order
== LSB_FIRST
? "lsb" : "msb");
#ifdef WORDS_BIGENDIAN
byterev
= (byte_order
== LSB_FIRST
);
#else
byterev
= (byte_order
== MSB_FIRST
);
#endif
vtype
= image_info
->x_visual_info
->class
;
if (vtype
== DirectColor
)
vtype
= TrueColor
;
red_mask
= image_info
->x_visual_info
->red_mask
;
green_mask
= image_info
->x_visual_info
->green_mask
;
blue_mask
= image_info
->x_visual_info
->blue_mask
;
mask_rgb
= red_mask
== 0xff0000 && green_mask
== 0xff00 && blue_mask
== 0xff;
mask_bgr
= red_mask
== 0xff && green_mask
== 0xff00 && blue_mask
== 0xff0000;
conv
= NULL
;
conv_d
= NULL
;
conv_32
= xlib_rgb_convert_32_generic
;
conv_32_d
= xlib_rgb_convert_32_generic_d
;
conv_gray
= xlib_rgb_convert_gray_generic
;
conv_gray_d
= xlib_rgb_convert_gray_generic_d
;
conv_indexed
= xlib_rgb_convert_indexed_generic
;
conv_indexed_d
= xlib_rgb_convert_indexed_generic_d
;
image_info
->dith_default
= FALSE
;
if (image_info
->bitmap
)
conv
= xlib_rgb_convert_1
;
else if (bpp
== 16 && depth
== 16 && !byterev
&&
red_mask
== 0xf800 && green_mask
== 0x7e0 && blue_mask
== 0x1f)
{
conv
= xlib_rgb_convert_565
;
conv_d
= xlib_rgb_convert_565_d
;
conv_gray
= xlib_rgb_convert_565_gray
;
xlib_rgb_preprocess_dm_565
();
}
else if (bpp
== 16 && depth
== 16 &&
vtype
== TrueColor
&& byterev
&&
red_mask
== 0xf800 && green_mask
== 0x7e0 && blue_mask
== 0x1f)
conv
= xlib_rgb_convert_565_br
;
else if (bpp
== 16 && depth
== 15 &&
vtype
== TrueColor
&& !byterev
&&
red_mask
== 0x7c00 && green_mask
== 0x3e0 && blue_mask
== 0x1f)
conv
= xlib_rgb_convert_555
;
else if (bpp
== 16 && depth
== 15 &&
vtype
== TrueColor
&& byterev
&&
red_mask
== 0x7c00 && green_mask
== 0x3e0 && blue_mask
== 0x1f)
conv
= xlib_rgb_convert_555_br
;
/* I'm not 100% sure about the 24bpp tests - but testing will show*/
else if (bpp
== 24 && depth
== 24 && vtype
== TrueColor
&&
((mask_rgb
&& byte_order
== LSB_FIRST
) ||
(mask_bgr
&& byte_order
== MSB_FIRST
)))
conv
= xlib_rgb_convert_888_lsb
;
else if (bpp
== 24 && depth
== 24 && vtype
== TrueColor
&&
((mask_rgb
&& byte_order
== MSB_FIRST
) ||
(mask_bgr
&& byte_order
== LSB_FIRST
)))
conv
= xlib_rgb_convert_888_msb
;
#ifdef WORDS_BIGENDIAN
else if (bpp
== 32 && depth
== 24 && vtype
== TrueColor
&&
(mask_rgb
&& byte_order
== LSB_FIRST
))
conv
= xlib_rgb_convert_0888_br
;
else if (bpp
== 32 && depth
== 24 && vtype
== TrueColor
&&
(mask_rgb
&& byte_order
== MSB_FIRST
))
conv
= xlib_rgb_convert_0888
;
else if (bpp
== 32 && depth
== 24 && vtype
== TrueColor
&&
(mask_bgr
&& byte_order
== MSB_FIRST
))
conv
= xlib_rgb_convert_8880_br
;
#else
else if (bpp
== 32 && depth
== 24 && vtype
== TrueColor
&&
(mask_rgb
&& byte_order
== MSB_FIRST
))
conv
= xlib_rgb_convert_0888_br
;
else if (bpp
== 32 && (depth
== 32 || depth
== 24) && vtype
== TrueColor
&&
(mask_rgb
&& byte_order
== LSB_FIRST
))
conv
= xlib_rgb_convert_0888
;
else if (bpp
== 32 && depth
== 24 && vtype
== TrueColor
&&
(mask_bgr
&& byte_order
== LSB_FIRST
))
conv
= xlib_rgb_convert_8880_br
;
#endif
else if (vtype
== TrueColor
&& byte_order
== LSB_FIRST
)
{
conv
= xlib_rgb_convert_truecolor_lsb
;
conv_d
= xlib_rgb_convert_truecolor_lsb_d
;
}
else if (vtype
== TrueColor
&& byte_order
== MSB_FIRST
)
{
conv
= xlib_rgb_convert_truecolor_msb
;
conv_d
= xlib_rgb_convert_truecolor_msb_d
;
}
else if (bpp
== 8 && depth
== 8 && (vtype
== PseudoColor
#ifdef ENABLE_GRAYSCALE
|| vtype
== GrayScale
#endif
))
{
image_info
->dith_default
= TRUE
;
conv
= xlib_rgb_convert_8
;
if (vtype
!= GrayScale
)
{
if (image_info
->nred_shades
== 6 &&
image_info
->ngreen_shades
== 6 &&
image_info
->nblue_shades
== 6)
conv_d
= xlib_rgb_convert_8_d666
;
else
conv_d
= xlib_rgb_convert_8_d
;
}
conv_indexed
= xlib_rgb_convert_8_indexed
;
conv_gray
= xlib_rgb_convert_gray_cmap
;
}
else if (bpp
== 8 && depth
== 8 && (vtype
== StaticGray
#ifdef not_ENABLE_GRAYSCALE
|| vtype
== GrayScale
#endif
))
{
conv
= xlib_rgb_convert_gray8
;
conv_gray
= xlib_rgb_convert_gray8_gray
;
}
else if (bpp
== 8 && depth
< 8 && depth
>= 2 &&
(vtype
== StaticGray
|| vtype
== GrayScale
))
{
conv
= xlib_rgb_convert_gray4
;
conv_d
= xlib_rgb_convert_gray4_d
;
}
else if (bpp
== 8 && depth
< 8 && depth
>= 3)
{
conv
= xlib_rgb_convert_4
;
}
else if (bpp
== 4 && depth
<= 4 && depth
>= 2 &&
(vtype
== StaticGray
|| vtype
== GrayScale
))
{
conv
= xlib_rgb_convert_gray4_pack
;
conv_d
= xlib_rgb_convert_gray4_d_pack
;
}
if (conv_d
== NULL
)
conv_d
= conv
;
image_info
->conv
= conv
;
image_info
->conv_d
= conv_d
;
image_info
->conv_32
= conv_32
;
image_info
->conv_32_d
= conv_32_d
;
image_info
->conv_gray
= conv_gray
;
image_info
->conv_gray_d
= conv_gray_d
;
image_info
->conv_indexed
= conv_indexed
;
image_info
->conv_indexed_d
= conv_indexed_d
;
}
static int horiz_idx
;
static int horiz_y
= IMAGE_HEIGHT
;
static int vert_idx
;
static int vert_x
= IMAGE_WIDTH
;
static int tile_idx
;
static int tile_x
= IMAGE_WIDTH
;
static int tile_y1
= IMAGE_HEIGHT
;
static int tile_y2
= IMAGE_HEIGHT
;
#ifdef VERBOSE
static int sincelast
;
#endif
/* Defining NO_FLUSH can cause inconsistent screen updates, but is useful
for performance evaluation. */
#undef NO_FLUSH
static int
xlib_rgb_alloc_scratch_image
(void)
{
if (static_image_idx
== N_IMAGES
)
{
#ifndef NO_FLUSH
XFlush
(image_info
->display
);
#endif
#ifdef VERBOSE
printf ("flush, %d puts since last flush\n", sincelast
);
sincelast
= 0;
#endif
static_image_idx
= 0;
horiz_y
= IMAGE_HEIGHT
;
vert_x
= IMAGE_WIDTH
;
tile_x
= IMAGE_WIDTH
;
tile_y1
= tile_y2
= IMAGE_HEIGHT
;
}
return static_image_idx
++;
}
static XImage
*
xlib_rgb_alloc_scratch
(int width
, int height
, int *ax
, int *ay
)
{
XImage
*image
;
int idx
;
if (width
>= (IMAGE_WIDTH
>> 1))
{
if (height
>= (IMAGE_HEIGHT
>> 1))
{
idx
= xlib_rgb_alloc_scratch_image
();
*ax
= 0;
*ay
= 0;
}
else
{
if (height
+ horiz_y
> IMAGE_HEIGHT
)
{
horiz_idx
= xlib_rgb_alloc_scratch_image
();
horiz_y
= 0;
}
idx
= horiz_idx
;
*ax
= 0;
*ay
= horiz_y
;
horiz_y
+= height
;
}
}
else
{
if (height
>= (IMAGE_HEIGHT
>> 1))
{
if (width
+ vert_x
> IMAGE_WIDTH
)
{
vert_idx
= xlib_rgb_alloc_scratch_image
();
vert_x
= 0;
}
idx
= vert_idx
;
*ax
= vert_x
;
*ay
= 0;
/* using 3 and -4 would be slightly more efficient on 32-bit machines
with > 1bpp displays */
vert_x
+= (width
+ 7) & -8;
}
else
{
if (width
+ tile_x
> IMAGE_WIDTH
)
{
tile_y1
= tile_y2
;
tile_x
= 0;
}
if (height
+ tile_y1
> IMAGE_HEIGHT
)
{
tile_idx
= xlib_rgb_alloc_scratch_image
();
tile_x
= 0;
tile_y1
= 0;
tile_y2
= 0;
}
if (height
+ tile_y1
> tile_y2
)
tile_y2
= height
+ tile_y1
;
idx
= tile_idx
;
*ax
= tile_x
;
*ay
= tile_y1
;
tile_x
+= (width
+ 7) & -8;
}
}
image
= static_image
[idx
];
#ifdef VERBOSE
printf ("index %d, x %d, y %d (%d x %d)\n", idx
, *ax
, *ay
, width
, height
);
sincelast
++;
#endif
return image
;
}
static void
xlib_draw_rgb_image_core
(Drawable drawable
,
GC gc
,
int x
,
int y
,
int width
,
int height
,
unsigned char *buf
,
int pixstride
,
int rowstride
,
XlibRgbConvFunc conv
,
XlibRgbCmap
*cmap
,
int xdith
,
int ydith
)
{
int ay
, ax
;
int xs0
, ys0
;
XImage
*image
;
int width1
, height1
;
unsigned char *buf_ptr
;
if (image_info
->bitmap
)
{
if (image_info
->own_gc
== 0)
{
XColor color
;
image_info
->own_gc
= XCreateGC
(image_info
->display
,
drawable
,
0, NULL
);
color.
pixel = WhitePixel
(image_info
->display
,
image_info
->screen_num
);
XSetForeground
(image_info
->display
, image_info
->own_gc
, color.
pixel);
color.
pixel = BlackPixel
(image_info
->display
,
image_info
->screen_num
);
XSetBackground
(image_info
->display
, image_info
->own_gc
, color.
pixel);
}
gc
= image_info
->own_gc
;
}
for (ay
= 0; ay
< height
; ay
+= IMAGE_HEIGHT
)
{
height1
= MIN
(height
- ay
, IMAGE_HEIGHT
);
for (ax
= 0; ax
< width
; ax
+= IMAGE_WIDTH
)
{
width1
= MIN
(width
- ax
, IMAGE_WIDTH
);
buf_ptr
= buf
+ ay
* rowstride
+ ax
* pixstride
;
image
= xlib_rgb_alloc_scratch
(width1
, height1
, &xs0
, &ys0
);
conv
(image
, xs0
, ys0
, width1
, height1
, buf_ptr
, rowstride
,
x
+ ax
+ xdith
, y
+ ay
+ ydith
, cmap
);
#ifndef DONT_ACTUALLY_DRAW
XPutImage
(image_info
->display
, drawable
, gc
, image
,
xs0
, ys0
, x
+ ax
, y
+ ay
, (unsigned int)width1
, (unsigned int)height1
);
#endif
}
}
}
/**
* xlib_draw_rgb_image:
* @drawable: Destination drawable.
* @gc: A graphic context.
* @x: Leftmost coordinate of the destination rectangle.
* @y: Upper coordinate of the destination rectangle.
* @width: Width of the destination rectangle, in pixels.
* @height: Height of the destination rectangle, in pixels.
* @dith: Dithering method to use.
* @rgb_buf: Pointer to the pixel in the RGB buffer that corresponds to the
* upper-left corner of the rectangular region to render.
* @rowstride: Offset between pixel rows in the RGB buffer, in bytes.
*
* Renders an RGB buffer to a drawable. Pixels are specified as RGB triplets
* with 8 bits per channel. An image will thus look like an RGBRGBRGBRGB
* sequence of 8-bit values. This function does not let you specify dither
* offsets; applications that need to render partial regions of a buffer to
* build the final image should use xlib_draw_rgb_image_dithalign() instead.
**/
void
xlib_draw_rgb_image
(Drawable drawable
,
GC gc
,
int x
,
int y
,
int width
,
int height
,
XlibRgbDither dith
,
unsigned char *rgb_buf
,
int rowstride
)
{
if (dith
== XLIB_RGB_DITHER_NONE
|| (dith
== XLIB_RGB_DITHER_NORMAL
&&
!image_info
->dith_default
))
xlib_draw_rgb_image_core
(drawable
, gc
, x
, y
, width
, height
,
rgb_buf
, 3, rowstride
, image_info
->conv
, NULL
,
0, 0);
else
xlib_draw_rgb_image_core
(drawable
, gc
, x
, y
, width
, height
,
rgb_buf
, 3, rowstride
, image_info
->conv_d
, NULL
,
0, 0);
}
/**
* xlib_draw_rgb_image_dithalign:
* @drawable: Destination drawable.
* @gc: A graphic context.
* @x: Leftmost coordinate of the destination rectangle.
* @y: Upper coordinate of the destination rectangle.
* @width: Width of the destination rectangle, in pixels.
* @height: Height of the destination rectangle, in pixels.
* @dith: Dithering method to use.
* @rgb_buf: Pointer to the pixel in the RGB buffer that corresponds to the
* upper-left corner of the rectangular region to render.
* @rowstride: Offset between pixel rows in the RGB buffer, in bytes.
* @xdith: X offset for the dither mask.
* @ydith: Y offset for the dither mask.
*
* Renders an RGB buffer to a drawable. Pixels are specified as RGB triplets
* with 8 bits per channel. An image will thus look like an RGBRGBRGBRGB
* sequence of 8-bit values. This function lets you specify a pair of dither
* offsets. It should be used when you need to render regions of an RGB buffer
* separately to form the final image; the dither offsets let you align the
* dither mask appropriately.
**/
void
xlib_draw_rgb_image_dithalign
(Drawable drawable
,
GC gc
,
int x
,
int y
,
int width
,
int height
,
XlibRgbDither dith
,
unsigned char *rgb_buf
,
int rowstride
,
int xdith
,
int ydith
)
{
if (dith
== XLIB_RGB_DITHER_NONE
|| (dith
== XLIB_RGB_DITHER_NORMAL
&&
!image_info
->dith_default
))
xlib_draw_rgb_image_core
(drawable
, gc
, x
, y
, width
, height
,
rgb_buf
, 3, rowstride
, image_info
->conv
, NULL
,
xdith
, ydith
);
else
xlib_draw_rgb_image_core
(drawable
, gc
, x
, y
, width
, height
,
rgb_buf
, 3, rowstride
, image_info
->conv_d
, NULL
,
xdith
, ydith
);
}
/**
* xlib_draw_rgb_32_image:
* @drawable: Destination drawable.
* @gc: A graphic context.
* @x: Leftmost coordinate of the destination rectangle.
* @y: Upper coordinate of the destination rectangle.
* @width: Width of the destination rectangle, in pixels.
* @height: Height of the destination rectangle, in pixels.
* @dith: Dithering method to use.
* @buf: Pointer to the pixel in the RGB buffer that corresponds to the
* upper-left corner of the rectangular region to render.
* @rowstride: Offset between pixel rows in the RGB buffer, in bytes.
*
* This function is analogous to xlib_draw_rgb_image(), but it lets you use
* 32-bit RGB buffers with pixels specified as 0xRRGGBB00. The
* least-significant 8 bits are actually discarded. This function can lead to
* faster results than xlib_draw_rgb_image() since the pixels are aligned on
* 32-bit boundaries.
**/
void
xlib_draw_rgb_32_image
(Drawable drawable
,
GC gc
,
int x
,
int y
,
int width
,
int height
,
XlibRgbDither dith
,
unsigned char *buf
,
int rowstride
)
{
if (dith
== XLIB_RGB_DITHER_NONE
|| (dith
== XLIB_RGB_DITHER_NORMAL
&&
!image_info
->dith_default
))
xlib_draw_rgb_image_core
(drawable
, gc
, x
, y
, width
, height
,
buf
, 4, rowstride
,
image_info
->conv_32
, NULL
, 0, 0);
else
xlib_draw_rgb_image_core
(drawable
, gc
, x
, y
, width
, height
,
buf
, 4, rowstride
,
image_info
->conv_32_d
, NULL
, 0, 0);
}
static void
xlib_rgb_make_gray_cmap
(XlibRgbInfo
*info
)
{
unsigned int rgb
[256];
int i
;
for (i
= 0; i
< 256; i
++)
rgb
[i
] = (i
<< 16) | (i
<< 8) | i
;
info
->gray_cmap
= xlib_rgb_cmap_new
(rgb
, 256);
}
/**
* xlib_draw_gray_image:
* @drawable: Destination drawable.
* @gc: A graphic context.
* @x: Leftmost coordinate of the destination rectangle.
* @y: Upper coordinate of the destination rectangle.
* @width: Width of the destination rectangle, in pixels.
* @height: Height of thd destination rectangle, in pixels.
* @dith: Dithering method to use.
* @buf: Pointer to the pixel in the grayscale buffer that corresponds to the
* upper-left corner of the rectangular region to render.
* @rowstride: Offset between pixel rows in the grayscale buffer, in pixels.
*
* Renders a grayscale buffer to a drawable. Pixels are specified as 8-bit
* intensity values. An image will thus look as a GGGGGG sequence of 8-bit
* values.
**/
void
xlib_draw_gray_image
(Drawable drawable
,
GC gc
,
int x
,
int y
,
int width
,
int height
,
XlibRgbDither dith
,
unsigned char *buf
,
int rowstride
)
{
if (image_info
->bpp
== 1 &&
image_info
->gray_cmap
== NULL
&&
(image_info
->x_visual_info
->class
== PseudoColor
||
image_info
->x_visual_info
->class
== GrayScale
))
xlib_rgb_make_gray_cmap
(image_info
);
if (dith
== XLIB_RGB_DITHER_NONE
|| (dith
== XLIB_RGB_DITHER_NORMAL
&&
!image_info
->dith_default
))
xlib_draw_rgb_image_core
(drawable
, gc
, x
, y
, width
, height
,
buf
, 1, rowstride
,
image_info
->conv_gray
, NULL
, 0, 0);
else
xlib_draw_rgb_image_core
(drawable
, gc
, x
, y
, width
, height
,
buf
, 1, rowstride
,
image_info
->conv_gray_d
, NULL
, 0, 0);
}
/**
* xlib_rgb_cmap_new:
* @colors: FIXME
* @n_colors: FIXME
*
* FIXME
*
* Return value: FIXME
**/
XlibRgbCmap
*
xlib_rgb_cmap_new
(unsigned int *colors
, int n_colors
)
{
XlibRgbCmap
*cmap
;
int i
, j
;
unsigned int rgb
;
if (n_colors
< 0)
return NULL
;
if (n_colors
> 256)
return NULL
;
cmap
= (XlibRgbCmap
*) malloc
(sizeof(XlibRgbCmap
));
memcpy
(cmap
->colors
, colors
, n_colors
* sizeof(unsigned int));
if (image_info
->bpp
== 1 &&
(image_info
->x_visual_info
->class
== PseudoColor
||
image_info
->x_visual_info
->class
== GrayScale
))
for (i
= 0; i
< n_colors
; i
++)
{
rgb
= colors
[i
];
j
= ((rgb
& 0xf00000) >> 12) |
((rgb
& 0xf000) >> 8) |
((rgb
& 0xf0) >> 4);
#ifdef VERBOSE
printf ("%d %x %x %d\n", i
, j
, colorcube
[j
]);
#endif
cmap
->lut
[i
] = colorcube
[j
];
}
return cmap
;
}
/**
* xlib_rgb_cmap_free:
* @cmap: An XlibRGB colormap.
*
* Frees an XlibRGB colormap.
**/
void
xlib_rgb_cmap_free
(XlibRgbCmap
*cmap
)
{
free
(cmap
);
}
/**
* xlib_draw_indexed_image:
* @drawable: FIXME
* @gc: FIXME
* @x: FIXME
* @y: FIXME
* @width: FIXME
* @height: FIXME
* @dith: FIXME
* @buf: FIXME
* @rowstride: FIXME
* @cmap: FIXME
*
* FIXME
**/
void
xlib_draw_indexed_image
(Drawable drawable
,
GC gc
,
int x
,
int y
,
int width
,
int height
,
XlibRgbDither dith
,
unsigned char *buf
,
int rowstride
,
XlibRgbCmap
*cmap
)
{
if (dith
== XLIB_RGB_DITHER_NONE
|| (dith
== XLIB_RGB_DITHER_NORMAL
&&
!image_info
->dith_default
))
xlib_draw_rgb_image_core
(drawable
, gc
, x
, y
, width
, height
,
buf
, 1, rowstride
,
image_info
->conv_indexed
, cmap
, 0, 0);
else
xlib_draw_rgb_image_core
(drawable
, gc
, x
, y
, width
, height
,
buf
, 1, rowstride
,
image_info
->conv_indexed_d
, cmap
, 0, 0);
}
/**
* xlib_rgb_ditherable:
*
* Queries whether XlibRGB supports dithering for its chosen visual.
*
* Return value: TRUE if dithering can be performed for the visual that XlibRGB
* is using, FALSE otherwise.
**/
Bool
xlib_rgb_ditherable
(void)
{
return (image_info
->conv
!= image_info
->conv_d
);
}
/**
* xlib_rgb_get_cmap:
*
* Queries the X colormap that XlibRGB is using.
*
* Return value: An X colormap.
**/
Colormap
xlib_rgb_get_cmap
(void)
{
/* xlib_rgb_init (); */
if (image_info
)
return image_info
->cmap
;
else
return 0;
}
/**
* xlib_rgb_get_visual:
*
* Queries the visual that XlibRGB is using.
*
* Return value: An X visual.
**/
Visual
*
xlib_rgb_get_visual
(void)
{
/* xlib_rgb_init (); */
if (image_info
)
return image_info
->x_visual_info
->visual
;
else
return 0;
}
/**
* xlib_rgb_get_visual_info:
*
* Queries the visual info structure for the visual that XlibRGB is using.
*
* Return value: An XVisualInfo structure.
**/
XVisualInfo
*
xlib_rgb_get_visual_info
(void)
{
/* xlib_rgb_init (); */
if (image_info
)
return image_info
->x_visual_info
;
else
return 0;
}
/**
* xlib_rgb_get_depth:
*
* Queries the depth of the visual that XlibRGB is using.
*
* Return value: Bit depth.
**/
int
xlib_rgb_get_depth
(void)
{
XVisualInfo
* v
= xlib_rgb_get_visual_info
();
if (v
)
{
return v
->depth
;
}
return 0;
}
/**
* xlib_rgb_get_display:
*
* Queries the X display that XlibRGB is using.
*
* Return value: An X display.
**/
Display
*
xlib_rgb_get_display
(void)
{
if (image_info
)
return image_info
->display
;
return NULL
;
}
/**
* xlib_rgb_get_screen:
*
* Queries the screen that XlibRGB is using.
*
* Return value: An X screen.
**/
Screen
*
xlib_rgb_get_screen
(void)
{
if (image_info
)
return image_info
->screen
;
return NULL
;
}