Back to index

scribus-ng  1.3.4.dfsg+svn20071115
colorutil.cpp
Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 /***************************************************************************
00008                           util.cpp  -  description
00009                              -------------------
00010     begin                : Fri Sep 14 2001
00011     copyright            : (C) 2001 by Franz Schmid
00012     email                : Franz.Schmid@altmuehlnet.de
00013  ***************************************************************************/
00014 
00015 /***************************************************************************
00016  *                                                                         *
00017  *   This program is free software; you can redistribute it and/or modify  *
00018  *   it under the terms of the GNU General Public License as published by  *
00019  *   the Free Software Foundation; either version 2 of the License, or     *
00020  *   (at your option) any later version.                                   *
00021  *                                                                         *
00022  ***************************************************************************/
00023 
00024 #include "colorutil.h"
00025 
00026 #include <qbitmap.h>
00027 #include <qdatetime.h> 
00028 #include <qpainter.h>
00029 #include <qcheckbox.h>
00030 // #include <algorithm>
00031 // #include <cstdlib>
00032 // #include <cmath>
00033 
00034 #include "scconfig.h"
00035 
00036 //#ifdef HAVE_UNISTD_H
00037 //#include <unistd.h>
00038 //#endif
00039 
00040 #if defined(_WIN32)
00041 #if defined(_MSC_VER)
00042 #define __STDC__ 1 // hack to get md5_buffer correctly identified
00043 #endif
00044 #include <valarray>
00045 #include <windows.h>
00046 #endif
00047 
00048 #include "md5.h"
00049 
00050 // #include <setjmp.h>
00051 // #include "commonstrings.h"
00052 // #include "pagestructs.h"
00053 // #include "prefsfile.h"
00054 // #include "prefscontext.h"
00055 // #include "prefstable.h"
00056 // #include "prefsmanager.h"
00057 // #include "qprocess.h"
00058 // #include "scmessagebox.h"
00059 #include "scribusdoc.h"
00060 #include "scpixmapcache.h"
00061 #include "commonstrings.h"
00062 // #include "scpaths.h"
00063 // #include "text/nlsconfig.h"
00064 #include "util.h"
00065 #include "sccolorengine.h"
00066 
00067 extern "C"
00068 {
00069 #define XMD_H           // shut JPEGlib up
00070 #if defined(Q_OS_UNIXWARE)
00071 #  define HAVE_BOOLEAN  // libjpeg under Unixware seems to need this
00072 #endif
00073 #include <jpeglib.h>
00074 #include <jerror.h>
00075 #undef HAVE_STDLIB_H
00076 #ifdef const
00077 #  undef const          // remove crazy C hackery in jconfig.h
00078 #endif
00079 }
00080 
00081 #include CMS_INC
00082 using namespace std;
00083 
00084 void handleOldColorShade(ScribusDoc* doc, QString& colName, int& shade)
00085 {
00086        int r, g, b;
00087        bool found = false;
00088        if( colName.isEmpty() || colName == CommonStrings::None || !doc->PageColors.contains(colName))
00089               return;
00090 
00091        const ScColor& scCol1(doc->PageColors[colName]);
00092        
00093        if( (shade == 100) || (scCol1.getColorModel() != colorModelRGB) )
00094               return;
00095        scCol1.getRGB(&r, &g, &b);
00096        QColor col1 = getOldColorShade(r, g, b, shade), col2;
00097        ColorList::Iterator it, itEnd = doc->PageColors.end();
00098        for( it = doc->PageColors.begin(); it != itEnd; it++)
00099        {
00100               if ( it.data().getColorModel() == colorModelRGB )
00101               {
00102                      it.data().getRGB(&r, &g, &b);
00103                      col2.setRgb(r, g, b);
00104                      if( col1 == col2 )
00105                      {
00106                             found = true;
00107                             break;
00108                      }
00109               }
00110        }
00111        if(!found)
00112        {
00113               ScColor tmp;
00114               tmp.fromQColor(col1);
00115               colName = QString("%1 %2%").arg(colName).arg(shade);
00116               doc->PageColors.insert(colName, tmp);
00117        }
00118        else
00119               colName = it.key();
00120        shade = 100;
00121 }
00122 
00123 QColor getOldColorShade(const QColor& color, int shade)
00124 {
00125        int r, g, b;
00126        color.getRgb(&r, &g, &b);
00127        return getOldColorShade(r, g, b, shade);
00128 }
00129 
00130 QColor SCRIBUS_API getOldColorShade(uchar red, uchar green, uchar blue, int shade)
00131 {
00132        int h, s, v, snew;
00133        QColor color(red, green, blue);
00134        color.hsv(&h, &s, &v);
00135        if (red == green && green == blue)
00136        {
00137               snew = 255 - ((255 - v) * shade / 100);
00138               color.setHsv(h, s, snew);
00139        }
00140        else
00141        {
00142               snew = s * shade / 100;
00143               color.setHsv(h, snew, v);
00144        }
00145        return color;
00146 }
00147 
00148 QImage ProofImage(QImage *Image, ScribusDoc* doc)
00149 {
00150        QImage out = Image->copy();
00151        bool cmsUse = doc ? doc->HasCMS : false;
00152        bool softProofing = doc ? doc->SoftProofing : false;
00153        if (cmsUse && softProofing)
00154        {
00155               int outheight=out.height();
00156               for (int i=0; i < outheight; ++i)
00157               {
00158                      LPBYTE ptr = out.scanLine(i);
00159                      cmsDoTransform(doc->stdProofImg, ptr, ptr, out.width());
00160               }
00161        }
00162        else
00163        {
00164               if (cmsUse)
00165               {
00166                      int outheight=out.height();
00167                      for (int i=0; i < outheight; ++i)
00168                      {
00169                             LPBYTE ptr = out.scanLine(i);
00170                             cmsDoTransform(doc->stdTransImg, ptr, ptr, out.width());
00171                      }
00172               }
00173        }
00174        return out;
00175 }
00176 
00177 QColor SetColor(ScribusDoc *currentDoc, QString color, int shad)
00178 {
00179        const ScColor& col = currentDoc->PageColors[color];
00180        return ScColorEngine::getShadeColorProof(col, currentDoc, shad);
00181 }
00182 
00183 
00188 QPixmap * getSmallPixmap(QColor rgb)
00189 {
00190        static ScPixmapCache<QRgb> pxCache;
00191 
00192        QRgb index=rgb.rgb();
00193        if (pxCache.contains(index))
00194               return pxCache[index];
00195 
00196        QPixmap *pm = new QPixmap(15, 15);
00197        pm->fill(rgb);
00198        QPainter p;
00199        p.begin(pm);
00200        p.setBrush(Qt::NoBrush);
00201        QPen b(Qt::black, 1);
00202        p.setPen(b);
00203        p.drawRect(0, 0, 15, 15);
00204        p.end();
00205        pxCache.insert(index, pm);
00206        return pm;
00207 }
00208 
00209 QPixmap * getWidePixmap(QColor rgb)
00210 {
00211        static ScPixmapCache<QRgb> pxCache;
00212 
00213        QRgb index=rgb.rgb();
00214        if (pxCache.contains(index))
00215               return pxCache[index];
00216 
00217        QPixmap *pm = new QPixmap(30, 15);
00218        pm->fill(rgb);
00219        pxCache.insert(index, pm);
00220        return pm;
00221 }
00222 
00223 static Q_UINT64 code64(const ScColor & col) {
00224        int C, M, Y, K, R, G, B;
00225        Q_UINT64 result=0;
00226        col.getRGB( &R, &G, &B );
00227        col.getCMYK( &C, &M, &Y, &K );
00228        result |= col.getColorModel() == colorModelRGB ? 1 : 0;
00229        result |= col.isSpotColor() ? 64 : 0;
00230        result |= col.isRegistrationColor() ? 32 : 0;
00231        result <<= 8;
00232        result |= C;
00233        result <<= 8;
00234        result |= M;
00235        result <<= 8;
00236        result |= Y;
00237        result <<= 8;
00238        result |= K;
00239        result <<= 8;
00240        result |= R;
00241        result <<= 8;
00242        result |= G;
00243        result <<= 8;
00244        result |= B;
00245        return result;
00246 }
00247 
00248 QPixmap * getFancyPixmap(const ScColor& col, ScribusDoc* doc) {
00249        static ScPixmapCache<Q_UINT64> pxCache;
00250 
00251        static QPixmap alertIcon;
00252        static QPixmap cmykIcon;
00253        static QPixmap rgbIcon;
00254        static QPixmap spotIcon;
00255        static QPixmap regIcon;
00256        static bool iconsInitialized = false;
00257 
00258        if ( !iconsInitialized ) {
00259               alertIcon = loadIcon("alert.png");
00260               cmykIcon = loadIcon("cmyk.png");
00261               rgbIcon = loadIcon("rgb.png");
00262               spotIcon = loadIcon("spot.png");
00263               regIcon = loadIcon("register.png");
00264               iconsInitialized = true;
00265        }
00266 
00267        Q_UINT64 res=code64(col);
00268        if (pxCache.contains(res))
00269               return pxCache[res];
00270 
00271        QPixmap *pa=new QPixmap(60, 15);
00272        QPixmap *pm=getSmallPixmap(col.getRawRGBColor());
00273        pa->fill(Qt::white);
00274        paintAlert(*pm, *pa, 0, 0);
00275        if (ScColorEngine::isOutOfGamut(col, doc))
00276               paintAlert(alertIcon, *pa, 15, 0);
00277        if ((col.getColorModel() == colorModelCMYK) || (col.isSpotColor()))
00278               paintAlert(cmykIcon, *pa, 30, 0);
00279        else
00280               paintAlert(rgbIcon, *pa, 30, 0);
00281        if (col.isSpotColor())
00282               paintAlert(spotIcon, *pa, 46, 2);
00283        if (col.isRegistrationColor())
00284               paintAlert(regIcon, *pa, 45, 0);
00285        pxCache.insert(res, pa);
00286        return pa;
00287 }
00288 
00289 
00290 void paintAlert(QPixmap &toPaint, QPixmap &target, int x, int y, bool useMask)
00291 {
00292        // there is no alpha mask in the beginning
00293        if (useMask)
00294        {
00295               if (target.mask()==0)
00296                      target.setMask(QBitmap(target.width(), target.height(), useMask));
00297        }
00298        QPainter p;
00299        p.begin(&target);
00300        p.drawPixmap(x, y, toPaint);
00301        if (useMask)
00302        {
00303               QPainter alpha; // transparency handling
00304               alpha.begin(target.mask());
00305               alpha.setBrush(Qt::color1);
00306               alpha.setPen(Qt::color1);
00307               alpha.drawRect(x, y, 15, 15);
00308               if (toPaint.mask() != 0)
00309                      alpha.drawPixmap(x, y, *toPaint.mask());
00310               alpha.end();
00311        }
00312        p.end();
00313 }
00314 
00315 unsigned char INT_MULT ( unsigned char a, unsigned char b )
00316 {
00317        int c = a * b + 0x80;
00318        return (unsigned char)(( ( c >> 8 ) + c ) >> 8);
00319 }
00320 
00321 void RGBTOHSV ( uchar& red, uchar& green, uchar& blue )
00322 {
00323        int r, g, b;
00324        double h, s, v;
00325        int min, max;
00326        h = 0.;
00327        r = red;
00328        g = green;
00329        b = blue;
00330        if ( r > g )
00331        {
00332               max = QMAX( r, b );
00333               min = QMIN( g, b );
00334        }
00335        else
00336        {
00337               max = QMAX( g, b );
00338               min = QMIN( r, b );
00339        }
00340        v = max;
00341        if ( max != 0 )
00342               s = ( ( max - min ) * 255 ) / (double)max;
00343        else
00344               s = 0;
00345        if ( s == 0 )
00346               h = 0;
00347        else
00348        {
00349               int delta = max - min;
00350               if ( r == max )
00351                      h = ( g - b ) / (double)delta;
00352               else if ( g == max )
00353                      h = 2 + ( b - r ) / (double)delta;
00354               else if ( b == max )
00355                      h = 4 + ( r - g ) / (double)delta;
00356               h *= 42.5;
00357               if ( h < 0 )
00358                      h += 255;
00359               if ( h > 255 )
00360                      h -= 255;
00361        }
00362        red   = (uchar)h;
00363        green = (uchar)s;
00364        blue  = (uchar)v;
00365 }
00366 
00367 void HSVTORGB ( uchar& hue, uchar& saturation, uchar& value )
00368 {
00369        if ( saturation == 0 )
00370        {
00371               hue        = value;
00372               saturation = value;
00373               value      = value;
00374        }
00375        else
00376        {
00377               double h = hue * 6. / 255.;
00378               double s = saturation / 255.;
00379               double v = value / 255.;
00380 
00381               double f = h - (int)h;
00382               double p = v * ( 1. - s );
00383               double q = v * ( 1. - ( s * f ) );
00384               double t = v * ( 1. - ( s * ( 1. - f ) ) );
00385               // Worth a note here that gcc 2.96 will generate different results
00386               // depending on optimization mode on i386.
00387               switch ((int)h)
00388               {
00389               case 0:
00390                      hue        = (uchar)( v * 255 );
00391                      saturation = (uchar)( t * 255 );
00392                      value      = (uchar)( p * 255 );
00393                      break;
00394               case 1:
00395                      hue        = (uchar)( q * 255 );
00396                      saturation = (uchar)( v * 255 );
00397                      value      = (uchar)( p * 255 );
00398                      break;
00399               case 2:
00400                      hue        = (uchar)( p * 255 );
00401                      saturation = (uchar)( v * 255 );
00402                      value      = (uchar)( t * 255 );
00403                      break;
00404               case 3:
00405                      hue        = (uchar)( p * 255 );
00406                      saturation = (uchar)( q * 255 );
00407                      value      = (uchar)( v * 255 );
00408                      break;
00409               case 4:
00410                      hue        = (uchar)( t * 255 );
00411                      saturation = (uchar)( p * 255 );
00412                      value      = (uchar)( v * 255 );
00413                      break;
00414               case 5:
00415                      hue        = (uchar)( v * 255 );
00416                      saturation = (uchar)( p * 255 );
00417                      value      = (uchar)( q * 255 );
00418               }
00419        }
00420 }
00421 
00422 void RGBTOHLS ( uchar& red, uchar& green, uchar& blue )
00423 {
00424        double var_R = ( red / 255.0 );
00425        double var_G = ( green / 255.0 );
00426        double var_B = ( blue / 255.0 );
00427        double var_Min = QMIN( var_R, QMIN(var_G, var_B) );    //Min. value of RGB
00428        double var_Max = QMAX( var_R, QMAX(var_G, var_B) );    //Max. value of RGB
00429        double del_Max = var_Max - var_Min;             //Delta RGB value
00430        double L = ( var_Max + var_Min ) / 2.0;
00431        double H = 0;
00432        double S = 0;
00433        double del_R = 0;
00434        double del_G = 0;
00435        double del_B = 0;
00436        if ( del_Max == 0 )
00437        {
00438               H = 0;
00439               S = 0;
00440        }
00441        else
00442        {
00443               if ( L < 0.5 )
00444                      S = del_Max / ( var_Max + var_Min );
00445               else
00446                      S = del_Max / ( 2 - var_Max - var_Min );
00447               del_R = ( ( ( var_Max - var_R ) / 6.0 ) + ( del_Max / 2.0 ) ) / del_Max;
00448               del_G = ( ( ( var_Max - var_G ) / 6.0 ) + ( del_Max / 2.0 ) ) / del_Max;
00449               del_B = ( ( ( var_Max - var_B ) / 6.0 ) + ( del_Max / 2.0 ) ) / del_Max;
00450               if ( var_R == var_Max )
00451                      H = del_B - del_G;
00452           else if ( var_G == var_Max )
00453                      H = ( 1.0 / 3.0 ) + del_R - del_B;
00454               else if ( var_B == var_Max )
00455                      H = ( 2.0 / 3.0 ) + del_G - del_R;
00456               if ( H < 0 )
00457                      H += 1;
00458               if ( H > 1 )
00459                      H -= 1;
00460        }
00461        red = qRound(H * 255);
00462        green = qRound(L * 255);
00463        blue = qRound(S * 255);
00464 }
00465 
00466 double HLSVALUE ( double n1, double n2, double hue )
00467 {
00468        if ( hue < 0 )
00469               hue += 1;
00470        if ( hue > 1 )
00471               hue -= 1;
00472        if ( ( 6 * hue ) < 1 )
00473               return n1 + ( n2 - n1 ) * 6 * hue;
00474        if ( ( 2 * hue ) < 1 )
00475               return n2;
00476        if ( ( 3 * hue ) < 2 )
00477               return n1 + ( n2 - n1 ) * ( ( 2.0 / 3.0 ) - hue ) * 6;
00478        return n1;
00479 }
00480 
00481 void HLSTORGB ( uchar& hue, uchar& lightness, uchar& saturation )
00482 {
00483        double H = ( hue / 255.0 );
00484        double L = ( lightness / 255.0 );
00485        double S = ( saturation / 255.0 );
00486        if (S == 0)
00487        {
00488               hue = qRound(255 * L);
00489               saturation = qRound(255 * L);
00490               return;
00491        }
00492        double var_1 = 0;
00493        double var_2 = 0;
00494        if ( L < 0.5 )
00495               var_2 = L * ( 1 + S );
00496        else
00497               var_2 = ( L + S ) - ( S * L );
00498        var_1 = 2 * L - var_2;
00499        hue = qRound(255 * HLSVALUE( var_1, var_2, H + ( 1.0 / 3.0 ) ));
00500        lightness = qRound(255 * HLSVALUE( var_1, var_2, H ));
00501        saturation = qRound(255 * HLSVALUE( var_1, var_2, H - ( 1.0 / 3.0 ) ));
00502 }
00503 
00504 double getCurveYValue(FPointArray &curve, double x, bool linear)
00505 {
00506     double t;
00507     FPoint p;
00508     FPoint p0,p1,p2,p3;
00509     double c0,c1,c2,c3;
00510     double val = 0.5;
00511     if(curve.size() == 0)
00512         return 0.5;
00513     // First find curve segment
00514     p = curve.point(0);
00515     if(x < p.x())
00516         return p.y();
00517     p = curve.point(curve.size()-1);
00518     if(x >= p.x())
00519         return p.y();
00520        uint cc = 0;
00521     // Find the four control points (two on each side of x)    
00522     p = curve.point(0);
00523     while(x >= p.x())
00524     {
00525               cc++;
00526         p = curve.point(cc);
00527     }
00528     if (cc > 1)
00529     {
00530        p0 = curve.point(cc-2);
00531        p1 = curve.point(cc-1);
00532     }
00533     else
00534         p1 = p0 = curve.point(0);
00535     p2 = p;
00536     if (cc < curve.size()-1)
00537        p3 = curve.point(cc+1);
00538     else
00539        p3 = p;
00540     // Calculate the value
00541        if (linear)
00542        {
00543               double mc;
00544               if (p1.x() - p2.x() != 0.0)
00545                      mc = (p1.y() - p2.y()) / (p1.x() - p2.x());
00546               else
00547                      mc = p2.y() / p2.x();
00548               val = (x - p1.x()) * mc + p1.y();
00549        }
00550        else
00551        {
00552               t = (x - p1.x()) / (p2.x() - p1.x());
00553               c2 = (p2.y() - p0.y()) * (p2.x()-p1.x()) / (p2.x()-p0.x());
00554               c3 = p1.y();
00555               c0 = -2*p2.y() + 2*c3 + c2 + (p3.y() - p1.y()) * (p2.x() - p1.x()) / (p3.x() - p1.x());
00556               c1 = p2.y() - c3 - c2 - c0;
00557               val = ((c0*t + c1)*t + c2)*t + c3;
00558        }
00559        if(val < 0.0)
00560               val = 0.0;
00561        if(val > 1.0)
00562               val = 1.0;
00563        return val;
00564 }
00565 
00566 double Lum(uchar red, uchar green, uchar blue)
00567 {
00568        return 0.3 * (red / 255.0) + 0.59 * (green / 255.0) + 0.11 * (blue / 255.0);
00569 }
00570 
00571 double LumD(double red, double green, double blue)
00572 {
00573        return 0.3 * red + 0.59 * green + 0.11 * blue;
00574 }
00575 
00576 void setLum(uchar& red, uchar& green, uchar& blue, double lum)
00577 {
00578        double rP = (red / 255.0);
00579        double gP = (green / 255.0);
00580        double bP = (blue / 255.0);
00581        double d = lum - Lum(red, green, blue);
00582        rP += d;
00583        gP += d;
00584        bP += d;
00585        clipColor(rP, gP, bP);
00586        red = qRound(rP * 255);
00587        green = qRound(gP * 255);
00588        blue = qRound(bP * 255);
00589        return;
00590 }
00591 
00592 void clipColor(double& red, double& green, double& blue)
00593 {
00594        double l = LumD(red, green, blue);
00595        double n = QMIN(red, QMIN(green, blue));
00596        double x = QMAX(red, QMAX(green, blue));
00597        if (n < 0.0)
00598        {
00599               red = l + (((red - l) * l) / (l - n));
00600               green = l + (((green - l) * l) / (l - n));
00601               blue = l + (((blue - l) * l) / (l - n));
00602        }
00603        if (x > 1.0)
00604        {
00605               red = l + (((red - l) * (1.0 - l)) / (x - l));
00606               green = l + (((green - l) * (1.0 - l)) / (x - l));
00607               blue = l + (((blue - l) * (1.0 - l)) / (x - l));
00608        }
00609 }