From ce4a32fe52ef09d8f5ff1dd22c001110902b60a2 Mon Sep 17 00:00:00 2001 From: toma Date: Wed, 25 Nov 2009 17:56:58 +0000 Subject: 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 --- kdefx/kpixmap.cpp | 389 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 kdefx/kpixmap.cpp (limited to 'kdefx/kpixmap.cpp') 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 + * Stephan Kulow + * + * $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 +#include +#include +#include +#include + +#include +#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; iheight() ) { + for (int i=0; i>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 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