diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch) | |
tree | 5ac38a06f3dde268dc7927dc155896926aaf7012 /kdefx/kpixmap.cpp | |
download | tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kdefx/kpixmap.cpp')
-rw-r--r-- | kdefx/kpixmap.cpp | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/kdefx/kpixmap.cpp b/kdefx/kpixmap.cpp new file mode 100644 index 000000000..9d7b186bd --- /dev/null +++ b/kdefx/kpixmap.cpp @@ -0,0 +1,389 @@ +/* + * This file is part of the KDE libraries + * Copyright (C) 1998 Mark Donohoe <donohoe@kde.org> + * Stephan Kulow <coolo@kde.org> + * + * $Id$ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <qpixmap.h> +#include <qpainter.h> +#include <qimage.h> +#include <qbitmap.h> +#include <qcolor.h> + +#include <stdlib.h> +#include "kpixmap.h" + +// Fast diffuse dither to 3x3x3 color cube +// Based on Qt's image conversion functions +static bool kdither_32_to_8( const QImage *src, QImage *dst ) +{ + // register QRgb *p; + uchar *b; + int y; + + if ( !dst->create(src->width(), src->height(), 8, 256) ) { + qWarning("KPixmap: destination image not valid\n"); + return false; + } + + dst->setNumColors( 256 ); + +#define MAX_R 2 +#define MAX_G 2 +#define MAX_B 2 +#define INDEXOF(r,g,b) (((r)*(MAX_G+1)+(g))*(MAX_B+1)+(b)) + + int rc, gc, bc; + + for ( rc=0; rc<=MAX_R; rc++ ) // build 2x2x2 color cube + for ( gc=0; gc<=MAX_G; gc++ ) + for ( bc=0; bc<=MAX_B; bc++ ) { + dst->setColor( INDEXOF(rc,gc,bc), + qRgb( rc*255/MAX_R, gc*255/MAX_G, bc*255/MAX_B ) ); + } + + int sw = src->width(); + int* line1[3]; + int* line2[3]; + int* pv[3]; + + line1[0] = new int[src->width()]; + line2[0] = new int[src->width()]; + line1[1] = new int[src->width()]; + line2[1] = new int[src->width()]; + line1[2] = new int[src->width()]; + line2[2] = new int[src->width()]; + pv[0] = new int[sw]; + pv[1] = new int[sw]; + pv[2] = new int[sw]; + + for ( y=0; y < src->height(); y++ ) { + // p = (QRgb *)src->scanLine(y); + b = dst->scanLine(y); + int endian = (QImage::systemBitOrder() == QImage::BigEndian); + int x; + uchar* q = src->scanLine(y); + uchar* q2 = src->scanLine(y+1 < src->height() ? y + 1 : 0); + + for (int chan = 0; chan < 3; chan++) { + b = dst->scanLine(y); + int *l1 = (y&1) ? line2[chan] : line1[chan]; + int *l2 = (y&1) ? line1[chan] : line2[chan]; + if ( y == 0 ) { + for (int i=0; i<sw; i++) + l1[i] = q[i*4+chan+endian]; + } + if ( y+1 < src->height() ) { + for (int i=0; i<sw; i++) + l2[i] = q2[i*4+chan+endian]; + } + + // Bi-directional error diffusion + if ( y&1 ) { + for (x=0; x<sw; x++) { + int pix = QMAX(QMIN(2, (l1[x] * 2 + 128)/ 255), 0); + int err = l1[x] - pix * 255 / 2; + pv[chan][x] = pix; + + // Spread the error around... + if ( x+1<sw ) { + l1[x+1] += (err*7)>>4; + l2[x+1] += err>>4; + } + l2[x]+=(err*5)>>4; + if (x>1) + l2[x-1]+=(err*3)>>4; + } + } else { + for (x=sw; x-->0; ) { + int pix = QMAX(QMIN(2, (l1[x] * 2 + 128)/ 255), 0); + int err = l1[x] - pix * 255 / 2; + pv[chan][x] = pix; + + // Spread the error around... + if ( x > 0 ) { + l1[x-1] += (err*7)>>4; + l2[x-1] += err>>4; + } + l2[x]+=(err*5)>>4; + if (x+1 < sw) + l2[x+1]+=(err*3)>>4; + } + } + } + + if (!endian) { + for (x=0; x<sw; x++) + *b++ = INDEXOF(pv[2][x],pv[1][x],pv[0][x]); + } else { + for (x=0; x<sw; x++) + *b++ = INDEXOF(pv[0][x],pv[1][x],pv[2][x]); + } + + } + + delete [] line1[0]; + delete [] line2[0]; + delete [] line1[1]; + delete [] line2[1]; + delete [] line1[2]; + delete [] line2[2]; + delete [] pv[0]; + delete [] pv[1]; + delete [] pv[2]; + +#undef MAX_R +#undef MAX_G +#undef MAX_B +#undef INDEXOF + + return true; +} + +KPixmap::~KPixmap() +{ +} + +bool KPixmap::load( const QString& fileName, const char *format, + int conversion_flags ) +{ + QImageIO io( fileName, format ); + + bool result = io.read(); + + if ( result ) { + detach(); + result = convertFromImage( io.image(), conversion_flags ); + } + return result; +} + +bool KPixmap::load( const QString& fileName, const char *format, + ColorMode mode ) +{ + int conversion_flags = 0; + switch (mode) { + case Color: + conversion_flags |= ColorOnly; + break; + case Mono: + conversion_flags |= MonoOnly; + break; + case LowColor: + conversion_flags |= LowOnly; + break; + case WebColor: + conversion_flags |= WebOnly; + break; + default: + break;// Nothing. + } + return load( fileName, format, conversion_flags ); +} + +bool KPixmap::convertFromImage( const QImage &img, ColorMode mode ) +{ + int conversion_flags = 0; + switch (mode) { + case Color: + conversion_flags |= ColorOnly; + break; + case Mono: + conversion_flags |= MonoOnly; + break; + case LowColor: + conversion_flags |= LowOnly; + break; + case WebColor: + conversion_flags |= WebOnly; + break; + default: + break; // Nothing. + } + return convertFromImage( img, conversion_flags ); +} + +bool KPixmap::convertFromImage( const QImage &img, int conversion_flags ) +{ + if ( img.isNull() ) { +#if defined(CHECK_NULL) + qWarning( "KPixmap::convertFromImage: Cannot convert a null image" ); +#endif + return false; + } + detach(); // detach other references + + int dd = defaultDepth(); + + // If color mode not one of KPixmaps extra modes nothing to do + if ( ( conversion_flags & KColorMode_Mask ) != LowOnly && + ( conversion_flags & KColorMode_Mask ) != WebOnly ) { + return QPixmap::convertFromImage ( img, conversion_flags ); + } + + // If the default pixmap depth is not 8bpp, KPixmap color modes have no + // effect. Ignore them and use AutoColor instead. + if ( dd > 8 ) { + if ( ( conversion_flags & KColorMode_Mask ) == LowOnly || + ( conversion_flags & KColorMode_Mask ) == WebOnly ) + conversion_flags = (conversion_flags & ~KColorMode_Mask) | Auto; + return QPixmap::convertFromImage ( img, conversion_flags ); + } + + if ( ( conversion_flags & KColorMode_Mask ) == LowOnly ) { + // Here we skimp a little on the possible conversion modes + // Don't offer ordered or threshold dither of RGB channels or + // diffuse or ordered dither of alpha channel. It hardly seems + // worth the effort for this specialized mode. + + // If image uses icon palette don't dither it. + if( img.numColors() > 0 && img.numColors() <=40 ) { + if ( checkColorTable( img ) ) + return QPixmap::convertFromImage( img, QPixmap::Auto ); + } + + QBitmap mask; + bool isMask = false; + + QImage image = img.convertDepth(32); + QImage tImage( image.width(), image.height(), 8, 256 ); + + if( img.hasAlphaBuffer() ) { + image.setAlphaBuffer( true ); + tImage.setAlphaBuffer( true ); + isMask = mask.convertFromImage( img.createAlphaMask() ); + } + + kdither_32_to_8( &image, &tImage ); + + if( QPixmap::convertFromImage( tImage ) ) { + if ( isMask ) QPixmap::setMask( mask ); + return true; + } else + return false; + } else { + QImage image = img.convertDepth( 32 ); + image.setAlphaBuffer( img.hasAlphaBuffer() ); + conversion_flags = (conversion_flags & ~ColorMode_Mask) | Auto; + return QPixmap::convertFromImage ( image, conversion_flags ); + } +} + +static QColor* kpixmap_iconPalette = 0; + +bool KPixmap::checkColorTable( const QImage &image ) +{ + int i = 0; + + if (kpixmap_iconPalette == 0) { + kpixmap_iconPalette = new QColor[40]; + + // Standard palette + kpixmap_iconPalette[i++] = red; + kpixmap_iconPalette[i++] = green; + kpixmap_iconPalette[i++] = blue; + kpixmap_iconPalette[i++] = cyan; + kpixmap_iconPalette[i++] = magenta; + kpixmap_iconPalette[i++] = yellow; + kpixmap_iconPalette[i++] = darkRed; + kpixmap_iconPalette[i++] = darkGreen; + kpixmap_iconPalette[i++] = darkBlue; + kpixmap_iconPalette[i++] = darkCyan; + kpixmap_iconPalette[i++] = darkMagenta; + kpixmap_iconPalette[i++] = darkYellow; + kpixmap_iconPalette[i++] = white; + kpixmap_iconPalette[i++] = lightGray; + kpixmap_iconPalette[i++] = gray; + kpixmap_iconPalette[i++] = darkGray; + kpixmap_iconPalette[i++] = black; + + // Pastels + kpixmap_iconPalette[i++] = QColor( 255, 192, 192 ); + kpixmap_iconPalette[i++] = QColor( 192, 255, 192 ); + kpixmap_iconPalette[i++] = QColor( 192, 192, 255 ); + kpixmap_iconPalette[i++] = QColor( 255, 255, 192 ); + kpixmap_iconPalette[i++] = QColor( 255, 192, 255 ); + kpixmap_iconPalette[i++] = QColor( 192, 255, 255 ); + + // Reds + kpixmap_iconPalette[i++] = QColor( 64, 0, 0 ); + kpixmap_iconPalette[i++] = QColor( 192, 0, 0 ); + + // Oranges + kpixmap_iconPalette[i++] = QColor( 255, 128, 0 ); + kpixmap_iconPalette[i++] = QColor( 192, 88, 0 ); + kpixmap_iconPalette[i++] = QColor( 255, 168, 88 ); + kpixmap_iconPalette[i++] = QColor( 255, 220, 168 ); + + // Blues + kpixmap_iconPalette[i++] = QColor( 0, 0, 192 ); + + // Turquoise + kpixmap_iconPalette[i++] = QColor( 0, 64, 64 ); + kpixmap_iconPalette[i++] = QColor( 0, 192, 192 ); + + // Yellows + kpixmap_iconPalette[i++] = QColor( 64, 64, 0 ); + kpixmap_iconPalette[i++] = QColor( 192, 192, 0 ); + + // Greens + kpixmap_iconPalette[i++] = QColor( 0, 64, 0 ); + kpixmap_iconPalette[i++] = QColor( 0, 192, 0 ); + + // Purples + kpixmap_iconPalette[i++] = QColor( 192, 0, 192 ); + + // Greys + kpixmap_iconPalette[i++] = QColor( 88, 88, 88 ); + kpixmap_iconPalette[i++] = QColor( 48, 48, 48 ); + kpixmap_iconPalette[i++] = QColor( 220, 220, 220 ); + + } + + QRgb* ctable = image.colorTable(); + + int ncols = image.numColors(); + int j; + + // Allow one failure which could be transparent background + int failures = 0; + + for ( i=0; i<ncols; i++ ) { + for ( j=0; j<40; j++ ) { + if ( kpixmap_iconPalette[j].red() == qRed( ctable[i] ) && + kpixmap_iconPalette[j].green() == qGreen( ctable[i] ) && + kpixmap_iconPalette[j].blue() == qBlue( ctable[i] ) ) { + break; + } + } + + if ( j == 40 ) { + failures ++; + } + } + + return ( failures <= 1 ); + +} + +KPixmap::KPixmap(const QPixmap& p) + : QPixmap(p) +{ +} |