kde-workspace/ksplash/ksplashx/pixmap.cpp

1045 lines
30 KiB
C++
Raw Normal View History

2014-11-13 19:30:51 +02:00
/****************************************************************************
**
** This file is based on sources of the Qt GUI Toolkit, used under the terms
** of the GNU General Public License version 2 (see the original copyright
** notice below).
** All further contributions to this file are (and are required to be)
** licensed under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** The original Qt license header follows:
**
**
** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
**
** This file is part of the kernel module of the Qt GUI Toolkit.
**
** This file may be distributed under the terms of the Q Public License
** as defined by Trolltech AS of Norway and appearing in the file
** LICENSE.QPL included in the packaging of this file.
**
** This file may be distributed and/or modified under the terms of the
** GNU General Public License version 2 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.
**
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
** licenses may use this file in accordance with the Qt Commercial License
** Agreement provided with the Software.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
** information about Qt Commercial License Agreements.
** See http://www.trolltech.com/qpl/ for QPL licensing information.
** See http://www.trolltech.com/gpl/ for GPL licensing information.
**
** Contact info@trolltech.com if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/
#include <config-X11.h>
#ifdef HAVE_XSHM
#define QT_MITSHM_CONVERSIONS
#endif
#include "qimage.h"
#include "qnamespace.h"
#include "qcolor.h"
#include <stdlib.h>
#include <string.h>
#include "pixmap.h"
#include "x11_defs.h"
#ifdef QT_MITSHM_CONVERSIONS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#endif
// Returns position of highest bit set or -1 if none
static int highest_bit( uint v )
{
int i;
uint b = (uint)1 << 31;
for ( i=31; ((b & v) == 0) && i>=0; i-- )
b >>= 1;
return i;
}
// Returns position of lowest set bit in 'v' as an integer (0-31), or -1
static int lowest_bit( uint v )
{
int i;
unsigned long lb;
lb = 1;
for (i=0; ((v & lb) == 0) && i<32; i++, lb<<=1);
return i==32 ? -1 : i;
}
// Counts the number of bits set in 'v'
static uint n_bits( uint v )
{
int i = 0;
while ( v ) {
v = v & (v - 1);
i++;
}
return i;
}
inline static void qSafeXDestroyImage( XImage *x )
{
if ( x->data ) {
free( x->data );
x->data = 0;
}
XDestroyImage( x );
}
#ifdef QT_MITSHM_CONVERSIONS
static bool qt_mitshm_error = false;
static int qt_mitshm_errorhandler( Display*, XErrorEvent* )
{
qt_mitshm_error = true;
return 0;
}
static XImage* qt_XShmCreateImage( Display* dpy, Visual* visual, unsigned int depth,
int format, int /*offset*/, char* /*data*/, unsigned int width, unsigned int height,
int /*bitmap_pad*/, int /*bytes_per_line*/, XShmSegmentInfo* shminfo )
{
if( width * height * depth < 100*100*32 )
return NULL;
static int shm_inited = -1;
if( shm_inited == -1 ) {
if( XShmQueryExtension( dpy ))
shm_inited = 1;
else
shm_inited = 0;
}
if( shm_inited == 0 )
return NULL;
XImage* xi = XShmCreateImage( dpy, visual, depth, format, NULL, shminfo, width,
height );
if( xi == NULL )
return NULL;
shminfo->shmid = shmget( IPC_PRIVATE, xi->bytes_per_line * xi->height,
IPC_CREAT|0600);
if( shminfo->shmid < 0 ) {
XDestroyImage( xi );
return NULL;
}
shminfo->readOnly = False;
shminfo->shmaddr = (char*)shmat( shminfo->shmid, 0, 0 );
if( shminfo->shmaddr == (char*)-1 ) {
XDestroyImage( xi );
shmctl( shminfo->shmid, IPC_RMID, 0 );
return NULL;
}
xi->data = shminfo->shmaddr;
#ifndef QT_MITSHM_RMID_IGNORES_REFCOUNT
// mark as deleted to automatically free the memory in case
// of a crash (but this doesn't work e.g. on Solaris)
shmctl( shminfo->shmid, IPC_RMID, 0 );
#endif
if( shm_inited == 1 ) { // first time
XErrorHandler old_h = XSetErrorHandler( qt_mitshm_errorhandler );
XShmAttach( dpy, shminfo );
shm_inited = 2;
XSync( dpy, False );
XSetErrorHandler( old_h );
if( qt_mitshm_error ) { // oops ... perhaps we are remote?
shm_inited = 0;
XDestroyImage( xi );
shmdt( shminfo->shmaddr );
#ifdef QT_MITSHM_RMID_IGNORES_REFCOUNT
shmctl( shminfo->shmid, IPC_RMID, 0 );
#endif
return NULL;
}
} else
XShmAttach( dpy, shminfo );
return xi;
}
static void qt_XShmDestroyImage( XImage* xi, XShmSegmentInfo* shminfo )
{
XShmDetach( QPaintDevice::x11AppDisplay(), shminfo );
XDestroyImage( xi );
shmdt( shminfo->shmaddr );
#ifdef QT_MITSHM_RMID_IGNORES_REFCOUNT
shmctl( shminfo->shmid, IPC_RMID, 0 );
#endif
}
#endif // QT_MITSHM_CONVERSIONS
PixmapData PP::convertFromImage( const QImage &img, int conversion_flags )
{
if ( img.isNull() ) {
#if defined(QT_CHECK_NULL)
qWarning( "QPixmap::convertFromImage: Cannot convert a null image" );
#endif
return PixmapData();
}
//# detach(); // detach other references
QImage image = img;
const uint w = image.width();
const uint h = image.height();
int d = image.depth();
const int dd = x11Depth();
bool force_mono = (dd == 1 || //#*isQBitmap() ||
(conversion_flags & Qt::ColorMode_Mask)==MonoOnly );
#if 0
// get rid of the mask
delete data->mask;
data->mask = 0;
// get rid of alpha pixmap
delete data->alphapm;
data->alphapm = 0;
#endif
// must be monochrome
if ( force_mono ) {
if ( d != 1 ) {
// dither
image = image.convertDepth( 1, conversion_flags );
d = 1;
}
} else { // can be both
bool conv8 = false;
if ( d > 8 && dd <= 8 ) { // convert to 8 bit
if ( (conversion_flags & DitherMode_Mask) == AutoDither )
conversion_flags = (conversion_flags & ~DitherMode_Mask)
| PreferDither;
conv8 = true;
} else if ( (conversion_flags & ColorMode_Mask) == ColorOnly ) {
conv8 = d == 1; // native depth wanted
} else if ( d == 1 ) {
if ( image.numColors() == 2 ) {
QRgb c0 = image.color(0); // Auto: convert to best
QRgb c1 = image.color(1);
conv8 = qMin(c0,c1) != qRgb(0,0,0) || qMax(c0,c1) != qRgb(255,255,255);
} else {
// eg. 1-color monochrome images (they do exist).
conv8 = true;
}
}
if ( conv8 ) {
image = image.convertDepth( 8, conversion_flags );
d = 8;
}
}
if ( d == 1 ) { // 1 bit pixmap (bitmap)
abort();
#if 0
if ( hd ) { // delete old X pixmap
#ifndef QT_NO_XFTFREETYPE
if (rendhd) {
XftDrawDestroy( (XftDraw *) rendhd );
rendhd = 0;
}
#endif // QT_NO_XFTFREETYPE
XFreePixmap( x11Display(), hd );
}
// make sure image.color(0) == color0 (white) and image.color(1) == color1 (black)
if (image.color(0) == Qt::black.rgb() && image.color(1) == Qt::white.rgb()) {
image.invertPixels();
image.setColor(0, Qt::white.rgb());
image.setColor(1, Qt::black.rgb());
}
char *bits;
uchar *tmp_bits;
int bpl = (w+7)/8;
int ibpl = image.bytesPerLine();
if ( image.bitOrder() == QImage::BigEndian || bpl != ibpl ) {
tmp_bits = new uchar[bpl*h];
Q_CHECK_PTR( tmp_bits );
bits = (char *)tmp_bits;
uchar *p, *b, *end;
uint y, count;
if ( image.bitOrder() == QImage::BigEndian ) {
const uchar *f = qt_get_bitflip_array();
b = tmp_bits;
for ( y=0; y<h; y++ ) {
p = image.scanLine( y );
end = p + bpl;
count = bpl;
while ( count > 4 ) {
*b++ = f[*p++];
*b++ = f[*p++];
*b++ = f[*p++];
*b++ = f[*p++];
count -= 4;
}
while ( p < end )
*b++ = f[*p++];
}
} else { // just copy
b = tmp_bits;
p = image.scanLine( 0 );
for ( y=0; y<h; y++ ) {
memcpy( b, p, bpl );
b += bpl;
p += ibpl;
}
}
} else {
bits = (char *)image.bits();
tmp_bits = 0;
}
hd = (HANDLE)XCreateBitmapFromData( x11Display(),
RootWindow(x11Display(), x11Screen() ),
bits, w, h );
#ifndef QT_NO_XFTFREETYPE
if ( qt_has_xft )
rendhd = (HANDLE) XftDrawCreateBitmap( x11Display(), hd );
#endif // QT_NO_XFTFREETYPE
if ( tmp_bits ) // Avoid purify complaint
delete [] tmp_bits;
data->w = w; data->h = h; data->d = 1;
if ( image.hasAlphaBuffer() ) {
QBitmap m;
m = image.createAlphaMask( conversion_flags );
setMask( m );
}
return true;
#endif
}
Display *dpy = x11Display();
Visual *visual = (Visual *)x11Visual();
XImage *xi = 0;
bool trucol = (visual->c_class == TrueColor);
int nbytes = image.byteCount();
2014-11-13 19:30:51 +02:00
uchar *newbits= 0;
int newbits_size = 0;
#ifdef QT_MITSHM_CONVERSIONS
bool mitshm_ximage = false;
XShmSegmentInfo shminfo;
#endif
if ( trucol ) { // truecolor display
QRgb pix[256]; // pixel translation table
const bool d8 = d == 8;
const uint red_mask = (uint)visual->red_mask;
const uint green_mask = (uint)visual->green_mask;
const uint blue_mask = (uint)visual->blue_mask;
const int red_shift = highest_bit( red_mask ) - 7;
const int green_shift = highest_bit( green_mask ) - 7;
const int blue_shift = highest_bit( blue_mask ) - 7;
const uint rbits = highest_bit(red_mask) - lowest_bit(red_mask) + 1;
const uint gbits = highest_bit(green_mask) - lowest_bit(green_mask) + 1;
const uint bbits = highest_bit(blue_mask) - lowest_bit(blue_mask) + 1;
if ( d8 ) { // setup pixel translation
QRgb *ctable = image.colorTable();
for ( int i=0; i<image.numColors(); i++ ) {
int r = qRed (ctable[i]);
int g = qGreen(ctable[i]);
int b = qBlue (ctable[i]);
r = red_shift > 0 ? r << red_shift : r >> -red_shift;
g = green_shift > 0 ? g << green_shift : g >> -green_shift;
b = blue_shift > 0 ? b << blue_shift : b >> -blue_shift;
pix[i] = (b & blue_mask) | (g & green_mask) | (r & red_mask)
| ~(blue_mask | green_mask | red_mask);
}
}
#ifdef QT_MITSHM_CONVERSIONS
xi = qt_XShmCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0, &shminfo );
if( xi != NULL ) {
mitshm_ximage = true;
newbits = (uchar*)xi->data;
}
else
#endif
xi = XCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0 );
Q_CHECK_PTR( xi );
if( newbits == NULL )
newbits = (uchar *)malloc( xi->bytes_per_line*h );
Q_CHECK_PTR( newbits );
if ( !newbits ) // no memory
return PixmapData();
int bppc = xi->bits_per_pixel;
bool contig_bits = n_bits(red_mask) == rbits &&
n_bits(green_mask) == gbits &&
n_bits(blue_mask) == bbits;
bool dither_tc =
// Want it?
(conversion_flags & Dither_Mask) != ThresholdDither &&
(conversion_flags & DitherMode_Mask) != AvoidDither &&
// Need it?
bppc < 24 && !d8 &&
// Can do it? (Contiguous bits?)
contig_bits;
static bool init=false;
static int D[16][16];
if ( dither_tc && !init ) {
// I also contributed this code to XV - WWA.
/*
The dither matrix, D, is obtained with this formula:
D2 = [ 0 2 ]
[ 3 1 ]
D2*n = [ 4*Dn 4*Dn+2*Un ]
[ 4*Dn+3*Un 4*Dn+1*Un ]
*/
int n,i,j;
init=1;
/* Set D2 */
D[0][0]=0;
D[1][0]=2;
D[0][1]=3;
D[1][1]=1;
/* Expand using recursive definition given above */
for (n=2; n<16; n*=2) {
for (i=0; i<n; i++) {
for (j=0; j<n; j++) {
D[i][j]*=4;
D[i+n][j]=D[i][j]+2;
D[i][j+n]=D[i][j]+3;
D[i+n][j+n]=D[i][j]+1;
}
}
}
init=true;
}
enum { BPP8,
BPP16_8_3_M3, BPP16_7_2_M3, BPP16_MSB, BPP16_LSB,
BPP24_MSB, BPP24_LSB,
BPP32_16_8_0, BPP32_MSB, BPP32_LSB
} mode = BPP8;
if ( bppc > 8 && xi->byte_order == LSBFirst )
bppc++;
int wordsize;
bool bigendian;
qSysInfo( &wordsize, &bigendian );
bool same_msb_lsb = ( xi->byte_order == MSBFirst ) == ( bigendian );
if( bppc == 8 ) // 8 bit
mode = BPP8;
else if( bppc == 16 || bppc == 17 ) { // 16 bit MSB/LSB
if( red_shift == 8 && green_shift == 3 && blue_shift == -3
&& !d8 && same_msb_lsb )
mode = BPP16_8_3_M3;
else if( red_shift == 7 && green_shift == 2 && blue_shift == -3
&& !d8 && same_msb_lsb )
mode = BPP16_7_2_M3;
else
mode = bppc == 17 ? BPP16_LSB : BPP16_MSB;
} else if( bppc == 24 || bppc == 25 ) { // 24 bit MSB/LSB
mode = bppc == 25 ? BPP24_LSB : BPP24_MSB;
} else if( bppc == 32 || bppc == 33 ) { // 32 bit MSB/LSB
if( red_shift == 16 && green_shift == 8 && blue_shift == 0
&& !d8 && same_msb_lsb )
mode = BPP32_16_8_0;
else
mode = bppc == 33 ? BPP32_LSB : BPP32_MSB;
} else
qFatal("Logic error 3");
#define GET_PIXEL \
int pixel; \
if ( d8 ) pixel = pix[*src++]; \
else { \
int r = qRed ( *p ); \
int g = qGreen( *p ); \
int b = qBlue ( *p++ ); \
r = red_shift > 0 \
? r << red_shift : r >> -red_shift; \
g = green_shift > 0 \
? g << green_shift : g >> -green_shift; \
b = blue_shift > 0 \
? b << blue_shift : b >> -blue_shift; \
pixel = (r & red_mask)|(g & green_mask) | (b & blue_mask) \
| ~(blue_mask | green_mask | red_mask); \
}
// optimized case - no d8 case, shift only once instead of twice, mask only once instead of twice,
// use direct values instead of variables, and use only one statement
// (*p >> 16), (*p >> 8 ) and (*p) are qRed(),qGreen() and qBlue() without masking
// shifts have to be passed including the shift operator (e.g. '>>3'), because of the direction
#define GET_PIXEL_OPT(red_shift,green_shift,blue_shift,red_mask,green_mask,blue_mask) \
int pixel = ((( *p >> 16 ) red_shift ) & red_mask ) \
| ((( *p >> 8 ) green_shift ) & green_mask ) \
| ((( *p ) blue_shift ) & blue_mask ); \
++p;
#define GET_PIXEL_DITHER_TC \
int r = qRed ( *p ); \
int g = qGreen( *p ); \
int b = qBlue ( *p++ ); \
const int thres = D[x%16][y%16]; \
if ( r <= (255-(1<<(8-rbits))) && ((r<<rbits) & 255) \
> thres) \
r += (1<<(8-rbits)); \
if ( g <= (255-(1<<(8-gbits))) && ((g<<gbits) & 255) \
> thres) \
g += (1<<(8-gbits)); \
if ( b <= (255-(1<<(8-bbits))) && ((b<<bbits) & 255) \
> thres) \
b += (1<<(8-bbits)); \
r = red_shift > 0 \
? r << red_shift : r >> -red_shift; \
g = green_shift > 0 \
? g << green_shift : g >> -green_shift; \
b = blue_shift > 0 \
? b << blue_shift : b >> -blue_shift; \
int pixel = (r & red_mask)|(g & green_mask) | (b & blue_mask);
// again, optimized case
// can't be optimized that much :(
#define GET_PIXEL_DITHER_TC_OPT(red_shift,green_shift,blue_shift,red_mask,green_mask,blue_mask, \
rbits,gbits,bbits) \
const int thres = D[x%16][y%16]; \
int r = qRed ( *p ); \
if ( r <= (255-(1<<(8-rbits))) && ((r<<rbits) & 255) \
> thres) \
r += (1<<(8-rbits)); \
int g = qGreen( *p ); \
if ( g <= (255-(1<<(8-gbits))) && ((g<<gbits) & 255) \
> thres) \
g += (1<<(8-gbits)); \
int b = qBlue ( *p++ ); \
if ( b <= (255-(1<<(8-bbits))) && ((b<<bbits) & 255) \
> thres) \
b += (1<<(8-bbits)); \
int pixel = (( r red_shift ) & red_mask ) \
| (( g green_shift ) & green_mask ) \
| (( b blue_shift ) & blue_mask );
#define CYCLE(body) \
for ( uint y=0; y<h; y++ ) { \
uchar* src = image.scanLine( y ); \
uchar* dst = newbits + xi->bytes_per_line*y; \
QRgb* p = (QRgb *)src; \
body \
}
if ( dither_tc ) {
switch ( mode ) {
case BPP16_8_3_M3:
CYCLE(
Q_INT16* dst16 = (Q_INT16*)dst;
for ( uint x=0; x<w; x++ ) {
GET_PIXEL_DITHER_TC_OPT(<<8,<<3,>>3,0xf800,0x7e0,0x1f,5,6,5)
*dst16++ = pixel;
}
)
break;
case BPP16_7_2_M3:
CYCLE(
Q_INT16* dst16 = (Q_INT16*)dst;
for ( uint x=0; x<w; x++ ) {
GET_PIXEL_DITHER_TC_OPT(<<7,<<2,>>3,0x7c00,0x3e0,0x1f,5,5,5)
*dst16++ = pixel;
}
)
break;
case BPP16_MSB: // 16 bit MSB
CYCLE(
for ( uint x=0; x<w; x++ ) {
GET_PIXEL_DITHER_TC
*dst++ = (pixel >> 8);
*dst++ = pixel;
}
)
break;
case BPP16_LSB: // 16 bit LSB
CYCLE(
for ( uint x=0; x<w; x++ ) {
GET_PIXEL_DITHER_TC
*dst++ = pixel;
*dst++ = pixel >> 8;
}
)
break;
default:
qFatal("Logic error");
}
} else {
switch ( mode ) {
case BPP8: // 8 bit
CYCLE(
Q_UNUSED(p);
for ( uint x=0; x<w; x++ ) {
int pixel = pix[*src++];
*dst++ = pixel;
}
)
break;
case BPP16_8_3_M3:
CYCLE(
Q_INT16* dst16 = (Q_INT16*)dst;
for ( uint x=0; x<w; x++ ) {
GET_PIXEL_OPT(<<8,<<3,>>3,0xf800,0x7e0,0x1f)
*dst16++ = pixel;
}
)
break;
case BPP16_7_2_M3:
CYCLE(
Q_INT16* dst16 = (Q_INT16*)dst;
for ( uint x=0; x<w; x++ ) {
GET_PIXEL_OPT(<<7,<<2,>>3,0x7c00,0x3e0,0x1f)
*dst16++ = pixel;
}
)
break;
case BPP16_MSB: // 16 bit MSB
CYCLE(
for ( uint x=0; x<w; x++ ) {
GET_PIXEL
*dst++ = (pixel >> 8);
*dst++ = pixel;
}
)
break;
case BPP16_LSB: // 16 bit LSB
CYCLE(
for ( uint x=0; x<w; x++ ) {
GET_PIXEL
*dst++ = pixel;
*dst++ = pixel >> 8;
}
)
break;
case BPP24_MSB: // 24 bit MSB
CYCLE(
for ( uint x=0; x<w; x++ ) {
GET_PIXEL
*dst++ = pixel >> 16;
*dst++ = pixel >> 8;
*dst++ = pixel;
}
)
break;
case BPP24_LSB: // 24 bit LSB
CYCLE(
for ( uint x=0; x<w; x++ ) {
GET_PIXEL
*dst++ = pixel;
*dst++ = pixel >> 8;
*dst++ = pixel >> 16;
}
)
break;
case BPP32_16_8_0:
CYCLE(
memcpy( dst, p, w * 4 );
)
break;
case BPP32_MSB: // 32 bit MSB
CYCLE(
for ( uint x=0; x<w; x++ ) {
GET_PIXEL
*dst++ = pixel >> 24;
*dst++ = pixel >> 16;
*dst++ = pixel >> 8;
*dst++ = pixel;
}
)
break;
case BPP32_LSB: // 32 bit LSB
CYCLE(
for ( uint x=0; x<w; x++ ) {
GET_PIXEL
*dst++ = pixel;
*dst++ = pixel >> 8;
*dst++ = pixel >> 16;
*dst++ = pixel >> 24;
}
)
break;
default:
qFatal("Logic error 2");
}
}
xi->data = (char *)newbits;
}
if ( d == 8 && !trucol ) { // 8 bit pixmap
int pop[256]; // pixel popularity
if ( image.numColors() == 0 )
image.setNumColors( 1 );
memset( pop, 0, sizeof(int)*256 ); // reset popularity array
uint i;
for ( i=0; i<h; i++ ) { // for each scanline...
uchar* p = image.scanLine( i );
uchar *end = p + w;
while ( p < end ) // compute popularity
pop[*p++]++;
}
newbits = (uchar *)malloc( nbytes ); // copy image into newbits
newbits_size = nbytes;
Q_CHECK_PTR( newbits );
if ( !newbits ) // no memory
return PixmapData();
uchar* p = newbits;
memcpy( p, image.bits(), nbytes ); // copy image data into newbits
/*
* The code below picks the most important colors. It is based on the
* diversity algorithm, implemented in XV 3.10. XV is (C) by John Bradley.
*/
struct PIX { // pixel sort element
uchar r,g,b,n; // color + pad
int use; // popularity
int index; // index in colormap
int mindist;
};
int ncols = 0;
for ( i=0; i< (uint) image.numColors(); i++ ) { // compute number of colors
if ( pop[i] > 0 )
ncols++;
}
for ( i=image.numColors(); i<256; i++ ) // ignore out-of-range pixels
pop[i] = 0;
// works since we make sure above to have at least
// one color in the image
if ( ncols == 0 )
ncols = 1;
PIX pixarr[256]; // pixel array
PIX pixarr_sorted[256]; // pixel array (sorted)
memset( pixarr, 0, ncols*sizeof(PIX) );
PIX *px = &pixarr[0];
int maxpop = 0;
int maxpix = 0;
Q_CHECK_PTR( pixarr );
uint j = 0;
QRgb* ctable = image.colorTable();
for ( i=0; i<256; i++ ) { // init pixel array
if ( pop[i] > 0 ) {
px->r = qRed ( ctable[i] );
px->g = qGreen( ctable[i] );
px->b = qBlue ( ctable[i] );
px->n = 0;
px->use = pop[i];
if ( pop[i] > maxpop ) { // select most popular entry
maxpop = pop[i];
maxpix = j;
}
px->index = i;
px->mindist = 1000000;
px++;
j++;
}
}
pixarr_sorted[0] = pixarr[maxpix];
pixarr[maxpix].use = 0;
for ( i=1; i< (uint) ncols; i++ ) { // sort pixels
int minpix = -1, mindist = -1;
px = &pixarr_sorted[i-1];
int r = px->r;
int g = px->g;
int b = px->b;
int dist;
if ( (i & 1) || i<10 ) { // sort on max distance
for ( int j=0; j<ncols; j++ ) {
px = &pixarr[j];
if ( px->use ) {
dist = (px->r - r)*(px->r - r) +
(px->g - g)*(px->g - g) +
(px->b - b)*(px->b - b);
if ( px->mindist > dist )
px->mindist = dist;
if ( px->mindist > mindist ) {
mindist = px->mindist;
minpix = j;
}
}
}
} else { // sort on max popularity
for ( int j=0; j<ncols; j++ ) {
px = &pixarr[j];
if ( px->use ) {
dist = (px->r - r)*(px->r - r) +
(px->g - g)*(px->g - g) +
(px->b - b)*(px->b - b);
if ( px->mindist > dist )
px->mindist = dist;
if ( px->use > mindist ) {
mindist = px->use;
minpix = j;
}
}
}
}
pixarr_sorted[i] = pixarr[minpix];
pixarr[minpix].use = 0;
}
uint pix[256]; // pixel translation table
px = &pixarr_sorted[0];
for ( i=0; i< (uint) ncols; i++ ) { // allocate colors
QColor c( px->r, px->g, px->b );
pix[px->index] = c.pixel(x11Screen());
px++;
}
p = newbits;
for ( i=0; i< (uint) nbytes; i++ ) { // translate pixels
*p = pix[*p];
p++;
}
}
if ( !xi ) { // X image not created
#ifdef QT_MITSHM_CONVERSIONS
xi = qt_XShmCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0, &shminfo );
if( xi != NULL )
mitshm_ximage = true;
else
#endif
xi = XCreateImage( dpy, visual, dd, ZPixmap, 0, 0, w, h, 32, 0 );
if ( xi->bits_per_pixel == 16 ) { // convert 8 bpp ==> 16 bpp
ushort *p2;
int p2inc = xi->bytes_per_line/sizeof(ushort);
ushort *newerbits = (ushort *)malloc( xi->bytes_per_line * h );
newbits_size = xi->bytes_per_line * h;
Q_CHECK_PTR( newerbits );
if ( !newerbits ) // no memory
return PixmapData();
uchar* p = newbits;
for ( uint y=0; y<h; y++ ) { // OOPS: Do right byte order!!
p2 = newerbits + p2inc*y;
for ( uint x=0; x<w; x++ )
*p2++ = *p++;
}
free( newbits );
newbits = (uchar *)newerbits;
} else if ( xi->bits_per_pixel != 8 ) {
#if defined(QT_CHECK_RANGE)
qWarning( "QPixmap::convertFromImage: Display not supported "
"(bpp=%d)", xi->bits_per_pixel );
#endif
}
#ifdef QT_MITSHM_CONVERSIONS
if( newbits_size > 0 && mitshm_ximage ) { // need to copy to shared memory
memcpy( xi->data, newbits, newbits_size );
free( newbits );
newbits = (uchar*)xi->data;
}
else
#endif
xi->data = (char *)newbits;
}
#if 0
if ( hd && (width() != (int)w || height() != (int)h || this->depth() != dd) ) {
#ifndef QT_NO_XFTFREETYPE
if (rendhd) {
XftDrawDestroy( (XftDraw *) rendhd );
rendhd = 0;
}
#endif // QT_NO_XFTFREETYPE
XFreePixmap( dpy, hd ); // don't reuse old pixmap
hd = 0;
}
#endif
PixmapData dat;
PixmapData* data = &dat;
data->hd = None;
Pixmap& hd = data->hd;
if ( !hd ) { // create new pixmap
hd = (HANDLE)XCreatePixmap( x11Display(),
RootWindow(x11Display(), x11Screen() ),
w, h, dd );
#ifndef QT_NO_XFTFREETYPE
if ( qt_has_xft ) {
if ( data->d == 1 ) {
rendhd = (HANDLE) XftDrawCreateBitmap( x11Display (), hd );
} else {
rendhd = (HANDLE) XftDrawCreate( x11Display (), hd,
(Visual *) x11Visual(), x11Colormap() );
}
}
#endif // QT_NO_XFTFREETYPE
}
#ifdef QT_MITSHM_CONVERSIONS
if( mitshm_ximage )
XShmPutImage( dpy, hd, qt_xget_readonly_gc( x11Screen(), false ),
xi, 0, 0, 0, 0, w, h, False );
else
#endif
XPutImage( dpy, hd, qt_xget_readonly_gc( x11Screen(), false ),
xi, 0, 0, 0, 0, w, h );
data->w = w;
data->h = h;
data->d = dd;
XImage* axi = NULL;
#ifdef QT_MITSHM_CONVERSIONS
bool mitshm_aximage = false;
XShmSegmentInfo ashminfo;
#endif
if ( image.hasAlphaBuffer() ) {
abort();
#if 0
QBitmap m;
m = image.createAlphaMask( conversion_flags );
setMask( m );
#ifndef QT_NO_XFTFREETYPE
// does this image have an alphamap (and not just a 1bpp mask)?
bool alphamap = image.depth() == 32;
if (image.depth() == 8) {
const QRgb * const rgb = image.colorTable();
for (int i = 0, count = image.numColors(); i < count; ++i) {
const int alpha = qAlpha(rgb[i]);
if (alpha != 0 && alpha != 0xff) {
alphamap = true;
break;
}
}
}
if (qt_use_xrender && qt_has_xft && alphamap) {
data->alphapm = new QPixmap; // create a null pixmap
// setup pixmap data
data->alphapm->data->w = w;
data->alphapm->data->h = h;
data->alphapm->data->d = 8;
// create 8bpp pixmap and render picture
data->alphapm->hd =
XCreatePixmap(x11Display(), RootWindow(x11Display(), x11Screen()),
w, h, 8);
data->alphapm->rendhd =
(HANDLE) XftDrawCreateAlpha( x11Display(), data->alphapm->hd, 8 );
#ifdef QT_MITSHM_CONVERSIONS
axi = qt_XShmCreateImage( x11Display(), (Visual*)x11Visual(),
8, ZPixmap, 0, 0, w, h, 8, 0, &ashminfo );
if( axi != NULL )
mitshm_aximage = true;
else
#endif
axi = XCreateImage(x11Display(), (Visual *) x11Visual(),
8, ZPixmap, 0, 0, w, h, 8, 0);
if (axi) {
if( axi->data==NULL ) {
// the data is deleted by qSafeXDestroyImage
axi->data = (char *) malloc(h * axi->bytes_per_line);
Q_CHECK_PTR( axi->data );
}
char *aptr = axi->data;
if (image.depth() == 32) {
const int *iptr = (const int *) image.bits();
if( axi->bytes_per_line == (int)w ) {
int max = w * h;
while (max--)
*aptr++ = *iptr++ >> 24; // squirt
} else {
for (uint i = 0; i < h; ++i ) {
for (uint j = 0; j < w; ++j )
*aptr++ = *iptr++ >> 24; // squirt
aptr += ( axi->bytes_per_line - w );
}
}
} else if (image.depth() == 8) {
const QRgb * const rgb = image.colorTable();
for (uint y = 0; y < h; ++y) {
const uchar *iptr = image.scanLine(y);
for (uint x = 0; x < w; ++x)
*aptr++ = qAlpha(rgb[*iptr++]);
aptr += ( axi->bytes_per_line - w );
}
}
GC gc = XCreateGC(x11Display(), data->alphapm->hd, 0, 0);
#ifdef QT_MITSHM_CONVERSIONS
if( mitshm_aximage )
XShmPutImage( dpy, data->alphapm->hd, gc, axi, 0, 0, 0, 0, w, h, False );
else
#endif
XPutImage(dpy, data->alphapm->hd, gc, axi, 0, 0, 0, 0, w, h);
XFreeGC(x11Display(), gc);
}
}
#endif // QT_NO_XFTFREETYPE
#endif
}
#ifdef QT_MITSHM_CONVERSIONS
if( mitshm_ximage || mitshm_aximage )
XSync( x11Display(), False ); // wait until processed
#endif
if ( data->optim != BestOptim ) { // throw away image
#ifdef QT_MITSHM_CONVERSIONS
if( mitshm_ximage )
qt_XShmDestroyImage( xi, &shminfo );
else
#endif
qSafeXDestroyImage( xi );
data->ximage = 0;
} else { // keep ximage that we created
#ifdef QT_MITSHM_CONVERSIONS
if( mitshm_ximage ) { // copy the XImage?
qt_XShmDestroyImage( xi, &shminfo );
xi = 0;
}
#endif
data->ximage = xi;
}
if( axi ) {
#ifdef QT_MITSHM_CONVERSIONS
if( mitshm_aximage )
qt_XShmDestroyImage( axi, &ashminfo );
else
#endif
qSafeXDestroyImage(axi);
}
return *data;
}