kdefx Library API Documentation

kpixmap.cpp

00001 /* 00002 * This file is part of the KDE libraries 00003 * Copyright (C) 1998 Mark Donohoe <donohoe@kde.org> 00004 * Stephan Kulow <coolo@kde.org> 00005 * 00006 * $Id: kpixmap.cpp,v 1.43 2003/10/07 22:40:42 mueller Exp $ 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Library General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Library General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Library General Public License 00019 * along with this library; see the file COPYING.LIB. If not, write to 00020 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00021 * Boston, MA 02111-1307, USA. 00022 */ 00023 00024 #include <qpixmap.h> 00025 #include <qpainter.h> 00026 #include <qimage.h> 00027 #include <qbitmap.h> 00028 #include <qcolor.h> 00029 00030 #include <stdlib.h> 00031 #include "kpixmap.h" 00032 00033 // Fast diffuse dither to 3x3x3 color cube 00034 // Based on Qt's image conversion functions 00035 static bool kdither_32_to_8( const QImage *src, QImage *dst ) 00036 { 00037 // register QRgb *p; 00038 uchar *b; 00039 int y; 00040 00041 if ( !dst->create(src->width(), src->height(), 8, 256) ) { 00042 qWarning("KPixmap: destination image not valid\n"); 00043 return false; 00044 } 00045 00046 int ncols = 256; 00047 00048 static uint bm[16][16]; 00049 static int init=0; 00050 if (!init) { 00051 00052 // Build a Bayer Matrix for dithering 00053 init = 1; 00054 int n, i, j; 00055 00056 bm[0][0]=0; 00057 00058 for (n=1; n<16; n*=2) 00059 for (i=0; i<n; i++) 00060 for (j=0; j<n; j++) { 00061 bm[i][j]*=4; 00062 bm[i+n][j]=bm[i][j]+2; 00063 bm[i][j+n]=bm[i][j]+3; 00064 bm[i+n][j+n]=bm[i][j]+1; 00065 } 00066 00067 for (i=0; i<16; i++) 00068 for (j=0; j<16; j++) 00069 bm[i][j]<<=8; 00070 } 00071 00072 dst->setNumColors( ncols ); 00073 00074 #define MAX_R 2 00075 #define MAX_G 2 00076 #define MAX_B 2 00077 #define INDEXOF(r,g,b) (((r)*(MAX_G+1)+(g))*(MAX_B+1)+(b)) 00078 00079 int rc, gc, bc; 00080 00081 for ( rc=0; rc<=MAX_R; rc++ ) // build 2x2x2 color cube 00082 for ( gc=0; gc<=MAX_G; gc++ ) 00083 for ( bc=0; bc<=MAX_B; bc++ ) { 00084 dst->setColor( INDEXOF(rc,gc,bc), 00085 qRgb( rc*255/MAX_R, gc*255/MAX_G, bc*255/MAX_B ) ); 00086 } 00087 00088 int sw = src->width(); 00089 int* line1[3]; 00090 int* line2[3]; 00091 int* pv[3]; 00092 00093 line1[0] = new int[src->width()]; 00094 line2[0] = new int[src->width()]; 00095 line1[1] = new int[src->width()]; 00096 line2[1] = new int[src->width()]; 00097 line1[2] = new int[src->width()]; 00098 line2[2] = new int[src->width()]; 00099 pv[0] = new int[sw]; 00100 pv[1] = new int[sw]; 00101 pv[2] = new int[sw]; 00102 00103 for ( y=0; y < src->height(); y++ ) { 00104 // p = (QRgb *)src->scanLine(y); 00105 b = dst->scanLine(y); 00106 int endian = (QImage::systemBitOrder() == QImage::BigEndian); 00107 int x; 00108 uchar* q = src->scanLine(y); 00109 uchar* q2 = src->scanLine(y+1 < src->height() ? y + 1 : 0); 00110 00111 for (int chan = 0; chan < 3; chan++) { 00112 b = dst->scanLine(y); 00113 int *l1 = (y&1) ? line2[chan] : line1[chan]; 00114 int *l2 = (y&1) ? line1[chan] : line2[chan]; 00115 if ( y == 0 ) { 00116 for (int i=0; i<sw; i++) 00117 l1[i] = q[i*4+chan+endian]; 00118 } 00119 if ( y+1 < src->height() ) { 00120 for (int i=0; i<sw; i++) 00121 l2[i] = q2[i*4+chan+endian]; 00122 } 00123 00124 // Bi-directional error diffusion 00125 if ( y&1 ) { 00126 for (x=0; x<sw; x++) { 00127 int pix = QMAX(QMIN(2, (l1[x] * 2 + 128)/ 255), 0); 00128 int err = l1[x] - pix * 255 / 2; 00129 pv[chan][x] = pix; 00130 00131 // Spread the error around... 00132 if ( x+1<sw ) { 00133 l1[x+1] += (err*7)>>4; 00134 l2[x+1] += err>>4; 00135 } 00136 l2[x]+=(err*5)>>4; 00137 if (x>1) 00138 l2[x-1]+=(err*3)>>4; 00139 } 00140 } else { 00141 for (x=sw; x-->0; ) { 00142 int pix = QMAX(QMIN(2, (l1[x] * 2 + 128)/ 255), 0); 00143 int err = l1[x] - pix * 255 / 2; 00144 pv[chan][x] = pix; 00145 00146 // Spread the error around... 00147 if ( x > 0 ) { 00148 l1[x-1] += (err*7)>>4; 00149 l2[x-1] += err>>4; 00150 } 00151 l2[x]+=(err*5)>>4; 00152 if (x+1 < sw) 00153 l2[x+1]+=(err*3)>>4; 00154 } 00155 } 00156 } 00157 00158 if (!endian) { 00159 for (x=0; x<sw; x++) 00160 *b++ = INDEXOF(pv[2][x],pv[1][x],pv[0][x]); 00161 } else { 00162 for (x=0; x<sw; x++) 00163 *b++ = INDEXOF(pv[0][x],pv[1][x],pv[2][x]); 00164 } 00165 00166 } 00167 00168 delete [] line1[0]; 00169 delete [] line2[0]; 00170 delete [] line1[1]; 00171 delete [] line2[1]; 00172 delete [] line1[2]; 00173 delete [] line2[2]; 00174 delete [] pv[0]; 00175 delete [] pv[1]; 00176 delete [] pv[2]; 00177 00178 #undef MAX_R 00179 #undef MAX_G 00180 #undef MAX_B 00181 #undef INDEXOF 00182 00183 return true; 00184 } 00185 00186 KPixmap::~KPixmap() 00187 { 00188 } 00189 00190 bool KPixmap::load( const QString& fileName, const char *format, 00191 int conversion_flags ) 00192 { 00193 QImageIO io( fileName, format ); 00194 00195 bool result = io.read(); 00196 00197 if ( result ) { 00198 detach(); 00199 result = convertFromImage( io.image(), conversion_flags ); 00200 } 00201 return result; 00202 } 00203 00204 bool KPixmap::load( const QString& fileName, const char *format, 00205 ColorMode mode ) 00206 { 00207 int conversion_flags = 0; 00208 switch (mode) { 00209 case Color: 00210 conversion_flags |= ColorOnly; 00211 break; 00212 case Mono: 00213 conversion_flags |= MonoOnly; 00214 break; 00215 case LowColor: 00216 conversion_flags |= LowOnly; 00217 break; 00218 case WebColor: 00219 conversion_flags |= WebOnly; 00220 break; 00221 default: 00222 break;// Nothing. 00223 } 00224 return load( fileName, format, conversion_flags ); 00225 } 00226 00227 bool KPixmap::convertFromImage( const QImage &img, ColorMode mode ) 00228 { 00229 int conversion_flags = 0; 00230 switch (mode) { 00231 case Color: 00232 conversion_flags |= ColorOnly; 00233 break; 00234 case Mono: 00235 conversion_flags |= MonoOnly; 00236 break; 00237 case LowColor: 00238 conversion_flags |= LowOnly; 00239 break; 00240 case WebColor: 00241 conversion_flags |= WebOnly; 00242 break; 00243 default: 00244 break; // Nothing. 00245 } 00246 return convertFromImage( img, conversion_flags ); 00247 } 00248 00249 bool KPixmap::convertFromImage( const QImage &img, int conversion_flags ) 00250 { 00251 if ( img.isNull() ) { 00252 #if defined(CHECK_NULL) 00253 qWarning( "KPixmap::convertFromImage: Cannot convert a null image" ); 00254 #endif 00255 return false; 00256 } 00257 detach(); // detach other references 00258 00259 int dd = defaultDepth(); 00260 00261 // If color mode not one of KPixmaps extra modes nothing to do 00262 if ( ( conversion_flags & KColorMode_Mask ) != LowOnly && 00263 ( conversion_flags & KColorMode_Mask ) != WebOnly ) { 00264 return QPixmap::convertFromImage ( img, conversion_flags ); 00265 } 00266 00267 // If the default pixmap depth is not 8bpp, KPixmap color modes have no 00268 // effect. Ignore them and use AutoColor instead. 00269 if ( dd > 8 ) { 00270 if ( ( conversion_flags & KColorMode_Mask ) == LowOnly || 00271 ( conversion_flags & KColorMode_Mask ) == WebOnly ) 00272 conversion_flags = (conversion_flags & ~KColorMode_Mask) | Auto; 00273 return QPixmap::convertFromImage ( img, conversion_flags ); 00274 } 00275 00276 if ( ( conversion_flags & KColorMode_Mask ) == LowOnly ) { 00277 // Here we skimp a little on the possible conversion modes 00278 // Don't offer ordered or threshold dither of RGB channels or 00279 // diffuse or ordered dither of alpha channel. It hardly seems 00280 // worth the effort for this specialized mode. 00281 00282 // If image uses icon palette don't dither it. 00283 if( img.numColors() > 0 && img.numColors() <=40 ) { 00284 if ( checkColorTable( img ) ) 00285 return QPixmap::convertFromImage( img, QPixmap::Auto ); 00286 } 00287 00288 QBitmap mask; 00289 bool isMask = false; 00290 00291 QImage image = img.convertDepth(32); 00292 QImage tImage( image.width(), image.height(), 8, 256 ); 00293 00294 if( img.hasAlphaBuffer() ) { 00295 image.setAlphaBuffer( true ); 00296 tImage.setAlphaBuffer( true ); 00297 isMask = mask.convertFromImage( img.createAlphaMask() ); 00298 } 00299 00300 kdither_32_to_8( &image, &tImage ); 00301 00302 if( QPixmap::convertFromImage( tImage ) ) { 00303 if ( isMask ) QPixmap::setMask( mask ); 00304 return true; 00305 } else 00306 return false; 00307 } else { 00308 QImage image = img.convertDepth( 32 ); 00309 image.setAlphaBuffer( img.hasAlphaBuffer() ); 00310 conversion_flags = (conversion_flags & ~ColorMode_Mask) | Auto; 00311 return QPixmap::convertFromImage ( image, conversion_flags ); 00312 } 00313 } 00314 00315 static QColor* kpixmap_iconPalette = 0; 00316 00317 bool KPixmap::checkColorTable( const QImage &image ) 00318 { 00319 int i = 0; 00320 00321 if (kpixmap_iconPalette == 0) { 00322 kpixmap_iconPalette = new QColor[40]; 00323 00324 // Standard palette 00325 kpixmap_iconPalette[i++] = red; 00326 kpixmap_iconPalette[i++] = green; 00327 kpixmap_iconPalette[i++] = blue; 00328 kpixmap_iconPalette[i++] = cyan; 00329 kpixmap_iconPalette[i++] = magenta; 00330 kpixmap_iconPalette[i++] = yellow; 00331 kpixmap_iconPalette[i++] = darkRed; 00332 kpixmap_iconPalette[i++] = darkGreen; 00333 kpixmap_iconPalette[i++] = darkBlue; 00334 kpixmap_iconPalette[i++] = darkCyan; 00335 kpixmap_iconPalette[i++] = darkMagenta; 00336 kpixmap_iconPalette[i++] = darkYellow; 00337 kpixmap_iconPalette[i++] = white; 00338 kpixmap_iconPalette[i++] = lightGray; 00339 kpixmap_iconPalette[i++] = gray; 00340 kpixmap_iconPalette[i++] = darkGray; 00341 kpixmap_iconPalette[i++] = black; 00342 00343 // Pastels 00344 kpixmap_iconPalette[i++] = QColor( 255, 192, 192 ); 00345 kpixmap_iconPalette[i++] = QColor( 192, 255, 192 ); 00346 kpixmap_iconPalette[i++] = QColor( 192, 192, 255 ); 00347 kpixmap_iconPalette[i++] = QColor( 255, 255, 192 ); 00348 kpixmap_iconPalette[i++] = QColor( 255, 192, 255 ); 00349 kpixmap_iconPalette[i++] = QColor( 192, 255, 255 ); 00350 00351 // Reds 00352 kpixmap_iconPalette[i++] = QColor( 64, 0, 0 ); 00353 kpixmap_iconPalette[i++] = QColor( 192, 0, 0 ); 00354 00355 // Oranges 00356 kpixmap_iconPalette[i++] = QColor( 255, 128, 0 ); 00357 kpixmap_iconPalette[i++] = QColor( 192, 88, 0 ); 00358 kpixmap_iconPalette[i++] = QColor( 255, 168, 88 ); 00359 kpixmap_iconPalette[i++] = QColor( 255, 220, 168 ); 00360 00361 // Blues 00362 kpixmap_iconPalette[i++] = QColor( 0, 0, 192 ); 00363 00364 // Turquoise 00365 kpixmap_iconPalette[i++] = QColor( 0, 64, 64 ); 00366 kpixmap_iconPalette[i++] = QColor( 0, 192, 192 ); 00367 00368 // Yellows 00369 kpixmap_iconPalette[i++] = QColor( 64, 64, 0 ); 00370 kpixmap_iconPalette[i++] = QColor( 192, 192, 0 ); 00371 00372 // Greens 00373 kpixmap_iconPalette[i++] = QColor( 0, 64, 0 ); 00374 kpixmap_iconPalette[i++] = QColor( 0, 192, 0 ); 00375 00376 // Purples 00377 kpixmap_iconPalette[i++] = QColor( 192, 0, 192 ); 00378 00379 // Greys 00380 kpixmap_iconPalette[i++] = QColor( 88, 88, 88 ); 00381 kpixmap_iconPalette[i++] = QColor( 48, 48, 48 ); 00382 kpixmap_iconPalette[i++] = QColor( 220, 220, 220 ); 00383 00384 } 00385 00386 QRgb* ctable = image.colorTable(); 00387 00388 int ncols = image.numColors(); 00389 int j; 00390 00391 // Allow one failure which could be transparent background 00392 int failures = 0; 00393 00394 for ( i=0; i<ncols; i++ ) { 00395 for ( j=0; j<40; j++ ) { 00396 if ( kpixmap_iconPalette[j].red() == qRed( ctable[i] ) && 00397 kpixmap_iconPalette[j].green() == qGreen( ctable[i] ) && 00398 kpixmap_iconPalette[j].blue() == qBlue( ctable[i] ) ) { 00399 break; 00400 } 00401 } 00402 00403 if ( j == 40 ) { 00404 failures ++; 00405 } 00406 } 00407 00408 return ( failures <= 1 ); 00409 00410 } 00411 00412 KPixmap::KPixmap(const QPixmap& p) 00413 : QPixmap(p) 00414 { 00415 }
KDE Logo
This file is part of the documentation for kdefx Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Aug 30 22:53:16 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003