summaryrefslogtreecommitdiffstats
path: root/tdefx/kpixmap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tdefx/kpixmap.cpp')
-rw-r--r--tdefx/kpixmap.cpp389
1 files changed, 389 insertions, 0 deletions
diff --git a/tdefx/kpixmap.cpp b/tdefx/kpixmap.cpp
new file mode 100644
index 000000000..152ae6e83
--- /dev/null
+++ b/tdefx/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 <tqpixmap.h>
+#include <tqpainter.h>
+#include <tqimage.h>
+#include <tqbitmap.h>
+#include <tqcolor.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 TQImage *src, TQImage *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),
+ tqRgb( 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 = (TQImage::systemBitOrder() == TQImage::BigEndian);
+ int x;
+ uchar* q = const_cast<TQImage*>(src)->scanLine(y);
+ uchar* q2 = const_cast<TQImage*>(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 TQString& fileName, const char *format,
+ int conversion_flags )
+{
+ TQImageIO io( fileName, format );
+
+ bool result = io.read();
+
+ if ( result ) {
+ detach();
+ result = convertFromImage( io.image(), conversion_flags );
+ }
+ return result;
+}
+
+bool KPixmap::load( const TQString& 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 TQImage &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 TQImage &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 TQPixmap::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 TQPixmap::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 TQPixmap::convertFromImage( img, TQPixmap::Auto );
+ }
+
+ TQBitmap mask;
+ bool isMask = false;
+
+ TQImage image = img.convertDepth(32);
+ TQImage 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( TQPixmap::convertFromImage( tImage ) ) {
+ if ( isMask ) TQPixmap::setMask( mask );
+ return true;
+ } else
+ return false;
+ } else {
+ TQImage image = img.convertDepth( 32 );
+ image.setAlphaBuffer( img.hasAlphaBuffer() );
+ conversion_flags = (conversion_flags & ~ColorMode_Mask) | Auto;
+ return TQPixmap::convertFromImage ( image, conversion_flags );
+ }
+}
+
+static TQColor* kpixmap_iconPalette = 0;
+
+bool KPixmap::checkColorTable( const TQImage &image )
+{
+ int i = 0;
+
+ if (kpixmap_iconPalette == 0) {
+ kpixmap_iconPalette = new TQColor[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++] = TQColor( 255, 192, 192 );
+ kpixmap_iconPalette[i++] = TQColor( 192, 255, 192 );
+ kpixmap_iconPalette[i++] = TQColor( 192, 192, 255 );
+ kpixmap_iconPalette[i++] = TQColor( 255, 255, 192 );
+ kpixmap_iconPalette[i++] = TQColor( 255, 192, 255 );
+ kpixmap_iconPalette[i++] = TQColor( 192, 255, 255 );
+
+ // Reds
+ kpixmap_iconPalette[i++] = TQColor( 64, 0, 0 );
+ kpixmap_iconPalette[i++] = TQColor( 192, 0, 0 );
+
+ // Oranges
+ kpixmap_iconPalette[i++] = TQColor( 255, 128, 0 );
+ kpixmap_iconPalette[i++] = TQColor( 192, 88, 0 );
+ kpixmap_iconPalette[i++] = TQColor( 255, 168, 88 );
+ kpixmap_iconPalette[i++] = TQColor( 255, 220, 168 );
+
+ // Blues
+ kpixmap_iconPalette[i++] = TQColor( 0, 0, 192 );
+
+ // Turquoise
+ kpixmap_iconPalette[i++] = TQColor( 0, 64, 64 );
+ kpixmap_iconPalette[i++] = TQColor( 0, 192, 192 );
+
+ // Yellows
+ kpixmap_iconPalette[i++] = TQColor( 64, 64, 0 );
+ kpixmap_iconPalette[i++] = TQColor( 192, 192, 0 );
+
+ // Greens
+ kpixmap_iconPalette[i++] = TQColor( 0, 64, 0 );
+ kpixmap_iconPalette[i++] = TQColor( 0, 192, 0 );
+
+ // Purples
+ kpixmap_iconPalette[i++] = TQColor( 192, 0, 192 );
+
+ // Greys
+ kpixmap_iconPalette[i++] = TQColor( 88, 88, 88 );
+ kpixmap_iconPalette[i++] = TQColor( 48, 48, 48 );
+ kpixmap_iconPalette[i++] = TQColor( 220, 220, 220 );
+
+ }
+
+ QRgb* ctable = image.tqcolorTable();
+
+ 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() == tqRed( ctable[i] ) &&
+ kpixmap_iconPalette[j].green() == tqGreen( ctable[i] ) &&
+ kpixmap_iconPalette[j].blue() == tqBlue( ctable[i] ) ) {
+ break;
+ }
+ }
+
+ if ( j == 40 ) {
+ failures ++;
+ }
+ }
+
+ return ( failures <= 1 );
+
+}
+
+KPixmap::KPixmap(const TQPixmap& p)
+ : TQPixmap(p)
+{
+}