Scribus Developer Documentation - API
logo-pen

Scribus Developer Documentation - API

scimage.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 #include "cmsettings.h"
00009 #include "scimage.h"
00010 #include "scribus.h"
00011 #include "scpaths.h"
00012 #include "scribuscore.h"
00013 #include "scimgdataloader_gimp.h"
00014 #include "scimgdataloader_jpeg.h"
00015 #include "scimgdataloader_ps.h"
00016 #include "scimgdataloader_psd.h"
00017 #include "scimgdataloader_pdf.h"
00018 #include "scimgdataloader_qt.h"
00019 #include "scimgdataloader_tiff.h"
00020 #include <QMessageBox>
00021 #include <QTextStream>
00022 #include <QList>
00023 #include <QByteArray>
00024 #include <cassert>
00025 #include <cmath>
00026 #include <cstdlib>
00027 #include <memory>
00028 #include <setjmp.h>
00029 #include CMS_INC
00030 #include "util_cms.h"
00031 #include "commonstrings.h"
00032 #include "exif.h"
00033 #include "util_ghostscript.h"
00034 #include "rawimage.h"
00035 #include "sccolorengine.h"
00036 #include "util.h"
00037 #include "util_color.h"
00038 #include "util_formats.h"
00039 #include "scstreamfilter.h"
00040 
00041 extern "C"
00042 {
00043 #define XMD_H           // shut JPEGlib up
00044 #if defined(Q_OS_UNIXWARE)
00045 #  define HAVE_BOOLEAN  // libjpeg under Unixware seems to need this
00046 #endif
00047 #include <jpeglib.h>
00048 #include <jerror.h>
00049 #undef HAVE_STDLIB_H
00050 #ifdef const
00051 #  undef const          // remove crazy C hackery in jconfig.h
00052 #endif
00053 }
00054 
00055 using namespace std;
00056 
00057 typedef struct my_error_mgr
00058 {
00059     struct jpeg_error_mgr pub;            /* "public" fields */
00060     jmp_buf setjmp_buffer;  /* for return to caller */
00061 }
00062 *my_error_ptr;
00063 
00064 static void my_error_exit (j_common_ptr cinfo)
00065 {
00066     my_error_ptr myerr = (my_error_ptr) cinfo->err;
00067     (*cinfo->err->output_message) (cinfo);
00068     longjmp (myerr->setjmp_buffer, 1);
00069 }
00070 
00071 ScImage::ScImage(const QImage & image) : QImage(image)
00072 {
00073     initialize();
00074 }
00075 
00076 
00077 // ScImage will use implicit sharing:
00078 ScImage::ScImage(const ScImage & image) : QImage(image.copy())
00079 {
00080     initialize();
00081 }
00082 
00083 
00084 ScImage::ScImage() : QImage()
00085 {
00086     initialize();
00087 }
00088 
00089 ScImage::ScImage( int width, int height ) : QImage( width, height, QImage::Format_ARGB32 )
00090 {
00091     initialize();
00092 }
00093 
00094 const QImage& ScImage::qImage()
00095 {
00096     return *this;
00097 }
00098 
00099 QImage* ScImage::qImagePtr()
00100 {
00101     return this;
00102 }
00103 
00104 QImage ScImage::scaled(int h, int w, Qt::AspectRatioMode mode, Qt::TransformationMode transformMode) const
00105 {
00106     return QImage::scaled(h, w, mode, transformMode);
00107 }
00108 
00109 
00110 void ScImage::initialize()
00111 {
00112     imgInfo.xres = 72;
00113     imgInfo.yres = 72;
00114     imgInfo.colorspace = ColorSpaceRGB;
00115     imgInfo.valid = false;
00116     imgInfo.isRequest = false;
00117     imgInfo.isEmbedded = false;
00118     imgInfo.progressive = false;
00119     imgInfo.exifDataValid = false;
00120     imgInfo.lowResType = 1;
00121     imgInfo.lowResScale = 1.0;
00122     imgInfo.PDSpathData.clear();
00123     imgInfo.RequestProps.clear();
00124     imgInfo.clipPath = "";
00125     imgInfo.usedPath = "";
00126     imgInfo.layerInfo.clear();
00127     imgInfo.duotoneColors.clear();
00128     imgInfo.exifInfo.cameraName = "";
00129     imgInfo.exifInfo.cameraVendor = "";
00130     imgInfo.exifInfo.thumbnail = QImage();
00131     imgInfo.BBoxX = 0;
00132     imgInfo.BBoxH = 0;
00133 }
00134 
00135 ScImage::~ScImage()
00136 {
00137     curveTable.resize(0);
00138 }
00139 
00140 void ScImage::applyEffect(const ScImageEffectList& effectsList, ColorList& colors, bool cmyk)
00141 {
00142     ScribusDoc* doc = colors.document();
00143     if (effectsList.count() != 0)
00144     {
00145         for (int a = 0; a < effectsList.count(); ++a)
00146         {
00147             if (effectsList.at(a).effectCode == EF_INVERT)
00148                 invert(cmyk);
00149             if (effectsList.at(a).effectCode == EF_GRAYSCALE)
00150                 toGrayscale(cmyk);
00151             if (effectsList.at(a).effectCode == EF_COLORIZE)
00152             {
00153                 QString tmpstr = effectsList.at(a).effectParameters;
00154                 QString col = CommonStrings::None;
00155                 int shading = 100;
00156                 QTextStream fp(&tmpstr, QIODevice::ReadOnly);
00157                 fp >> col;
00158                 fp >> shading;
00159                 colorize(doc, colors[col], shading, cmyk);
00160             }
00161             if (effectsList.at(a).effectCode == EF_BRIGHTNESS)
00162             {
00163                 QString tmpstr = effectsList.at(a).effectParameters;
00164                 int brightnessValue = 0;
00165                 QTextStream fp(&tmpstr, QIODevice::ReadOnly);
00166                 fp >> brightnessValue;
00167                 brightness(brightnessValue, cmyk);
00168             }
00169             if (effectsList.at(a).effectCode == EF_CONTRAST)
00170             {
00171                 QString tmpstr = effectsList.at(a).effectParameters;
00172                 int contrastValue = 0;
00173                 QTextStream fp(&tmpstr, QIODevice::ReadOnly);
00174                 fp >> contrastValue;
00175                 contrast(contrastValue, cmyk);
00176             }
00177             if (effectsList.at(a).effectCode == EF_SHARPEN)
00178             {
00179                 QString tmpstr = effectsList.at(a).effectParameters;
00180                 double radius, sigma;
00181                 QTextStream fp(&tmpstr, QIODevice::ReadOnly);
00182                 fp >> radius;
00183                 fp >> sigma;
00184                 sharpen(radius, sigma);
00185             }
00186             if (effectsList.at(a).effectCode == EF_BLUR)
00187             {
00188                 QString tmpstr = effectsList.at(a).effectParameters;
00189                 double radius, sigma;
00190                 QTextStream fp(&tmpstr, QIODevice::ReadOnly);
00191                 fp >> radius;
00192                 fp >> sigma;
00193                 blur(static_cast<int>(radius));
00194             }
00195             if (effectsList.at(a).effectCode == EF_SOLARIZE)
00196             {
00197                 QString tmpstr = effectsList.at(a).effectParameters;
00198                 double sigma;
00199                 QTextStream fp(&tmpstr, QIODevice::ReadOnly);
00200                 fp >> sigma;
00201                 solarize(sigma, cmyk);
00202             }
00203             if (effectsList.at(a).effectCode == EF_DUOTONE)
00204             {
00205                 QString tmpstr = effectsList.at(a).effectParameters;
00206                 QString col1 = CommonStrings::None;
00207                 int shading1 = 100;
00208                 QString col2 = CommonStrings::None;
00209                 int shading2 = 100;
00210                 QTextStream fp(&tmpstr, QIODevice::ReadOnly);
00211                 col1 = fp.readLine();
00212                 col2 = fp.readLine();
00213                 fp >> shading1;
00214                 fp >> shading2;
00215                 int numVals;
00216                 double xval, yval;
00217                 FPointArray curve1;
00218                 curve1.resize(0);
00219                 fp >> numVals;
00220                 for (int nv = 0; nv < numVals; nv++)
00221                 {
00222                     fp >> xval;
00223                     fp >> yval;
00224                     curve1.addPoint(xval, yval);
00225                 }
00226                 int lin1;
00227                 fp >> lin1;
00228                 FPointArray curve2;
00229                 curve2.resize(0);
00230                 fp >> numVals;
00231                 for (int nv = 0; nv < numVals; nv++)
00232                 {
00233                     fp >> xval;
00234                     fp >> yval;
00235                     curve2.addPoint(xval, yval);
00236                 }
00237                 int lin2;
00238                 fp >> lin2;
00239                 duotone(doc, colors[col1], shading1, curve1, lin1, colors[col2], shading2, curve2, lin2, cmyk);
00240             }
00241             if (effectsList.at(a).effectCode == EF_TRITONE)
00242             {
00243                 QString tmpstr = effectsList.at(a).effectParameters;
00244                 QString col1 = CommonStrings::None;
00245                 QString col2 = CommonStrings::None;
00246                 QString col3 = CommonStrings::None;
00247                 int shading1 = 100;
00248                 int shading2 = 100;
00249                 int shading3 = 100;
00250                 QTextStream fp(&tmpstr, QIODevice::ReadOnly);
00251                 col1 = fp.readLine();
00252                 col2 = fp.readLine();
00253                 col3 = fp.readLine();
00254                 fp >> shading1;
00255                 fp >> shading2;
00256                 fp >> shading3;
00257                 int numVals;
00258                 double xval, yval;
00259                 FPointArray curve1;
00260                 curve1.resize(0);
00261                 fp >> numVals;
00262                 for (int nv = 0; nv < numVals; nv++)
00263                 {
00264                     fp >> xval;
00265                     fp >> yval;
00266                     curve1.addPoint(xval, yval);
00267                 }
00268                 int lin1;
00269                 fp >> lin1;
00270                 FPointArray curve2;
00271                 curve2.resize(0);
00272                 fp >> numVals;
00273                 for (int nv = 0; nv < numVals; nv++)
00274                 {
00275                     fp >> xval;
00276                     fp >> yval;
00277                     curve2.addPoint(xval, yval);
00278                 }
00279                 int lin2;
00280                 fp >> lin2;
00281                 FPointArray curve3;
00282                 curve3.resize(0);
00283                 fp >> numVals;
00284                 for (int nv = 0; nv < numVals; nv++)
00285                 {
00286                     fp >> xval;
00287                     fp >> yval;
00288                     curve3.addPoint(xval, yval);
00289                 }
00290                 int lin3;
00291                 fp >> lin3;
00292                 tritone(doc, colors[col1], shading1, curve1, lin1, colors[col2], shading2, curve2, lin2, colors[col3], shading3, curve3, lin3, cmyk);
00293             }
00294             if (effectsList.at(a).effectCode == EF_QUADTONE)
00295             {
00296                 QString tmpstr = effectsList.at(a).effectParameters;
00297                 QString col1 = CommonStrings::None;
00298                 QString col2 = CommonStrings::None;
00299                 QString col3 = CommonStrings::None;
00300                 QString col4 = CommonStrings::None;
00301                 int shading1 = 100;
00302                 int shading2 = 100;
00303                 int shading3 = 100;
00304                 int shading4 = 100;
00305                 QTextStream fp(&tmpstr, QIODevice::ReadOnly);
00306                 col1 = fp.readLine();
00307                 col2 = fp.readLine();
00308                 col3 = fp.readLine();
00309                 col4 = fp.readLine();
00310                 fp >> shading1;
00311                 fp >> shading2;
00312                 fp >> shading3;
00313                 fp >> shading4;
00314                 int numVals;
00315                 double xval, yval;
00316                 FPointArray curve1;
00317                 curve1.resize(0);
00318                 fp >> numVals;
00319                 for (int nv = 0; nv < numVals; nv++)
00320                 {
00321                     fp >> xval;
00322                     fp >> yval;
00323                     curve1.addPoint(xval, yval);
00324                 }
00325                 int lin1;
00326                 fp >> lin1;
00327                 FPointArray curve2;
00328                 curve2.resize(0);
00329                 fp >> numVals;
00330                 for (int nv = 0; nv < numVals; nv++)
00331                 {
00332                     fp >> xval;
00333                     fp >> yval;
00334                     curve2.addPoint(xval, yval);
00335                 }
00336                 int lin2;
00337                 fp >> lin2;
00338                 FPointArray curve3;
00339                 curve3.resize(0);
00340                 fp >> numVals;
00341                 for (int nv = 0; nv < numVals; nv++)
00342                 {
00343                     fp >> xval;
00344                     fp >> yval;
00345                     curve3.addPoint(xval, yval);
00346                 }
00347                 int lin3;
00348                 fp >> lin3;
00349                 FPointArray curve4;
00350                 curve4.resize(0);
00351                 fp >> numVals;
00352                 for (int nv = 0; nv < numVals; nv++)
00353                 {
00354                     fp >> xval;
00355                     fp >> yval;
00356                     curve4.addPoint(xval, yval);
00357                 }
00358                 int lin4;
00359                 fp >> lin4;
00360                 quadtone(doc, colors[col1], shading1, curve1, lin1, colors[col2], shading2, curve2, lin2, colors[col3], shading3, curve3, lin3, colors[col4], shading4, curve4, lin4, cmyk);
00361             }
00362             if (effectsList.at(a).effectCode == EF_GRADUATE)
00363             {
00364                 QString tmpstr = effectsList.at(a).effectParameters;
00365                 int numVals;
00366                 double xval, yval;
00367                 FPointArray curve;
00368                 curve.resize(0);
00369                 QTextStream fp(&tmpstr, QIODevice::ReadOnly);
00370                 fp >> numVals;
00371                 for (int nv = 0; nv < numVals; nv++)
00372                 {
00373                     fp >> xval;
00374                     fp >> yval;
00375                     curve.addPoint(xval, yval);
00376                 }
00377                 int lin;
00378                 fp >> lin;
00379                 doGraduate(curve, cmyk, lin);
00380             }
00381         }
00382     }
00383 }
00384 /*
00385 void ScImage::liberateMemory(void **memory)
00386 {
00387     assert(memory != (void **)NULL);
00388     if(*memory == (void *)NULL)
00389         return;
00390     free(*memory);
00391     *memory=(void *) NULL;
00392 }
00393 */
00394 void ScImage::solarize(double factor, bool cmyk)
00395 {
00396     curveTable.resize(256);
00397     int fk = qRound(255 / factor);
00398     for (int i = 0; i < 256; ++i)
00399     {
00400         curveTable[i] = qMin(255, static_cast<int>(i / fk) * fk);
00401     }
00402     applyCurve(cmyk);
00403 }
00404 
00405 // Stack Blur Algorithm by Mario Klingemann <mario@quasimondo.com>
00406 void ScImage::blur(int radius)
00407 {
00408     if (radius < 1) {
00409         return;
00410     }
00411 
00412     QRgb *pix = (QRgb*)bits();
00413     int w   = width();
00414     int h   = height();
00415     int wm  = w-1;
00416     int hm  = h-1;
00417     int wh  = w*h;
00418     int div = radius+radius+1;
00419 
00420     int *r = new int[wh];
00421     int *g = new int[wh];
00422     int *b = new int[wh];
00423     int *a = new int[wh];
00424     int rsum, gsum, bsum, asum, x, y, i, yp, yi, yw;
00425     QRgb p;
00426     int *vmin = new int[qMax(w,h)];
00427 
00428     int divsum = (div+1)>>1;
00429     divsum *= divsum;
00430     int *dv = new int[256*divsum];
00431     for (i=0; i < 256*divsum; ++i) {
00432         dv[i] = (i/divsum);
00433     }
00434 
00435     yw = yi = 0;
00436 
00437     int **stack = new int*[div];
00438     for(int i = 0; i < div; ++i) {
00439         stack[i] = new int[4];
00440     }
00441 
00442 
00443     int stackpointer;
00444     int stackstart;
00445     int *sir;
00446     int rbs;
00447     int r1 = radius+1;
00448     int routsum, goutsum, boutsum, aoutsum;
00449     int rinsum, ginsum, binsum, ainsum;
00450 
00451     for (y = 0; y < h; ++y){
00452         rinsum = ginsum = binsum = ainsum
00453                = routsum = goutsum = boutsum = aoutsum
00454                = rsum = gsum = bsum = asum = 0;
00455         for(i =- radius; i <= radius; ++i) {
00456             p = pix[yi+qMin(wm,qMax(i,0))];
00457             sir = stack[i+radius];
00458             sir[0] = qRed(p);
00459             sir[1] = qGreen(p);
00460             sir[2] = qBlue(p);
00461             sir[3] = qAlpha(p);
00462             
00463             rbs = r1-abs(i);
00464             rsum += sir[0]*rbs;
00465             gsum += sir[1]*rbs;
00466             bsum += sir[2]*rbs;
00467             asum += sir[3]*rbs;
00468             
00469             if (i > 0){
00470                 rinsum += sir[0];
00471                 ginsum += sir[1];
00472                 binsum += sir[2];
00473                 ainsum += sir[3];
00474             } else {
00475                 routsum += sir[0];
00476                 goutsum += sir[1];
00477                 boutsum += sir[2];
00478                 aoutsum += sir[3];
00479             }
00480         }
00481         stackpointer = radius;
00482 
00483         for (x=0; x < w; ++x) {
00484 
00485             r[yi] = dv[rsum];
00486             g[yi] = dv[gsum];
00487             b[yi] = dv[bsum];
00488             a[yi] = dv[asum];
00489 
00490             rsum -= routsum;
00491             gsum -= goutsum;
00492             bsum -= boutsum;
00493             asum -= aoutsum;
00494 
00495             stackstart = stackpointer-radius+div;
00496             sir = stack[stackstart%div];
00497 
00498             routsum -= sir[0];
00499             goutsum -= sir[1];
00500             boutsum -= sir[2];
00501             aoutsum -= sir[3];
00502 
00503             if (y == 0) {
00504                 vmin[x] = qMin(x+radius+1,wm);
00505             }
00506             p = pix[yw+vmin[x]];
00507 
00508             sir[0] = qRed(p);
00509             sir[1] = qGreen(p);
00510             sir[2] = qBlue(p);
00511             sir[3] = qAlpha(p);
00512 
00513             rinsum += sir[0];
00514             ginsum += sir[1];
00515             binsum += sir[2];
00516             ainsum += sir[3];
00517 
00518             rsum += rinsum;
00519             gsum += ginsum;
00520             bsum += binsum;
00521             asum += ainsum;
00522 
00523             stackpointer = (stackpointer+1)%div;
00524             sir = stack[(stackpointer)%div];
00525 
00526             routsum += sir[0];
00527             goutsum += sir[1];
00528             boutsum += sir[2];
00529             aoutsum += sir[3];
00530 
00531             rinsum -= sir[0];
00532             ginsum -= sir[1];
00533             binsum -= sir[2];
00534             ainsum -= sir[3];
00535 
00536             ++yi;
00537         }
00538         yw += w;
00539     }
00540     for (x=0; x < w; ++x){
00541         rinsum = ginsum = binsum = ainsum 
00542                = routsum = goutsum = boutsum = aoutsum 
00543                = rsum = gsum = bsum = asum = 0;
00544         
00545         yp =- radius * w;
00546         
00547         for(i=-radius; i <= radius; ++i) {
00548             yi=qMax(0,yp)+x;
00549 
00550             sir = stack[i+radius];
00551 
00552             sir[0] = r[yi];
00553             sir[1] = g[yi];
00554             sir[2] = b[yi];
00555             sir[3] = a[yi];
00556 
00557             rbs = r1-abs(i);
00558 
00559             rsum += r[yi]*rbs;
00560             gsum += g[yi]*rbs;
00561             bsum += b[yi]*rbs;
00562             asum += a[yi]*rbs;
00563 
00564             if (i > 0) {
00565                 rinsum += sir[0];
00566                 ginsum += sir[1];
00567                 binsum += sir[2];
00568                 ainsum += sir[3];
00569             } else {
00570                 routsum += sir[0];
00571                 goutsum += sir[1];
00572                 boutsum += sir[2];
00573                 aoutsum += sir[3];
00574             }
00575 
00576             if (i < hm){
00577                 yp += w;
00578             }
00579         }
00580 
00581         yi = x;
00582         stackpointer = radius;
00583 
00584         for (y=0; y < h; ++y){
00585             pix[yi] = qRgba(dv[rsum], dv[gsum], dv[bsum], dv[asum]);
00586 
00587             rsum -= routsum;
00588             gsum -= goutsum;
00589             bsum -= boutsum;
00590             asum -= aoutsum;
00591 
00592             stackstart = stackpointer-radius+div;
00593             sir = stack[stackstart%div];
00594 
00595             routsum -= sir[0];
00596             goutsum -= sir[1];
00597             boutsum -= sir[2];
00598             aoutsum -= sir[3];
00599 
00600             if (x==0){
00601                 vmin[y] = qMin(y+r1,hm)*w;
00602             }
00603             p = x+vmin[y];
00604 
00605             sir[0] = r[p];
00606             sir[1] = g[p];
00607             sir[2] = b[p];
00608             sir[3] = a[p];
00609 
00610             rinsum += sir[0];
00611             ginsum += sir[1];
00612             binsum += sir[2];
00613             ainsum += sir[3];
00614 
00615             rsum += rinsum;
00616             gsum += ginsum;
00617             bsum += binsum;
00618             asum += ainsum;
00619 
00620             stackpointer = (stackpointer+1)%div;
00621             sir = stack[stackpointer];
00622 
00623             routsum += sir[0];
00624             goutsum += sir[1];
00625             boutsum += sir[2];
00626             aoutsum += sir[3];
00627 
00628             rinsum -= sir[0];
00629             ginsum -= sir[1];
00630             binsum -= sir[2];
00631             ainsum -= sir[3];
00632 
00633             yi += w;
00634         }
00635     }
00636     delete [] r;
00637     delete [] g;
00638     delete [] b;
00639     delete [] a;
00640     delete [] vmin;
00641     delete [] dv;
00642 
00643     for(int i = 0; i < div; ++i) {
00644         delete [] stack[i];
00645     }
00646     delete [] stack;
00647 }
00648 
00649 bool ScImage::convolveImage(QImage *dest, const unsigned int order, const double *kernel)
00650 {
00651     long widthk;
00652     double red, green, blue, alpha;
00653     double normalize, *normal_kernel;
00654     register const double *k;
00655     register unsigned int *q;
00656     int x, y, mx, my, sx, sy;
00657     long i;
00658     int mcx, mcy;
00659     widthk = order;
00660     if((widthk % 2) == 0)
00661         return(false);
00662     normal_kernel = (double *)malloc(widthk*widthk*sizeof(double));
00663     if(!normal_kernel)
00664         return(false);
00665     *dest = QImage();
00666     *dest = QImage(width(), height(), QImage::Format_ARGB32);
00667     normalize=0.0;
00668     for(i=0; i < (widthk*widthk); i++)
00669         normalize += kernel[i];
00670     if(fabs(normalize) <= 1.0e-12)
00671         normalize=1.0;
00672     normalize=1.0/normalize;
00673     for(i=0; i < (widthk*widthk); i++)
00674         normal_kernel[i] = normalize*kernel[i];
00675     for(y=0; y < dest->height(); ++y)
00676     {
00677         sy = y-(widthk/2);
00678         q = (unsigned int *)dest->scanLine(y);
00679         for(x=0; x < dest->width(); ++x)
00680         {
00681             k = normal_kernel;
00682             red = green = blue = alpha = 0;
00683             sy = y-(widthk/2);
00684             for(mcy=0; mcy < widthk; ++mcy, ++sy)
00685             {
00686                 my = sy < 0 ? 0 : sy > height()-1 ? height()-1 : sy;
00687                 sx = x+(-widthk/2);
00688                 for(mcx=0; mcx < widthk; ++mcx, ++sx)
00689                 {
00690                     mx = sx < 0 ? 0 : sx > width()-1 ? width()-1 : sx;
00691                     red += (*k)*(qRed(scanLine(my)[mx])*257);
00692                     green += (*k)*(qGreen(scanLine(my)[mx])*257);
00693                     blue += (*k)*(qBlue(scanLine(my)[mx])*257);
00694                     alpha += (*k)*(qAlpha(scanLine(my)[mx])*257);
00695                     ++k;
00696                 }
00697             }
00698             red = red < 0 ? 0 : red > 65535 ? 65535 : red+0.5;
00699             green = green < 0 ? 0 : green > 65535 ? 65535 : green+0.5;
00700             blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue+0.5;
00701             alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha+0.5;
00702             *q++ = qRgba((unsigned char)(red/257UL),
00703                          (unsigned char)(green/257UL),
00704                          (unsigned char)(blue/257UL),
00705                          (unsigned char)(alpha/257UL));
00706         }
00707     }
00708     free(normal_kernel);
00709     return(true);
00710 }
00711 
00712 int ScImage::getOptimalKernelWidth(double radius, double sigma)
00713 {
00714     double normalize, value;
00715     long width;
00716     register long u;
00717     assert(sigma != 0.0);
00718     if(radius > 0.0)
00719         return((int)(2.0*ceil(radius)+1.0));
00720     for(width=5; ;)
00721     {
00722         normalize=0.0;
00723         for(u=(-width/2); u <= (width/2); u++)
00724             normalize+=exp(-((double) u*u)/(2.0*sigma*sigma))/(2.50662827463100024161235523934010416269302368164062*sigma);
00725         u=width/2;
00726         value=exp(-((double) u*u)/(2.0*sigma*sigma))/(2.50662827463100024161235523934010416269302368164062*sigma)/normalize;
00727         if((long)(65535*value) <= 0)
00728             break;
00729         width+=2;
00730     }
00731     return((int)width-2);
00732 }
00733 
00734 void ScImage::sharpen(double radius, double sigma)
00735 {
00736     double alpha, normalize, *kernel;
00737     int widthk;
00738     register long i, u, v;
00739     QImage dest;
00740     if(sigma == 0.0)
00741         return;
00742     widthk = getOptimalKernelWidth(radius, sigma);
00743     if(width() < widthk)
00744         return;
00745     kernel = (double *)malloc(widthk*widthk*sizeof(double));
00746     if(!kernel)
00747         return;
00748     i = 0;
00749     normalize=0.0;
00750     for (v=(-widthk/2); v <= (widthk/2); v++)
00751     {
00752         for (u=(-widthk/2); u <= (widthk/2); u++)
00753         {
00754             alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma));
00755             kernel[i]=alpha/(2.0*3.14159265358979323846264338327950288419716939937510*sigma*sigma);
00756             normalize+=kernel[i];
00757             i++;
00758         }
00759     }
00760     kernel[i/2]=(-2.0)*normalize;
00761     convolveImage(&dest, widthk, kernel);
00762     free(kernel);
00763 //  liberateMemory((void **) &kernel);
00764     for( int yi=0; yi < dest.height(); ++yi )
00765     {
00766         QRgb *s = (QRgb*)(dest.scanLine( yi ));
00767         QRgb *d = (QRgb*)(scanLine( yi ));
00768         for(int xi=0; xi < dest.width(); ++xi )
00769         {
00770             (*d) = (*s);
00771             s++;
00772             d++;
00773         }
00774     }
00775     return;
00776 }
00777 
00778 void ScImage::contrast(int contrastValue, bool cmyk)
00779 {
00780     curveTable.resize(256);
00781     QPoint p1(0,0 - contrastValue);
00782     QPoint p2(256, 256 + contrastValue);
00783     double mc = (p1.y() - p2.y()) / (double)(p1.x() - p2.x());
00784     for (int i = 0; i < 256; ++i)
00785     {
00786         curveTable[i] = qMin(255, qMax(0, int(i * mc) + p1.y()));
00787     }
00788     applyCurve(cmyk);
00789 }
00790 
00791 void ScImage::brightness(int brightnessValue, bool cmyk)
00792 {
00793     curveTable.resize(256);
00794     QPoint p1(0,0 + brightnessValue);
00795     QPoint p2(256, 256 + brightnessValue);
00796     double mc = (p1.y() - p2.y()) / (double)(p1.x() - p2.x());
00797     for (int i = 0; i < 256; ++i)
00798     {
00799         curveTable[i] = qMin(255, qMax(0, int(i * mc) + p1.y()));
00800     }
00801     applyCurve(cmyk);
00802 }
00803 
00804 void ScImage::doGraduate(FPointArray curve, bool cmyk, bool linear)
00805 {
00806     curveTable.resize(256);
00807     for (int x = 0 ; x < 256 ; x++)
00808     {
00809         curveTable[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve, x / 255.0, linear) * 255)));
00810     }
00811     applyCurve(cmyk);
00812 }
00813 
00814 void ScImage::applyCurve(bool cmyk)
00815 {
00816     int h = height();
00817     int w = width();
00818     QRgb *s;
00819     QRgb r;
00820     int c, m, y, k;
00821     unsigned char *p;
00822     unsigned char rc, gc, bc;
00823     for( int yi=0; yi < h; ++yi )
00824     {
00825         s = (QRgb*)(scanLine( yi ));
00826         for( int xi=0; xi < w; ++xi )
00827         {
00828             r = *s;
00829             if (cmyk)
00830             {
00831                 p = (unsigned char *) s;
00832                 rc = 255 - qMin(255, p[0] + p[3]);
00833                 gc = 255 - qMin(255, p[1] + p[3]);
00834                 bc = 255 - qMin(255, p[2] + p[3]);
00835                 c = 255 - curveTable[(int)rc];
00836                 m = 255 - curveTable[(int)gc];
00837                 y = 255 - curveTable[(int)bc];
00838                 k = qMin(qMin(c, m), y);
00839                 *s = qRgba(y - k, m - k, c - k, k );
00840             }
00841             else
00842             {
00843                 c = curveTable[qRed(r)];
00844                 m = curveTable[qGreen(r)];
00845                 y = curveTable[qBlue(r)];
00846                 k = qAlpha(r);
00847                 *s = qRgba(c, m, y, k);
00848             }
00849             s++;
00850         }
00851     }
00852 }
00853 
00854 void ScImage::colorize(ScribusDoc* doc, ScColor color, int shade, bool cmyk)
00855 {
00856     int h = height();
00857     int w = width();
00858     int cc, cm, cy, ck;
00859     int hu, sa, v;
00860     ScColor tmp2;
00861     QColor tmpR;
00862     QRgb *s;
00863     QRgb r;
00864     double k;
00865     int cc2, cm2, cy2, k2;
00866     if (cmyk)
00867     {
00868         CMYKColor cmykCol;
00869         ScColorEngine::getShadeColorCMYK(color, doc, cmykCol, shade);
00870         cmykCol.getValues(cc, cm, cy, ck);
00871     }
00872     else
00873     {
00874         ck = 0;
00875         RGBColor rgbCol;
00876         ScColorEngine::getShadeColorRGB(color, doc, rgbCol, shade);
00877         rgbCol.getValues(cc, cm, cy);
00878     }
00879     for( int yi=0; yi < h; ++yi )
00880     {
00881         s = (QRgb*)(scanLine( yi ));
00882         for( int xi=0; xi < w; ++xi )
00883         {
00884             r = *s;
00885             if (cmyk)
00886             {
00887                 k = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r) + qAlpha(r)), 255) / 255.0;
00888                 *s = qRgba(qMin(qRound(cc*k), 255), qMin(qRound(cm*k), 255), qMin(qRound(cy*k), 255), qMin(qRound(ck*k), 255));
00889             }
00890             else
00891             {
00892                 k2 = 255 - qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255);
00893                 tmpR.setRgb(cc, cm, cy);
00894                 tmpR.getHsv(&hu, &sa, &v);
00895                 tmpR.setHsv(hu, sa * k2 / 255, 255 - ((255 - v) * k2 / 255));
00896                 tmpR.getRgb(&cc2, &cm2, &cy2);
00897                 *s = qRgba(cc2, cm2, cy2, qAlpha(r));
00898             }
00899             s++;
00900         }
00901     }
00902 }
00903 
00904 void ScImage::duotone(ScribusDoc* doc, ScColor color1, int shade1, FPointArray curve1, bool lin1, ScColor color2, int shade2, FPointArray curve2, bool lin2, bool cmyk)
00905 {
00906     int h = height();
00907     int w = width();
00908     int c, c1, m, m1, y, y1, k, k1;
00909     int cn, c1n, mn, m1n, yn, y1n, kn, k1n;
00910     uchar cb;
00911     QVector<int> curveTable1;
00912     QVector<int> curveTable2;
00913     CMYKColor cmykCol;
00914     ScColorEngine::getShadeColorCMYK(color1, doc, cmykCol, shade1);
00915     cmykCol.getValues(c, m, y, k);
00916     ScColorEngine::getShadeColorCMYK(color2, doc, cmykCol, shade2);
00917     cmykCol.getValues(c1, m1, y1, k1);
00918     curveTable1.resize(256);
00919     for (int x = 0 ; x < 256 ; x++)
00920     {
00921         curveTable1[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve1, x / 255.0, lin1) * 255)));
00922     }
00923     curveTable2.resize(256);
00924     for (int x = 0 ; x < 256 ; x++)
00925     {
00926         curveTable2[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve2, x / 255.0, lin2) * 255)));
00927     }
00928     for( int yi=0; yi < h; ++yi )
00929     {
00930         QRgb * s = (QRgb*)(scanLine( yi ));
00931         for( int xi=0; xi < w; ++xi )
00932         {
00933             QRgb r=*s;
00934             if (cmyk)
00935                 cb = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r) + qAlpha(r)), 255);
00936             else
00937                 cb = 255 - qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255);
00938             cn = qMin((c * curveTable1[(int)cb]) >> 8, 255);
00939             mn = qMin((m * curveTable1[(int)cb]) >> 8, 255);
00940             yn = qMin((y * curveTable1[(int)cb]) >> 8, 255);
00941             kn = qMin((k * curveTable1[(int)cb]) >> 8, 255);
00942             c1n = qMin((c1 * curveTable1[(int)cb]) >> 8, 255);
00943             m1n = qMin((m1 * curveTable2[(int)cb]) >> 8, 255);
00944             y1n = qMin((y1 * curveTable2[(int)cb]) >> 8, 255);
00945             k1n = qMin((k1 * curveTable2[(int)cb]) >> 8, 255);
00946             ScColor col = ScColor(qMin(cn+c1n, 255), qMin(mn+m1n, 255), qMin(yn+y1n, 255), qMin(kn+k1n, 255));
00947             if (cmyk)
00948                 col.getCMYK(&cn, &mn, &yn, &kn);
00949             else
00950             {
00951                 col.getRawRGBColor(&cn, &mn, &yn);
00952                 kn = qAlpha(r);
00953             }
00954             *s = qRgba(cn, mn, yn, kn);
00955             s++;
00956         }
00957     }
00958 }
00959 
00960 void ScImage::tritone(ScribusDoc* doc, ScColor color1, int shade1, FPointArray curve1, bool lin1, ScColor color2, int shade2, FPointArray curve2, bool lin2, ScColor color3, int shade3, FPointArray curve3, bool lin3, bool cmyk)
00961 {
00962     int h = height();
00963     int w = width();
00964     int c, c1, c2, m, m1, m2, y, y1, y2, k, k1, k2;
00965     int cn, c1n, c2n, mn, m1n, m2n, yn, y1n, y2n, kn, k1n, k2n;
00966     uchar cb;
00967     CMYKColor cmykCol;
00968     QVector<int> curveTable1;
00969     QVector<int> curveTable2;
00970     QVector<int> curveTable3;
00971     ScColorEngine::getShadeColorCMYK(color1, doc, cmykCol, shade1);
00972     cmykCol.getValues(c, m, y, k);
00973     ScColorEngine::getShadeColorCMYK(color2, doc, cmykCol, shade2);
00974     cmykCol.getValues(c1, m1, y1, k1);
00975     ScColorEngine::getShadeColorCMYK(color3, doc, cmykCol, shade3);
00976     cmykCol.getValues(c2, m2, y2, k2);
00977     curveTable1.resize(256);
00978     for (int x = 0 ; x < 256 ; x++)
00979     {
00980         curveTable1[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve1, x / 255.0, lin1) * 255)));
00981     }
00982     curveTable2.resize(256);
00983     for (int x = 0 ; x < 256 ; x++)
00984     {
00985         curveTable2[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve2, x / 255.0, lin2) * 255)));
00986     }
00987     curveTable3.resize(256);
00988     for (int x = 0 ; x < 256 ; x++)
00989     {
00990         curveTable3[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve2, x / 255.0, lin3) * 255)));
00991     }
00992     for( int yi=0; yi < h; ++yi )
00993     {
00994         QRgb * s = (QRgb*)(scanLine( yi ));
00995         for( int xi=0; xi < w; ++xi )
00996         {
00997             QRgb r=*s;
00998             if (cmyk)
00999                 cb = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r) + qAlpha(r)), 255);
01000             else
01001                 cb = 255 - qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255);
01002             cn = qMin((c * curveTable1[(int)cb]) >> 8, 255);
01003             mn = qMin((m * curveTable1[(int)cb]) >> 8, 255);
01004             yn = qMin((y * curveTable1[(int)cb]) >> 8, 255);
01005             kn = qMin((k * curveTable1[(int)cb]) >> 8, 255);
01006             c1n = qMin((c1 * curveTable2[(int)cb]) >> 8, 255);
01007             m1n = qMin((m1 * curveTable2[(int)cb]) >> 8, 255);
01008             y1n = qMin((y1 * curveTable2[(int)cb]) >> 8, 255);
01009             k1n = qMin((k1 * curveTable2[(int)cb]) >> 8, 255);
01010             c2n = qMin((c2 * curveTable3[(int)cb]) >> 8, 255);
01011             m2n = qMin((m2 * curveTable3[(int)cb]) >> 8, 255);
01012             y2n = qMin((y2 * curveTable3[(int)cb]) >> 8, 255);
01013             k2n = qMin((k2 * curveTable3[(int)cb]) >> 8, 255);
01014             ScColor col = ScColor(qMin(cn+c1n+c2n, 255), qMin(mn+m1n+m2n, 255), qMin(yn+y1n+y2n, 255), qMin(kn+k1n+k2n, 255));
01015             if (cmyk)
01016                 col.getCMYK(&cn, &mn, &yn, &kn);
01017             else
01018             {
01019                 col.getRawRGBColor(&cn, &mn, &yn);
01020                 kn = qAlpha(r);
01021             }
01022             *s = qRgba(cn, mn, yn, kn);
01023             s++;
01024         }
01025     }
01026 }
01027 
01028 void ScImage::quadtone(ScribusDoc* doc, ScColor color1, int shade1, FPointArray curve1, bool lin1, ScColor color2, int shade2, FPointArray curve2, bool lin2, ScColor color3, int shade3, FPointArray curve3, bool lin3, ScColor color4, int shade4, FPointArray curve4, bool lin4, bool cmyk)
01029 {
01030     int h = height();
01031     int w = width();
01032     int c, c1, c2, c3, m, m1, m2, m3, y, y1, y2, y3, k, k1, k2, k3;
01033     int cn, c1n, c2n, c3n, mn, m1n, m2n, m3n, yn, y1n, y2n, y3n, kn, k1n, k2n, k3n;
01034     uchar cb;
01035     CMYKColor cmykCol;
01036     QVector<int> curveTable1;
01037     QVector<int> curveTable2;
01038     QVector<int> curveTable3;
01039     QVector<int> curveTable4;
01040     ScColorEngine::getShadeColorCMYK(color1, doc, cmykCol, shade1);
01041     cmykCol.getValues(c, m, y, k);
01042     ScColorEngine::getShadeColorCMYK(color2, doc, cmykCol, shade2);
01043     cmykCol.getValues(c1, m1, y1, k1);
01044     ScColorEngine::getShadeColorCMYK(color3, doc, cmykCol, shade3);
01045     cmykCol.getValues(c2, m2, y2, k2);
01046     ScColorEngine::getShadeColorCMYK(color4, doc, cmykCol, shade4);
01047     cmykCol.getValues(c3, m3, y3, k3);
01048     curveTable1.resize(256);
01049     for (int x = 0 ; x < 256 ; x++)
01050     {
01051         curveTable1[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve1, x / 255.0, lin1) * 255)));
01052     }
01053     curveTable2.resize(256);
01054     for (int x = 0 ; x < 256 ; x++)
01055     {
01056         curveTable2[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve2, x / 255.0, lin2) * 255)));
01057     }
01058     curveTable3.resize(256);
01059     for (int x = 0 ; x < 256 ; x++)
01060     {
01061         curveTable3[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve3, x / 255.0, lin3) * 255)));
01062     }
01063     curveTable4.resize(256);
01064     for (int x = 0 ; x < 256 ; x++)
01065     {
01066         curveTable4[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve4, x / 255.0, lin4) * 255)));
01067     }
01068     for( int yi=0; yi < h; ++yi )
01069     {
01070         QRgb * s = (QRgb*)(scanLine( yi ));
01071         for( int xi=0; xi < w; ++xi )
01072         {
01073             QRgb r=*s;
01074             if (cmyk)
01075                 cb = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r) + qAlpha(r)), 255);
01076             else
01077                 cb = 255 - qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255);
01078             cn = qMin((c * curveTable1[(int)cb]) >> 8, 255);
01079             mn = qMin((m * curveTable1[(int)cb]) >> 8, 255);
01080             yn = qMin((y * curveTable1[(int)cb]) >> 8, 255);
01081             kn = qMin((k * curveTable1[(int)cb]) >> 8, 255);
01082             c1n = qMin((c1 * curveTable2[(int)cb]) >> 8, 255);
01083             m1n = qMin((m1 * curveTable2[(int)cb]) >> 8, 255);
01084             y1n = qMin((y1 * curveTable2[(int)cb]) >> 8, 255);
01085             k1n = qMin((k1 * curveTable2[(int)cb]) >> 8, 255);
01086             c2n = qMin((c2 * curveTable3[(int)cb]) >> 8, 255);
01087             m2n = qMin((m2 * curveTable3[(int)cb]) >> 8, 255);
01088             y2n = qMin((y2 * curveTable3[(int)cb]) >> 8, 255);
01089             k2n = qMin((k2 * curveTable3[(int)cb]) >> 8, 255);
01090             c3n = qMin((c3 * curveTable4[(int)cb]) >> 8, 255);
01091             m3n = qMin((m3 * curveTable4[(int)cb]) >> 8, 255);
01092             y3n = qMin((y3 * curveTable4[(int)cb]) >> 8, 255);
01093             k3n = qMin((k3 * curveTable4[(int)cb]) >> 8, 255);
01094             ScColor col = ScColor(qMin(cn+c1n+c2n+c3n, 255), qMin(mn+m1n+m2n+m3n, 255), qMin(yn+y1n+y2n+y3n, 255), qMin(kn+k1n+k2n+k3n, 255));
01095             if (cmyk)
01096                 col.getCMYK(&cn, &mn, &yn, &kn);
01097             else
01098             {
01099                 col.getRawRGBColor(&cn, &mn, &yn);
01100                 kn = qAlpha(r);
01101             }
01102             *s = qRgba(cn, mn, yn, kn);
01103             s++;
01104         }
01105     }
01106 }
01107 
01108 void ScImage::invert(bool cmyk)
01109 {
01110     int h = height();
01111     int w = width();
01112     unsigned char *p;
01113     QRgb * s;
01114     unsigned char c, m, y, k;
01115     for( int yi=0; yi < h; ++yi )
01116     {
01117         s = (QRgb*)(scanLine( yi ));
01118         for( int xi=0; xi < w; ++xi )
01119         {
01120             if (cmyk)
01121             {
01122                 p = (unsigned char *) s;
01123                 c = 255 - qMin(255, p[0] + p[3]);
01124                 m = 255 - qMin(255, p[1] + p[3]);
01125                 y = 255 - qMin(255, p[2] + p[3]);
01126                 k = qMin(qMin(c, m), y);
01127                 p[0] = c - k;
01128                 p[1] = m - k;
01129                 p[2] = y - k;
01130                 p[3] = k;
01131             }
01132             else
01133                 *s ^= 0x00ffffff;
01134             s++;
01135         }
01136     }
01137 }
01138 
01139 void ScImage::toGrayscale(bool cmyk)
01140 {
01141     int h = height();
01142     int w = width();
01143     int k;
01144     QRgb * s;
01145     QRgb r;
01146     for( int yi=0; yi < h; ++yi )
01147     {
01148         s = (QRgb*)(scanLine( yi ));
01149         for( int xi=0; xi < w; ++xi )
01150         {
01151             r = *s;
01152             if (cmyk)
01153             {
01154                 k = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r) + qAlpha(r)), 255);
01155                 *s = qRgba(0, 0, 0, k);
01156             }
01157             else
01158             {
01159                 k = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255);
01160                 *s = qRgba(k, k, k, qAlpha(r));
01161             }
01162             s++;
01163         }
01164     }
01165 }
01166 
01167 void ScImage::swapRGBA()
01168 {
01169     unsigned int *ptr;
01170     unsigned char *p;
01171     unsigned char r, b;
01172     for (int i = 0; i < height(); ++i)
01173     {
01174         ptr = (unsigned int *) scanLine(i);
01175         for (int j = 0; j < width(); ++j)
01176         {
01177             p = (unsigned char *) ptr;
01178             r = p[0];
01179             b = p[2];
01180             p[2] = r;
01181             p[0] = b;
01182             ptr++;
01183         }
01184     }
01185 }
01186 
01187 void ScImage::createLowRes(double scale)
01188 {
01189     int w = qRound(width() / scale);
01190     int h = qRound(height() / scale);
01191     QImage tmp = scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
01192     QImage::operator=(QImage(w, h, QImage::Format_ARGB32));
01193     tmp = tmp.convertToFormat(QImage::Format_ARGB32);
01194     QRgb *s;
01195     QRgb *d;
01196     for( int yi=0; yi < tmp.height(); ++yi )
01197     {
01198         s = (QRgb*)(tmp.scanLine( yi ));
01199         d = (QRgb*)(scanLine( yi ));
01200         for(int xi=0; xi < tmp.width(); ++xi )
01201         {
01202             (*d) = (*s);
01203             s++;
01204             d++;
01205         }
01206     }
01207 }
01208 
01209 void ScImage::Convert2JPG(QString fn, int Quality, bool isCMYK, bool isGray)
01210 {
01211     struct jpeg_compress_struct cinfo;
01212     struct my_error_mgr         jerr;
01213     FILE     *outfile;
01214     JSAMPROW row_pointer[1];
01215     row_pointer[0] = 0;
01216     cinfo.err = jpeg_std_error (&jerr.pub);
01217     jerr.pub.error_exit = my_error_exit;
01218     outfile = NULL;
01219     if (setjmp (jerr.setjmp_buffer))
01220     {
01221         jpeg_destroy_compress (&cinfo);
01222         if (outfile)
01223             fclose (outfile);
01224         return;
01225     }
01226     jpeg_create_compress (&cinfo);
01227     if ((outfile = fopen (fn.toLocal8Bit(), "wb")) == NULL)
01228         return;
01229     jpeg_stdio_dest (&cinfo, outfile);
01230     cinfo.image_width  = width();
01231     cinfo.image_height = height();
01232     if (isCMYK)
01233     {
01234         cinfo.in_color_space = JCS_CMYK;
01235         cinfo.input_components = 4;
01236     }
01237     else
01238     {
01239         if (isGray)
01240         {
01241             cinfo.in_color_space = JCS_GRAYSCALE;
01242             cinfo.input_components = 1;
01243         }
01244         else
01245         {
01246             cinfo.in_color_space = JCS_RGB;
01247             cinfo.input_components = 3;
01248         }
01249     }
01250     jpeg_set_defaults (&cinfo);
01251     int qual[] = { 95, 85, 75, 50, 25 };  // These are the JPEG Quality settings 100 means best, 0 .. don't discuss
01252     jpeg_set_quality (&cinfo, qual[Quality], true);
01253     jpeg_start_compress (&cinfo, true);
01254     row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
01255     int w = cinfo.image_width;
01256     while (cinfo.next_scanline < cinfo.image_height)
01257     {
01258         uchar *row = row_pointer[0];
01259         if (isCMYK)
01260         {
01261             QRgb* rgba = (QRgb*)scanLine(cinfo.next_scanline);
01262             for (int i=0; i<w; ++i)
01263             {
01264                 *row++ = 255-qRed(*rgba);
01265                 *row++ = 255-qGreen(*rgba);
01266                 *row++ = 255-qBlue(*rgba);
01267                 *row++ = 255-qAlpha(*rgba);
01268                 ++rgba;
01269             }
01270         }
01271         else
01272         {
01273             if (isGray)
01274             {
01275                 QRgb* rgba = (QRgb*)scanLine(cinfo.next_scanline);
01276                 for (int i=0; i<w; ++i)
01277                 {
01278                     *row++ = qRed(*rgba);
01279                     ++rgba;
01280                 }
01281             }
01282             else
01283             {
01284                 QRgb* rgb = (QRgb*)scanLine(cinfo.next_scanline);
01285                 for (int i=0; i<w; i++)
01286                 {
01287                     *row++ = qRed(*rgb);
01288                     *row++ = qGreen(*rgb);
01289                     *row++ = qBlue(*rgb);
01290                     ++rgb;
01291                 }
01292             }
01293         }
01294         jpeg_write_scanlines (&cinfo, row_pointer, 1);
01295     }
01296     jpeg_finish_compress (&cinfo);
01297     fclose (outfile);
01298     jpeg_destroy_compress (&cinfo);
01299     delete [] row_pointer[0];
01300 }
01301 
01302 QByteArray ScImage::ImageToArray()
01303 {
01304     int i = 0;
01305     int h = height();
01306     int w = width();
01307     unsigned char u;
01308     QRgb *s;
01309     QRgb r;
01310     QByteArray imgArray(3 * h * w, ' ');
01311     if (imgArray.isNull())
01312         return imgArray;
01313     for( int yi=0; yi < h; ++yi )
01314     {
01315         s = (QRgb*)(scanLine( yi ));
01316         for( int xi=0; xi < w; ++xi )
01317         {
01318             r = *s++;
01319             u=qRed(r);
01320             imgArray[i++] = u;
01321             u=qGreen(r);
01322             imgArray[i++] = u;
01323             u=qBlue(r);
01324             imgArray[i++] = u;
01325         }
01326     }
01327     return imgArray;
01328 }
01329 
01330 QByteArray ScImage::ImageToGray()
01331 {
01332     int i = 0, k;
01333     int h = height();
01334     int w = width();
01335     QRgb *s;
01336     QRgb r;
01337     QByteArray imgArray(h * w, ' ');
01338     if (imgArray.isNull())
01339         return imgArray;
01340     for( int yi=0; yi < h; ++yi )
01341     {
01342         s = (QRgb*)(scanLine( yi ));
01343         for( int xi=0; xi < w; ++xi )
01344         {
01345             r = *s;
01346             k = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255);
01347             *s = qRgba(k, 0, 0, 0);
01348             imgArray[i++] = k;
01349             s++;
01350         }
01351     }
01352     return imgArray;
01353 }
01354 
01355 QByteArray ScImage::ImageToCMYK_PDF()
01356 {
01357     int i = 0;
01358     int h = height();
01359     int w = width();
01360     QRgb *s;
01361     QRgb r;
01362     QByteArray imgArray( 4 * h * w, ' ' );
01363     if (imgArray.isNull()) // Memory allocation failure
01364         return imgArray;
01365     for( int yi=0; yi < h; ++yi )
01366     {
01367         s = (QRgb*)(scanLine( yi ));
01368         for( int xi=0; xi < w; ++xi )