📄 kpixmap.cpp
字号:
/* This file is part of the KDE libraries Copyright (C) 1998 Mark Donohoe <donohoe@kde.org> Stephan Kulow 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#include <qpixmap.h>#include <qpainter.h>#include <qimage.h>#include <qbitmap.h>#include <qcolor.h>#include <kapp.h>#include <dither.h>#include "kpixmap.h"// Fast diffuse dither to 3x3x3 color cube// Based on Qt's image conversion functionsstatic bool kdither_32_to_8( const QImage *src, QImage *dst ){ register QRgb *p; uchar *b; int y; //printf("kconvert_32_to_8\n"); if ( !dst->create(src->width(), src->height(), 8, 256) ) { warning("KPixmap: destination image not valid\n"); return FALSE; } int ncols = 256; static uint bm[16][16]; static int init=0; if (!init) { // Build a Bayer Matrix for dithering init = 1; int n, i, j; bm[0][0]=0; for (n=1; n<16; n*=2) { for (i=0; i<n; i++) { for (j=0; j<n; j++) { bm[i][j]*=4; bm[i+n][j]=bm[i][j]+2; bm[i][j+n]=bm[i][j]+3; bm[i+n][j+n]=bm[i][j]+1; } } } for (i=0; i<16; i++) for (j=0; j<16; j++) bm[i][j]<<=8; } dst->setNumColors( ncols );#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::systemByteOrder() == 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;}void KPixmap::gradientFill( QColor ca, QColor cb, bool upDown, int ncols ){ QPixmap pmCrop; QColor cRow; int ySize; int rca, gca, bca; int rDiff, gDiff, bDiff; float rat; uint *p; uint rgbRow; if( upDown ) ySize = height(); else ySize = width(); pmCrop.resize( 30, ySize ); QImage image( 30, ySize, 32 ); rca = ca.red(); gca = ca.green(); bca = ca.blue(); rDiff = cb.red() - ca.red(); gDiff = cb.green() - ca.green(); bDiff = cb.blue() - ca.blue(); for ( int y = ySize - 1; y >= 0; y-- ) { p = (uint *) image.scanLine( ySize - y - 1 ); rat = 1.0 * y / ySize; cRow.setRgb( rca + (int) ( rDiff * rat ), gca + (int) ( gDiff * rat ), bca + (int) ( bDiff * rat ) ); rgbRow = cRow.rgb(); for( int x = 0; x < 30; x++ ) { *p = rgbRow; p++; } } if ( depth() <= 16 ) { if( depth() == 16 ) ncols = 32; if ( ncols < 2 || ncols > 256 ) ncols = 3; QColor *dPal = new QColor[ncols]; for ( int i=0; i<ncols; i++) { dPal[i].setRgb ( rca + rDiff * i / ( ncols - 1 ), gca + gDiff * i / ( ncols - 1 ), bca + bDiff * i / ( ncols - 1 ) ); } kFSDither dither( dPal, ncols ); QImage dImage = dither.dither( image ); pmCrop.convertFromImage( dImage ); delete [] dPal; } else pmCrop.convertFromImage( image ); // Copy the cropped pixmap into the KPixmap. // Extract only a central column from the cropped pixmap // to avoid edge effects. int s; int sSize = 20; int sOffset = 5; if( upDown ) s = width() / sSize + 1; else s = height() / sSize + 1; QPainter paint; paint.begin( this ); if ( upDown ) for( int i=0; i<s; i++ ) paint.drawPixmap( sSize*i, 0, pmCrop, sOffset, 0 , sSize, ySize ); else { QWMatrix matrix; matrix.translate( (float) width() - 1.0, 0.0 ); matrix.rotate( 90.0 ); paint.setWorldMatrix( matrix ); for( int i=0; i<s; i++) paint.drawPixmap( sSize*i, 0, pmCrop, sOffset, 0 , sSize, ySize ); } paint.end();}void KPixmap::patternFill( QColor ca, QColor cb, uint pattern[8] ){ QPixmap tile( 8, 8 ); tile.fill( cb ); QPainter pt; pt.begin( &tile ); pt.setBackgroundColor( cb ); pt.setPen( ca ); for ( int y = 0; y < 8; y++ ) { uint v = pattern[y]; for ( int x = 0; x < 8; x++ ) { if ( v & 1 ) pt.drawPoint( 7 - x, y ); v /= 2; } } pt.end(); int sx, sy = 0; while ( sy < height() ) { sx = 0; while (sx < width()) { bitBlt( this, sx, sy, &tile, 0, 0, 8, 8 ); sx += 8; } sy += 8; }}bool KPixmap::load( const char *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 char *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) warning( "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 specialised 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 ++; } } if( failures > 1 ) return FALSE; else return TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -