kpixmap.cpp Source File (kdefx Library)

| # kdefx Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# 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 }

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:44:24 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001