1
/* This file is based on qt-3.3.2/src/qimage.cpp , plus it includes
2
* a fix from qt-bugs@ issue #49934. Original copyright follows.
4
/****************************************************************************
7
** Implementation of QImage and QImageIO classes
11
** Copyright (C) 1992-2003 Trolltech AS. All rights reserved.
13
** This file is part of the kernel module of the Qt GUI Toolkit.
15
** This file may be distributed under the terms of the Q Public License
16
** as defined by Trolltech AS of Norway and appearing in the file
17
** LICENSE.QPL included in the packaging of this file.
19
** This file may be distributed and/or modified under the terms of the
20
** GNU General Public License version 2 as published by the Free Software
21
** Foundation and appearing in the file LICENSE.GPL included in the
22
** packaging of this file.
24
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
25
** licenses may use this file in accordance with the Qt Commercial License
26
** Agreement provided with the Software.
28
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
32
** information about Qt Commercial License Agreements.
33
** See http://www.trolltech.com/qpl/ for QPL licensing information.
34
** See http://www.trolltech.com/gpl/ for GPL licensing information.
36
** Contact info@trolltech.com if any conditions of this licensing are
39
**********************************************************************/
43
This code is xpm loader copied from qimage.cpp, with changes making it
44
possible to use this class from another thread. The problem is that
45
QColor::setNamedColor() isn't reentrant without thread-safe Xlib,
46
i.e. without XInitThreads() called. Current KDE applications
47
don't call XInitThreads(), and since it needs to be the very first
48
Xlib function called, and Gwenview is also a KPart, it's not possible
49
to rely on Xlib being thread-safe.
51
Changes are marked using #ifdef GV_XPM_CHANGES.
55
#define GV_XPM_CHANGES
63
#include "gvthreadgate.h"
66
// Qt code start ---------------------------
67
static QString fbname( const QString &fileName ) // get file basename (sort of)
72
if ( (i = s.findRev('/')) >= 0 )
74
if ( (i = s.findRev('\\')) >= 0 )
76
QRegExp r( QString::fromLatin1("[a-zA-Z][a-zA-Z0-9_]*") );
77
int p = r.search( s );
81
s = s.mid( p, r.matchedLength() );
84
s = QString::fromLatin1( "dummy" );
88
/*****************************************************************************
89
XPM image read/write functions
90
*****************************************************************************/
93
// Skip until ", read until the next ", return the rest in *buf
94
// Returns FALSE on error, TRUE on success
96
static bool read_xpm_string( QCString &buf, QIODevice *d,
97
const char * const *source, int &index )
100
buf = source[index++];
104
if ( buf.size() < 69 ) //# just an approximation
110
while ( (c=d->getch()) != EOF && c != '"' ) { }
115
while ( (c=d->getch()) != EOF && c != '"' ) {
116
if ( i == (int)buf.size() )
117
buf.resize( i*2+42 );
124
if ( i == (int)buf.size() ) // always use a 0 terminator
132
static int nextColorSpec(const QCString & buf)
134
int i = buf.find(" c ");
138
i = buf.find(" g4 ");
149
// Reads an .xpm from either the QImageIO or from the QString *.
150
// One of the two HAS to be 0, the other one is used.
153
static void read_xpm_image_or_array( QImageIO * iio, const char * const * source,
160
int i, cpp, ncols, w, h, index = 0;
164
d = iio ? iio->ioDevice() : 0;
165
d->readLine( buf.data(), buf.size() ); // "/* XPM */"
166
QRegExp r( QString::fromLatin1("/\\*.XPM.\\*/") );
167
if ( buf.find(r) == -1 )
169
} else if ( !source ) {
173
if ( !read_xpm_string( buf, d, source, index ) )
176
if ( sscanf( buf, "%d %d %d %d", &w, &h, &ncols, &cpp ) < 4 )
177
return; // < 4 numbers parsed
183
image.create( w, h, 32 );
185
image.create( w, h, 8, ncols );
191
QMap<QString, int> colorMap;
194
for( currentColor=0; currentColor < ncols; ++currentColor ) {
195
if ( !read_xpm_string( buf, d, source, index ) ) {
196
#if defined(QT_CHECK_RANGE)
197
qWarning( "QImage: XPM color specification missing");
202
index = buf.left( cpp );
203
buf = buf.mid( cpp ).simplifyWhiteSpace().lower();
205
i = nextColorSpec(buf);
207
#if defined(QT_CHECK_RANGE)
208
qWarning( "QImage: XPM color specification is missing: %s", buf.data());
210
return; // no c/g/g4/m/s specification at all
212
buf = buf.mid( i+3 );
213
// Strip any other colorspec
214
int end = nextColorSpec(buf);
217
buf = buf.stripWhiteSpace();
218
if ( buf == "none" ) {
219
image.setAlphaBuffer( TRUE );
220
int transparentColor = currentColor;
221
if ( image.depth() == 8 ) {
222
image.setColor( transparentColor,
223
RGB_MASK & qRgb(198,198,198) );
224
colorMap.insert( index, transparentColor );
226
QRgb rgb = RGB_MASK & qRgb(198,198,198);
227
colorMap.insert( index, rgb );
230
if ( ((buf.length()-1) % 3) && (buf[0] == '#') ) {
231
buf.truncate (((buf.length()-1) / 4 * 3) + 1); // remove alpha channel left by imagemagick
233
#ifdef GV_XPM_CHANGES
234
QColor c = GVThreadGate::instance()->color( buf.data());
236
QColor c( buf.data() );
238
if ( image.depth() == 8 ) {
239
image.setColor( currentColor, 0xff000000 | c.rgb() );
240
colorMap.insert( index, currentColor );
242
QRgb rgb = 0xff000000 | c.rgb();
243
colorMap.insert( index, rgb );
249
for( int y=0; y<h; y++ ) {
250
if ( !read_xpm_string( buf, d, source, index ) ) {
251
#if defined(QT_CHECK_RANGE)
252
qWarning( "QImage: XPM pixels missing on image line %d", y);
256
if ( image.depth() == 8 ) {
257
uchar *p = image.scanLine(y);
258
uchar *d = (uchar *)buf.data();
259
uchar *end = d + buf.length();
264
for ( x=0; x<w && d<end; x++ ) {
266
*p++ = (uchar)colorMap[b];
271
for ( x=0; x<w && d<end; x++ ) {
272
strncpy( b, (char *)d, cpp );
273
*p++ = (uchar)colorMap[b];
278
QRgb *p = (QRgb*)image.scanLine(y);
279
uchar *d = (uchar *)buf.data();
280
uchar *end = d + buf.length();
284
for ( x=0; x<w && d<end; x++ ) {
285
strncpy( b, (char *)d, cpp );
286
*p++ = (QRgb)colorMap[b];
292
iio->setImage( image );
293
iio->setStatus( 0 ); // image ok
298
static void read_xpm_image( QImageIO * iio )
301
(void)read_xpm_image_or_array( iio, 0, i );
306
static const char* xpm_color_name( int cpp, int index )
308
static char returnable[5];
309
static const char code[] = ".#abcdefghijklmnopqrstuvwxyzABCD"
310
"EFGHIJKLMNOPQRSTUVWXYZ0123456789";
311
// cpp is limited to 4 and index is limited to 64^cpp
315
returnable[3] = code[index % 64];
318
returnable[3] = '\0';
319
returnable[2] = code[index % 64];
322
returnable[2] = '\0';
323
// the following 4 lines are a joke!
326
else if ( index == 64*44+21 )
328
returnable[1] = code[index % 64];
331
returnable[1] = '\0';
332
returnable[0] = code[index];
338
// write XPM image data
339
static void write_xpm_image( QImageIO * iio )
346
// ### 8-bit case could be made faster
348
if ( iio->image().depth() != 32 )
349
image = iio->image().convertDepth( 32 );
351
image = iio->image();
353
QMap<QRgb, int> colorMap;
355
int w = image.width(), h = image.height(), ncolors = 0;
359
for( y=0; y<h; y++ ) {
360
QRgb * yp = (QRgb *)image.scanLine( y );
361
for( x=0; x<w; x++ ) {
362
QRgb color = *(yp + x);
363
if ( !colorMap.contains(color) )
364
colorMap.insert( color, ncolors++ );
368
// number of 64-bit characters per pixel needed to encode all colors
370
for ( int k = 64; ncolors > k; k *= 64 ) {
372
// limit to 4 characters per pixel
373
// 64^4 colors is enough for a 4096x4096 image
381
QTextStream s( iio->ioDevice() );
382
s << "/* XPM */" << endl
383
<< "static char *" << fbname(iio->fileName()) << "[]={" << endl
384
<< "\"" << w << " " << h << " " << ncolors << " " << cpp << "\"";
387
QMap<QRgb, int>::Iterator c = colorMap.begin();
388
while ( c != colorMap.end() ) {
389
QRgb color = c.key();
390
if ( image.hasAlphaBuffer() && color == (color & RGB_MASK) )
391
line.sprintf( "\"%s c None\"",
392
xpm_color_name(cpp, *c) );
394
line.sprintf( "\"%s c #%02x%02x%02x\"",
395
xpm_color_name(cpp, *c),
400
s << "," << endl << line;
403
// write pixels, limit to 4 characters per pixel
404
line.truncate( cpp*w );
405
for( y=0; y<h; y++ ) {
406
QRgb * yp = (QRgb *) image.scanLine( y );
408
for( x=0; x<w; x++ ) {
409
int color = (int)(*(yp + x));
410
QCString chars = xpm_color_name( cpp, colorMap[color] );
411
line[cc++] = chars[0];
413
line[cc++] = chars[1];
415
line[cc++] = chars[2];
417
line[cc++] = chars[3];
422
s << "," << endl << "\"" << line << "\"";
429
// Qt code end ---------------------------
433
QImageIO::inputFormats(); // trigger registration of Qt's handlers
434
QImageIO::defineIOHandler( "XPM", "/\\*.XPM.\\*/", "T",
435
read_xpm_image, write_xpm_image );