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.41 2001/11/21 12:14:36 faure 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 
00187 bool KPixmap::load( const QString& fileName, const char *format,
00188             int conversion_flags )
00189 {
00190     QImageIO io( fileName, format );
00191 
00192     bool result = io.read();
00193     
00194     if ( result ) {
00195     detach();
00196     result = convertFromImage( io.image(), conversion_flags );
00197     }
00198     return result;
00199 }
00200 
00201 bool KPixmap::load( const QString& fileName, const char *format,
00202             ColorMode mode )
00203 {
00204     int conversion_flags = 0;
00205     switch (mode) {
00206     case Color:
00207     conversion_flags |= ColorOnly;
00208     break;
00209     case Mono:
00210     conversion_flags |= MonoOnly;
00211     break;
00212     case LowColor:
00213     conversion_flags |= LowOnly;
00214     break;
00215     case WebColor:
00216     conversion_flags |= WebOnly;
00217     break;
00218     default:
00219     break;// Nothing.
00220     }
00221     return load( fileName, format, conversion_flags );
00222 }
00223 
00224 bool KPixmap::convertFromImage( const QImage &img, ColorMode mode )
00225 {
00226     int conversion_flags = 0;
00227     switch (mode) {
00228     case Color:
00229     conversion_flags |= ColorOnly;
00230     break;
00231     case Mono:
00232     conversion_flags |= MonoOnly;
00233     break;
00234     case LowColor:
00235     conversion_flags |= LowOnly;
00236     break;
00237     case WebColor:
00238     conversion_flags |= WebOnly;
00239     break;
00240     default:
00241     break;  // Nothing.
00242     }
00243     return convertFromImage( img, conversion_flags );
00244 }
00245 
00246 bool KPixmap::convertFromImage( const QImage &img, int conversion_flags  )
00247 {
00248     if ( img.isNull() ) {
00249 #if defined(CHECK_NULL)
00250     qWarning( "KPixmap::convertFromImage: Cannot convert a null image" );
00251 #endif
00252     return false;
00253     }
00254     detach();                   // detach other references
00255     
00256     int dd = defaultDepth();
00257 
00258     // If color mode not one of KPixmaps extra modes nothing to do
00259     if ( ( conversion_flags & KColorMode_Mask ) != LowOnly &&
00260      ( conversion_flags & KColorMode_Mask ) != WebOnly ) {
00261         return QPixmap::convertFromImage ( img, conversion_flags );
00262     }
00263 
00264     // If the default pixmap depth is not 8bpp, KPixmap color modes have no
00265     // effect. Ignore them and use AutoColor instead.
00266     if ( dd > 8 ) {
00267     if ( ( conversion_flags & KColorMode_Mask ) == LowOnly ||
00268          ( conversion_flags & KColorMode_Mask ) == WebOnly )
00269         conversion_flags = (conversion_flags & ~KColorMode_Mask) | Auto;
00270     return QPixmap::convertFromImage ( img, conversion_flags );
00271     }
00272     
00273     if ( ( conversion_flags & KColorMode_Mask ) == LowOnly ) {
00274     // Here we skimp a little on the possible conversion modes
00275     // Don't offer ordered or threshold dither of RGB channels or
00276     // diffuse or ordered dither of alpha channel. It hardly seems
00277     // worth the effort for this specialised mode.
00278     
00279     // If image uses icon palette don't dither it.
00280     if( img.numColors() > 0 && img.numColors() <=40 ) {
00281         if ( checkColorTable( img ) )
00282         return QPixmap::convertFromImage( img, QPixmap::Auto );
00283     }
00284     
00285     QBitmap mask;
00286     bool isMask = false;
00287 
00288     QImage  image = img.convertDepth(32);
00289     QImage tImage( image.width(), image.height(), 8, 256 );
00290     
00291     if( img.hasAlphaBuffer() ) {
00292         image.setAlphaBuffer( true );
00293         tImage.setAlphaBuffer( true );
00294         isMask = mask.convertFromImage( img.createAlphaMask() );
00295     }
00296     
00297     kdither_32_to_8( &image, &tImage );
00298         
00299     if( QPixmap::convertFromImage( tImage ) ) {
00300         if ( isMask ) QPixmap::setMask( mask );
00301         return true;
00302     } else
00303         return false;
00304     } else {
00305     QImage  image = img.convertDepth( 32 );
00306     image.setAlphaBuffer( img.hasAlphaBuffer() );
00307     conversion_flags = (conversion_flags & ~ColorMode_Mask) | Auto;
00308     return QPixmap::convertFromImage ( image, conversion_flags );
00309     }
00310 }
00311 
00312 static QColor* kpixmap_iconPalette = 0;
00313 
00314 bool KPixmap::checkColorTable( const QImage &image )
00315 {
00316     int i = 0;
00317 
00318     if (kpixmap_iconPalette == 0) {
00319     kpixmap_iconPalette = new QColor[40];
00320     
00321     // Standard palette
00322     kpixmap_iconPalette[i++] = red;
00323     kpixmap_iconPalette[i++] = green;
00324     kpixmap_iconPalette[i++] = blue;
00325     kpixmap_iconPalette[i++] = cyan;
00326     kpixmap_iconPalette[i++] = magenta;
00327     kpixmap_iconPalette[i++] = yellow;
00328     kpixmap_iconPalette[i++] = darkRed;
00329     kpixmap_iconPalette[i++] = darkGreen;
00330     kpixmap_iconPalette[i++] = darkBlue;
00331     kpixmap_iconPalette[i++] = darkCyan;
00332     kpixmap_iconPalette[i++] = darkMagenta;
00333     kpixmap_iconPalette[i++] = darkYellow;
00334     kpixmap_iconPalette[i++] = white;
00335     kpixmap_iconPalette[i++] = lightGray;
00336     kpixmap_iconPalette[i++] = gray;
00337     kpixmap_iconPalette[i++] = darkGray;
00338     kpixmap_iconPalette[i++] = black;
00339     
00340     // Pastels
00341     kpixmap_iconPalette[i++] = QColor( 255, 192, 192 );
00342     kpixmap_iconPalette[i++] = QColor( 192, 255, 192 );
00343     kpixmap_iconPalette[i++] = QColor( 192, 192, 255 );
00344     kpixmap_iconPalette[i++] = QColor( 255, 255, 192 );
00345     kpixmap_iconPalette[i++] = QColor( 255, 192, 255 );
00346     kpixmap_iconPalette[i++] = QColor( 192, 255, 255 );
00347 
00348     // Reds
00349     kpixmap_iconPalette[i++] = QColor( 64,   0,   0 );
00350     kpixmap_iconPalette[i++] = QColor( 192,  0,   0 );
00351 
00352     // Oranges
00353     kpixmap_iconPalette[i++] = QColor( 255, 128,   0 );
00354     kpixmap_iconPalette[i++] = QColor( 192,  88,   0 );
00355     kpixmap_iconPalette[i++] = QColor( 255, 168,  88 );
00356     kpixmap_iconPalette[i++] = QColor( 255, 220, 168 );
00357 
00358     // Blues
00359     kpixmap_iconPalette[i++] = QColor(   0,   0, 192 );
00360 
00361     // Turquoise
00362     kpixmap_iconPalette[i++] = QColor(   0,  64,  64 );
00363     kpixmap_iconPalette[i++] = QColor(   0, 192, 192 );
00364 
00365     // Yellows
00366     kpixmap_iconPalette[i++] = QColor(  64,  64,   0 );
00367     kpixmap_iconPalette[i++] = QColor( 192, 192,   0 );
00368 
00369     // Greens
00370     kpixmap_iconPalette[i++] = QColor(   0,  64,   0 );
00371     kpixmap_iconPalette[i++] = QColor(   0, 192,   0 );
00372 
00373     // Purples
00374     kpixmap_iconPalette[i++] = QColor( 192,   0, 192 );
00375 
00376     // Greys
00377     kpixmap_iconPalette[i++] = QColor(  88,  88,  88 );
00378     kpixmap_iconPalette[i++] = QColor(  48,  48,  48 );
00379     kpixmap_iconPalette[i++] = QColor( 220, 220, 220 );
00380     
00381     }
00382 
00383     QRgb* ctable = image.colorTable();
00384 
00385     int ncols = image.numColors();
00386     int j;
00387 
00388     // Allow one failure which could be transparent background
00389     int failures = 0;
00390 
00391     for ( i=0; i<ncols; i++ ) {
00392     for ( j=0; j<40; j++ ) {
00393         if ( kpixmap_iconPalette[j].red() == qRed( ctable[i] ) &&
00394          kpixmap_iconPalette[j].green() == qGreen( ctable[i] ) &&
00395          kpixmap_iconPalette[j].blue() == qBlue( ctable[i] ) ) {
00396         break;
00397         }
00398     }
00399     
00400     if ( j == 40 ) {
00401         failures ++;            
00402     }
00403     }
00404 
00405     return ( failures <= 1 );
00406 
00407 }
00408 
00409 KPixmap::KPixmap(const QPixmap& p)
00410     : QPixmap(p)
00411 {
00412 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:14:38 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001