/* For general Scribus (>=1.3.2) copyright and licensing information please refer to the COPYING file provided with the program. Following this notice may exist a copyright and/or license notice that predates the release of Scribus 1.3.2 for which a new license (GPL+exception) is in place. */ #include "cmsettings.h" #include "scclocale.h" #include "scimage.h" #include "scribus.h" #include "scpaths.h" #include "scribuscore.h" #include "scimgdataloader_gimp.h" #include "scimgdataloader_jpeg.h" #include "scimgdataloader_ps.h" #include "scimgdataloader_psd.h" #include "scimgdataloader_pdf.h" #include "scimgdataloader_qt.h" #include "scimgdataloader_tiff.h" #include "sctextstream.h" #include #include #include #include #include #include #include #include #include "colormgmt/sccolormgmtengine.h" #include "commonstrings.h" #include "exif.h" #include "util_ghostscript.h" #include "rawimage.h" #include "sccolorengine.h" #include "util.h" #include "util_color.h" #include "util_formats.h" #include "scstreamfilter.h" extern "C" { #define XMD_H // shut JPEGlib up #if defined(Q_OS_UNIXWARE) # define HAVE_BOOLEAN // libjpeg under Unixware seems to need this #endif #include #include #undef HAVE_STDLIB_H #ifdef const # undef const // remove crazy C hackery in jconfig.h #endif } using namespace std; typedef struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ } *my_error_ptr; static void my_error_exit (j_common_ptr cinfo) { my_error_ptr myerr = (my_error_ptr) cinfo->err; (*cinfo->err->output_message) (cinfo); longjmp (myerr->setjmp_buffer, 1); } ScImage::ScImage(const QImage & image) : QImage(image) { initialize(); } // ScImage will use implicit sharing: ScImage::ScImage(const ScImage & image) : QImage(image.copy()) { initialize(); } ScImage::ScImage() : QImage() { initialize(); } ScImage::ScImage( int width, int height ) : QImage( width, height, QImage::Format_ARGB32 ) { initialize(); } const QImage& ScImage::qImage() { return *this; } QImage* ScImage::qImagePtr() { return this; } QImage ScImage::scaled(int h, int w, Qt::AspectRatioMode mode, Qt::TransformationMode transformMode) const { return QImage::scaled(h, w, mode, transformMode); } void ScImage::initialize() { imgInfo.xres = 72; imgInfo.yres = 72; imgInfo.colorspace = ColorSpaceRGB; imgInfo.valid = false; imgInfo.isRequest = false; imgInfo.isEmbedded = false; imgInfo.progressive = false; imgInfo.exifDataValid = false; imgInfo.lowResType = 1; imgInfo.lowResScale = 1.0; imgInfo.PDSpathData.clear(); imgInfo.RequestProps.clear(); imgInfo.clipPath = ""; imgInfo.usedPath = ""; imgInfo.layerInfo.clear(); imgInfo.duotoneColors.clear(); imgInfo.exifInfo.cameraName = ""; imgInfo.exifInfo.cameraVendor = ""; imgInfo.exifInfo.thumbnail = QImage(); imgInfo.BBoxX = 0; imgInfo.BBoxH = 0; } ScImage::~ScImage() { } void ScImage::applyEffect(const ScImageEffectList& effectsList, ColorList& colors, bool cmyk) { ScribusDoc* doc = colors.document(); if (effectsList.count() != 0) { for (int a = 0; a < effectsList.count(); ++a) { if (effectsList.at(a).effectCode == EF_INVERT) invert(cmyk); if (effectsList.at(a).effectCode == EF_GRAYSCALE) toGrayscale(cmyk); if (effectsList.at(a).effectCode == EF_COLORIZE) { QString tmpstr = effectsList.at(a).effectParameters; QString col = CommonStrings::None; int shading = 100; ScTextStream fp(&tmpstr, QIODevice::ReadOnly); // fp >> col; col = fp.readLine(); fp >> shading; colorize(doc, colors[col], shading, cmyk); } if (effectsList.at(a).effectCode == EF_BRIGHTNESS) { QString tmpstr = effectsList.at(a).effectParameters; int brightnessValue = 0; ScTextStream fp(&tmpstr, QIODevice::ReadOnly); fp >> brightnessValue; brightness(brightnessValue, cmyk); } if (effectsList.at(a).effectCode == EF_CONTRAST) { QString tmpstr = effectsList.at(a).effectParameters; int contrastValue = 0; ScTextStream fp(&tmpstr, QIODevice::ReadOnly); fp >> contrastValue; contrast(contrastValue, cmyk); } if (effectsList.at(a).effectCode == EF_SHARPEN) { QString tmpstr = effectsList.at(a).effectParameters; double radius, sigma; ScTextStream fp(&tmpstr, QIODevice::ReadOnly); fp >> radius; fp >> sigma; sharpen(radius, sigma); } if (effectsList.at(a).effectCode == EF_BLUR) { QString tmpstr = effectsList.at(a).effectParameters; double radius, sigma; ScTextStream fp(&tmpstr, QIODevice::ReadOnly); fp >> radius; fp >> sigma; blur(static_cast(radius)); } if (effectsList.at(a).effectCode == EF_SOLARIZE) { QString tmpstr = effectsList.at(a).effectParameters; double sigma; ScTextStream fp(&tmpstr, QIODevice::ReadOnly); fp >> sigma; solarize(sigma, cmyk); } if (effectsList.at(a).effectCode == EF_DUOTONE) { QString tmpstr = effectsList.at(a).effectParameters; QString col1 = CommonStrings::None; int shading1 = 100; QString col2 = CommonStrings::None; int shading2 = 100; ScTextStream fp(&tmpstr, QIODevice::ReadOnly); col1 = fp.readLine(); col2 = fp.readLine(); fp >> shading1; fp >> shading2; int numVals; double xval, yval; FPointArray curve1; curve1.resize(0); fp >> numVals; for (int nv = 0; nv < numVals; nv++) { fp >> xval; fp >> yval; curve1.addPoint(xval, yval); } int lin1; fp >> lin1; FPointArray curve2; curve2.resize(0); fp >> numVals; for (int nv = 0; nv < numVals; nv++) { fp >> xval; fp >> yval; curve2.addPoint(xval, yval); } int lin2; fp >> lin2; duotone(doc, colors[col1], shading1, curve1, lin1, colors[col2], shading2, curve2, lin2, cmyk); } if (effectsList.at(a).effectCode == EF_TRITONE) { QString tmpstr = effectsList.at(a).effectParameters; QString col1 = CommonStrings::None; QString col2 = CommonStrings::None; QString col3 = CommonStrings::None; int shading1 = 100; int shading2 = 100; int shading3 = 100; ScTextStream fp(&tmpstr, QIODevice::ReadOnly); col1 = fp.readLine(); col2 = fp.readLine(); col3 = fp.readLine(); fp >> shading1; fp >> shading2; fp >> shading3; int numVals; double xval, yval; FPointArray curve1; curve1.resize(0); fp >> numVals; for (int nv = 0; nv < numVals; nv++) { fp >> xval; fp >> yval; curve1.addPoint(xval, yval); } int lin1; fp >> lin1; FPointArray curve2; curve2.resize(0); fp >> numVals; for (int nv = 0; nv < numVals; nv++) { fp >> xval; fp >> yval; curve2.addPoint(xval, yval); } int lin2; fp >> lin2; FPointArray curve3; curve3.resize(0); fp >> numVals; for (int nv = 0; nv < numVals; nv++) { fp >> xval; fp >> yval; curve3.addPoint(xval, yval); } int lin3; fp >> lin3; tritone(doc, colors[col1], shading1, curve1, lin1, colors[col2], shading2, curve2, lin2, colors[col3], shading3, curve3, lin3, cmyk); } if (effectsList.at(a).effectCode == EF_QUADTONE) { QString tmpstr = effectsList.at(a).effectParameters; QString col1 = CommonStrings::None; QString col2 = CommonStrings::None; QString col3 = CommonStrings::None; QString col4 = CommonStrings::None; int shading1 = 100; int shading2 = 100; int shading3 = 100; int shading4 = 100; ScTextStream fp(&tmpstr, QIODevice::ReadOnly); col1 = fp.readLine(); col2 = fp.readLine(); col3 = fp.readLine(); col4 = fp.readLine(); fp >> shading1; fp >> shading2; fp >> shading3; fp >> shading4; int numVals; double xval, yval; FPointArray curve1; curve1.resize(0); fp >> numVals; for (int nv = 0; nv < numVals; nv++) { fp >> xval; fp >> yval; curve1.addPoint(xval, yval); } int lin1; fp >> lin1; FPointArray curve2; curve2.resize(0); fp >> numVals; for (int nv = 0; nv < numVals; nv++) { fp >> xval; fp >> yval; curve2.addPoint(xval, yval); } int lin2; fp >> lin2; FPointArray curve3; curve3.resize(0); fp >> numVals; for (int nv = 0; nv < numVals; nv++) { fp >> xval; fp >> yval; curve3.addPoint(xval, yval); } int lin3; fp >> lin3; FPointArray curve4; curve4.resize(0); fp >> numVals; for (int nv = 0; nv < numVals; nv++) { fp >> xval; fp >> yval; curve4.addPoint(xval, yval); } int lin4; fp >> lin4; quadtone(doc, colors[col1], shading1, curve1, lin1, colors[col2], shading2, curve2, lin2, colors[col3], shading3, curve3, lin3, colors[col4], shading4, curve4, lin4, cmyk); } if (effectsList.at(a).effectCode == EF_GRADUATE) { QString tmpstr = effectsList.at(a).effectParameters; int numVals; double xval, yval; FPointArray curve; curve.resize(0); ScTextStream fp(&tmpstr, QIODevice::ReadOnly); fp >> numVals; for (int nv = 0; nv < numVals; nv++) { fp >> xval; fp >> yval; curve.addPoint(xval, yval); } int lin; fp >> lin; doGraduate(curve, cmyk, lin); } } } } /* void ScImage::liberateMemory(void **memory) { assert(memory != (void **)NULL); if(*memory == (void *)NULL) return; free(*memory); *memory=(void *) NULL; } */ void ScImage::solarize(double factor, bool cmyk) { QVector curveTable(256); int fk = qRound(255 / factor); for (int i = 0; i < 256; ++i) { curveTable[i] = qMin(255, static_cast(i / fk) * fk); } applyCurve(curveTable, cmyk); } // Stack Blur Algorithm by Mario Klingemann void ScImage::blur(int radius) { if (radius < 1) { return; } QRgb *pix = (QRgb*)bits(); int w = width(); int h = height(); int wm = w-1; int hm = h-1; int wh = w*h; int div = radius+radius+1; int *r = new int[wh]; int *g = new int[wh]; int *b = new int[wh]; int *a = new int[wh]; int rsum, gsum, bsum, asum, x, y, i, yp, yi, yw; QRgb p; int *vmin = new int[qMax(w,h)]; int divsum = (div+1)>>1; divsum *= divsum; int *dv = new int[256*divsum]; for (i=0; i < 256*divsum; ++i) { dv[i] = (i/divsum); } yw = yi = 0; int **stack = new int*[div]; for(int i = 0; i < div; ++i) { stack[i] = new int[4]; } int stackpointer; int stackstart; int *sir; int rbs; int r1 = radius+1; int routsum, goutsum, boutsum, aoutsum; int rinsum, ginsum, binsum, ainsum; for (y = 0; y < h; ++y){ rinsum = ginsum = binsum = ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0; for(i =- radius; i <= radius; ++i) { p = pix[yi+qMin(wm,qMax(i,0))]; sir = stack[i+radius]; sir[0] = qRed(p); sir[1] = qGreen(p); sir[2] = qBlue(p); sir[3] = qAlpha(p); rbs = r1-abs(i); rsum += sir[0]*rbs; gsum += sir[1]*rbs; bsum += sir[2]*rbs; asum += sir[3]*rbs; if (i > 0){ rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; ainsum += sir[3]; } else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; aoutsum += sir[3]; } } stackpointer = radius; for (x=0; x < w; ++x) { r[yi] = dv[rsum]; g[yi] = dv[gsum]; b[yi] = dv[bsum]; a[yi] = dv[asum]; rsum -= routsum; gsum -= goutsum; bsum -= boutsum; asum -= aoutsum; stackstart = stackpointer-radius+div; sir = stack[stackstart%div]; routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2]; aoutsum -= sir[3]; if (y == 0) { vmin[x] = qMin(x+radius+1,wm); } p = pix[yw+vmin[x]]; sir[0] = qRed(p); sir[1] = qGreen(p); sir[2] = qBlue(p); sir[3] = qAlpha(p); rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; ainsum += sir[3]; rsum += rinsum; gsum += ginsum; bsum += binsum; asum += ainsum; stackpointer = (stackpointer+1)%div; sir = stack[(stackpointer)%div]; routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; aoutsum += sir[3]; rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2]; ainsum -= sir[3]; ++yi; } yw += w; } for (x=0; x < w; ++x){ rinsum = ginsum = binsum = ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0; yp =- radius * w; for(i=-radius; i <= radius; ++i) { yi=qMax(0,yp)+x; sir = stack[i+radius]; sir[0] = r[yi]; sir[1] = g[yi]; sir[2] = b[yi]; sir[3] = a[yi]; rbs = r1-abs(i); rsum += r[yi]*rbs; gsum += g[yi]*rbs; bsum += b[yi]*rbs; asum += a[yi]*rbs; if (i > 0) { rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; ainsum += sir[3]; } else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; aoutsum += sir[3]; } if (i < hm){ yp += w; } } yi = x; stackpointer = radius; for (y=0; y < h; ++y){ pix[yi] = qRgba(dv[rsum], dv[gsum], dv[bsum], dv[asum]); rsum -= routsum; gsum -= goutsum; bsum -= boutsum; asum -= aoutsum; stackstart = stackpointer-radius+div; sir = stack[stackstart%div]; routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2]; aoutsum -= sir[3]; if (x==0){ vmin[y] = qMin(y+r1,hm)*w; } p = x+vmin[y]; sir[0] = r[p]; sir[1] = g[p]; sir[2] = b[p]; sir[3] = a[p]; rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; ainsum += sir[3]; rsum += rinsum; gsum += ginsum; bsum += binsum; asum += ainsum; stackpointer = (stackpointer+1)%div; sir = stack[stackpointer]; routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; aoutsum += sir[3]; rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2]; ainsum -= sir[3]; yi += w; } } delete [] r; delete [] g; delete [] b; delete [] a; delete [] vmin; delete [] dv; for(int i = 0; i < div; ++i) { delete [] stack[i]; } delete [] stack; } bool ScImage::convolveImage(QImage *dest, const unsigned int order, const double *kernel) { long widthk; double red, green, blue, alpha; double normalize, *normal_kernel; register const double *k; register unsigned int *q; int x, y, mx, my, sx, sy; long i; int mcx, mcy; widthk = order; if((widthk % 2) == 0) return(false); normal_kernel = (double *)malloc(widthk*widthk*sizeof(double)); if(!normal_kernel) return(false); *dest = QImage(width(), height(), QImage::Format_ARGB32); normalize=0.0; for(i=0; i < (widthk*widthk); i++) normalize += kernel[i]; if(fabs(normalize) <= 1.0e-12) normalize=1.0; normalize=1.0/normalize; for(i=0; i < (widthk*widthk); i++) normal_kernel[i] = normalize*kernel[i]; for(y=0; y < dest->height(); ++y) { sy = y-(widthk/2); q = (unsigned int *)dest->scanLine(y); for(x=0; x < dest->width(); ++x) { k = normal_kernel; red = green = blue = alpha = 0; sy = y-(widthk/2); for(mcy=0; mcy < widthk; ++mcy, ++sy) { my = sy < 0 ? 0 : sy > height()-1 ? height()-1 : sy; sx = x+(-widthk/2); for(mcx=0; mcx < widthk; ++mcx, ++sx) { mx = sx < 0 ? 0 : sx > width()-1 ? width()-1 : sx; int px = pixel(mx, my); red += (*k)*(qRed(px)*257); green += (*k)*(qGreen(px)*257); blue += (*k)*(qBlue(px)*257); alpha += (*k)*(qAlpha(px)*257); ++k; } } red = red < 0 ? 0 : red > 65535 ? 65535 : red+0.5; green = green < 0 ? 0 : green > 65535 ? 65535 : green+0.5; blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue+0.5; alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha+0.5; *q++ = qRgba((unsigned char)(red/257UL), (unsigned char)(green/257UL), (unsigned char)(blue/257UL), (unsigned char)(alpha/257UL)); } } free(normal_kernel); return(true); } int ScImage::getOptimalKernelWidth(double radius, double sigma) { double normalize, value; long width; register long u; assert(sigma != 0.0); if(radius > 0.0) return((int)(2.0*ceil(radius)+1.0)); for(width=5; ;) { normalize=0.0; for(u=(-width/2); u <= (width/2); u++) normalize+=exp(-((double) u*u)/(2.0*sigma*sigma))/(2.50662827463100024161235523934010416269302368164062*sigma); u=width/2; value=exp(-((double) u*u)/(2.0*sigma*sigma))/(2.50662827463100024161235523934010416269302368164062*sigma)/normalize; if((long)(65535*value) <= 0) break; width+=2; } return((int)width-2); } void ScImage::sharpen(double radius, double sigma) { double alpha, normalize, *kernel; int widthk; register long i, u, v; QImage dest; if(sigma == 0.0) return; widthk = getOptimalKernelWidth(radius, sigma); if(width() < widthk) return; kernel = (double *)malloc(widthk*widthk*sizeof(double)); if(!kernel) return; i = 0; normalize=0.0; for (v=(-widthk/2); v <= (widthk/2); v++) { for (u=(-widthk/2); u <= (widthk/2); u++) { alpha=exp(-((double) u*u+v*v)/(2.0*sigma*sigma)); kernel[i]=alpha/(2.0*3.14159265358979323846264338327950288419716939937510*sigma*sigma); normalize+=kernel[i]; i++; } } kernel[i/2]=(-2.0)*normalize; convolveImage(&dest, widthk, kernel); free(kernel); // liberateMemory((void **) &kernel); for( int yi=0; yi < dest.height(); ++yi ) { QRgb *s = (QRgb*)(dest.scanLine( yi )); QRgb *d = (QRgb*)(scanLine( yi )); for(int xi=0; xi < dest.width(); ++xi ) { (*d) = (*s); s++; d++; } } return; } void ScImage::contrast(int contrastValue, bool cmyk) { QVector curveTable(256); QPoint p1(0,0 - contrastValue); QPoint p2(256, 256 + contrastValue); double mc = (p1.y() - p2.y()) / (double)(p1.x() - p2.x()); for (int i = 0; i < 256; ++i) { curveTable[i] = qMin(255, qMax(0, int(i * mc) + p1.y())); } applyCurve(curveTable, cmyk); } void ScImage::brightness(int brightnessValue, bool cmyk) { QVector curveTable(256); QPoint p1(0,0 + brightnessValue); QPoint p2(256, 256 + brightnessValue); double mc = (p1.y() - p2.y()) / (double)(p1.x() - p2.x()); for (int i = 0; i < 256; ++i) { curveTable[i] = qMin(255, qMax(0, int(i * mc) + p1.y())); } applyCurve(curveTable, cmyk); } void ScImage::doGraduate(FPointArray curve, bool cmyk, bool linear) { QVector curveTable(256); for (int x = 0 ; x < 256 ; x++) { curveTable[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve, x / 255.0, linear) * 255))); } applyCurve(curveTable, cmyk); } void ScImage::applyCurve(const QVector& curveTable, bool cmyk) { int h = height(); int w = width(); QRgb *s; QRgb r; int c, m, y, k; unsigned char *p; for( int yi=0; yi < h; ++yi ) { s = (QRgb*)(scanLine( yi )); for( int xi=0; xi < w; ++xi ) { r = *s; if (cmyk) { p = (unsigned char *) s; p[0] = 255 - curveTable[255 - p[0]]; p[1] = 255 - curveTable[255 - p[1]]; p[2] = 255 - curveTable[255 - p[2]]; p[3] = 255 - curveTable[255 - p[3]]; } else { c = curveTable[qRed(r)]; m = curveTable[qGreen(r)]; y = curveTable[qBlue(r)]; k = qAlpha(r); *s = qRgba(c, m, y, k); } s++; } } } void ScImage::colorize(ScribusDoc* doc, ScColor color, int shade, bool cmyk) { int h = height(); int w = width(); int cc, cm, cy, ck; int hu, sa, v; ScColor tmp2; QColor tmpR; QRgb *s; QRgb r; double k; int cc2, cm2, cy2, k2; if (cmyk) { CMYKColor cmykCol; ScColorEngine::getShadeColorCMYK(color, doc, cmykCol, shade); cmykCol.getValues(cc, cm, cy, ck); } else { ck = 0; RGBColor rgbCol; ScColorEngine::getShadeColorRGB(color, doc, rgbCol, shade); rgbCol.getValues(cc, cm, cy); } for( int yi=0; yi < h; ++yi ) { s = (QRgb*)(scanLine( yi )); for( int xi=0; xi < w; ++xi ) { r = *s; if (cmyk) { k = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r) + qAlpha(r)), 255) / 255.0; *s = qRgba(qMin(qRound(cc*k), 255), qMin(qRound(cm*k), 255), qMin(qRound(cy*k), 255), qMin(qRound(ck*k), 255)); } else { k2 = 255 - qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255); tmpR.setRgb(cc, cm, cy); tmpR.getHsv(&hu, &sa, &v); tmpR.setHsv(hu, sa * k2 / 255, 255 - ((255 - v) * k2 / 255)); tmpR.getRgb(&cc2, &cm2, &cy2); *s = qRgba(cc2, cm2, cy2, qAlpha(r)); } s++; } } } void ScImage::duotone(ScribusDoc* doc, ScColor color1, int shade1, FPointArray curve1, bool lin1, ScColor color2, int shade2, FPointArray curve2, bool lin2, bool cmyk) { int h = height(); int w = width(); int c, c1, m, m1, y, y1, k, k1; int cn, c1n, mn, m1n, yn, y1n, kn, k1n; uchar cb; QVector curveTable1; QVector curveTable2; CMYKColor cmykCol; ScColorEngine::getShadeColorCMYK(color1, doc, cmykCol, shade1); cmykCol.getValues(c, m, y, k); ScColorEngine::getShadeColorCMYK(color2, doc, cmykCol, shade2); cmykCol.getValues(c1, m1, y1, k1); curveTable1.resize(256); for (int x = 0 ; x < 256 ; x++) { curveTable1[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve1, x / 255.0, lin1) * 255))); } curveTable2.resize(256); for (int x = 0 ; x < 256 ; x++) { curveTable2[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve2, x / 255.0, lin2) * 255))); } for( int yi=0; yi < h; ++yi ) { QRgb * s = (QRgb*)(scanLine( yi )); for( int xi=0; xi < w; ++xi ) { QRgb r=*s; if (cmyk) cb = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r) + qAlpha(r)), 255); else cb = 255 - qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255); cn = qMin((c * curveTable1[(int)cb]) >> 8, 255); mn = qMin((m * curveTable1[(int)cb]) >> 8, 255); yn = qMin((y * curveTable1[(int)cb]) >> 8, 255); kn = qMin((k * curveTable1[(int)cb]) >> 8, 255); c1n = qMin((c1 * curveTable1[(int)cb]) >> 8, 255); m1n = qMin((m1 * curveTable2[(int)cb]) >> 8, 255); y1n = qMin((y1 * curveTable2[(int)cb]) >> 8, 255); k1n = qMin((k1 * curveTable2[(int)cb]) >> 8, 255); ScColor col = ScColor(qMin(cn+c1n, 255), qMin(mn+m1n, 255), qMin(yn+y1n, 255), qMin(kn+k1n, 255)); if (cmyk) col.getCMYK(&cn, &mn, &yn, &kn); else { col.getRawRGBColor(&cn, &mn, &yn); kn = qAlpha(r); } *s = qRgba(cn, mn, yn, kn); s++; } } } 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) { int h = height(); int w = width(); int c, c1, c2, m, m1, m2, y, y1, y2, k, k1, k2; int cn, c1n, c2n, mn, m1n, m2n, yn, y1n, y2n, kn, k1n, k2n; uchar cb; CMYKColor cmykCol; QVector curveTable1; QVector curveTable2; QVector curveTable3; ScColorEngine::getShadeColorCMYK(color1, doc, cmykCol, shade1); cmykCol.getValues(c, m, y, k); ScColorEngine::getShadeColorCMYK(color2, doc, cmykCol, shade2); cmykCol.getValues(c1, m1, y1, k1); ScColorEngine::getShadeColorCMYK(color3, doc, cmykCol, shade3); cmykCol.getValues(c2, m2, y2, k2); curveTable1.resize(256); for (int x = 0 ; x < 256 ; x++) { curveTable1[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve1, x / 255.0, lin1) * 255))); } curveTable2.resize(256); for (int x = 0 ; x < 256 ; x++) { curveTable2[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve2, x / 255.0, lin2) * 255))); } curveTable3.resize(256); for (int x = 0 ; x < 256 ; x++) { curveTable3[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve2, x / 255.0, lin3) * 255))); } for( int yi=0; yi < h; ++yi ) { QRgb * s = (QRgb*)(scanLine( yi )); for( int xi=0; xi < w; ++xi ) { QRgb r=*s; if (cmyk) cb = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r) + qAlpha(r)), 255); else cb = 255 - qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255); cn = qMin((c * curveTable1[(int)cb]) >> 8, 255); mn = qMin((m * curveTable1[(int)cb]) >> 8, 255); yn = qMin((y * curveTable1[(int)cb]) >> 8, 255); kn = qMin((k * curveTable1[(int)cb]) >> 8, 255); c1n = qMin((c1 * curveTable2[(int)cb]) >> 8, 255); m1n = qMin((m1 * curveTable2[(int)cb]) >> 8, 255); y1n = qMin((y1 * curveTable2[(int)cb]) >> 8, 255); k1n = qMin((k1 * curveTable2[(int)cb]) >> 8, 255); c2n = qMin((c2 * curveTable3[(int)cb]) >> 8, 255); m2n = qMin((m2 * curveTable3[(int)cb]) >> 8, 255); y2n = qMin((y2 * curveTable3[(int)cb]) >> 8, 255); k2n = qMin((k2 * curveTable3[(int)cb]) >> 8, 255); ScColor col = ScColor(qMin(cn+c1n+c2n, 255), qMin(mn+m1n+m2n, 255), qMin(yn+y1n+y2n, 255), qMin(kn+k1n+k2n, 255)); if (cmyk) col.getCMYK(&cn, &mn, &yn, &kn); else { col.getRawRGBColor(&cn, &mn, &yn); kn = qAlpha(r); } *s = qRgba(cn, mn, yn, kn); s++; } } } 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) { int h = height(); int w = width(); int c, c1, c2, c3, m, m1, m2, m3, y, y1, y2, y3, k, k1, k2, k3; int cn, c1n, c2n, c3n, mn, m1n, m2n, m3n, yn, y1n, y2n, y3n, kn, k1n, k2n, k3n; uchar cb; CMYKColor cmykCol; QVector curveTable1; QVector curveTable2; QVector curveTable3; QVector curveTable4; ScColorEngine::getShadeColorCMYK(color1, doc, cmykCol, shade1); cmykCol.getValues(c, m, y, k); ScColorEngine::getShadeColorCMYK(color2, doc, cmykCol, shade2); cmykCol.getValues(c1, m1, y1, k1); ScColorEngine::getShadeColorCMYK(color3, doc, cmykCol, shade3); cmykCol.getValues(c2, m2, y2, k2); ScColorEngine::getShadeColorCMYK(color4, doc, cmykCol, shade4); cmykCol.getValues(c3, m3, y3, k3); curveTable1.resize(256); for (int x = 0 ; x < 256 ; x++) { curveTable1[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve1, x / 255.0, lin1) * 255))); } curveTable2.resize(256); for (int x = 0 ; x < 256 ; x++) { curveTable2[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve2, x / 255.0, lin2) * 255))); } curveTable3.resize(256); for (int x = 0 ; x < 256 ; x++) { curveTable3[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve3, x / 255.0, lin3) * 255))); } curveTable4.resize(256); for (int x = 0 ; x < 256 ; x++) { curveTable4[x] = qMin(255, qMax(0, qRound(getCurveYValue(curve4, x / 255.0, lin4) * 255))); } for( int yi=0; yi < h; ++yi ) { QRgb * s = (QRgb*)(scanLine( yi )); for( int xi=0; xi < w; ++xi ) { QRgb r=*s; if (cmyk) cb = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r) + qAlpha(r)), 255); else cb = 255 - qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255); cn = qMin((c * curveTable1[(int)cb]) >> 8, 255); mn = qMin((m * curveTable1[(int)cb]) >> 8, 255); yn = qMin((y * curveTable1[(int)cb]) >> 8, 255); kn = qMin((k * curveTable1[(int)cb]) >> 8, 255); c1n = qMin((c1 * curveTable2[(int)cb]) >> 8, 255); m1n = qMin((m1 * curveTable2[(int)cb]) >> 8, 255); y1n = qMin((y1 * curveTable2[(int)cb]) >> 8, 255); k1n = qMin((k1 * curveTable2[(int)cb]) >> 8, 255); c2n = qMin((c2 * curveTable3[(int)cb]) >> 8, 255); m2n = qMin((m2 * curveTable3[(int)cb]) >> 8, 255); y2n = qMin((y2 * curveTable3[(int)cb]) >> 8, 255); k2n = qMin((k2 * curveTable3[(int)cb]) >> 8, 255); c3n = qMin((c3 * curveTable4[(int)cb]) >> 8, 255); m3n = qMin((m3 * curveTable4[(int)cb]) >> 8, 255); y3n = qMin((y3 * curveTable4[(int)cb]) >> 8, 255); k3n = qMin((k3 * curveTable4[(int)cb]) >> 8, 255); 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)); if (cmyk) col.getCMYK(&cn, &mn, &yn, &kn); else { col.getRawRGBColor(&cn, &mn, &yn); kn = qAlpha(r); } *s = qRgba(cn, mn, yn, kn); s++; } } } void ScImage::invert(bool cmyk) { int h = height(); int w = width(); unsigned char *p; QRgb * s; unsigned char c, m, y, k; for( int yi=0; yi < h; ++yi ) { s = (QRgb*)(scanLine( yi )); for( int xi=0; xi < w; ++xi ) { if (cmyk) { p = (unsigned char *) s; c = 255 - qMin(255, p[0] + p[3]); m = 255 - qMin(255, p[1] + p[3]); y = 255 - qMin(255, p[2] + p[3]); k = qMin(qMin(c, m), y); p[0] = c - k; p[1] = m - k; p[2] = y - k; p[3] = k; } else *s ^= 0x00ffffff; s++; } } } void ScImage::toGrayscale(bool cmyk) { int h = height(); int w = width(); int k; QRgb * s; QRgb r; for( int yi=0; yi < h; ++yi ) { s = (QRgb*)(scanLine( yi )); for( int xi=0; xi < w; ++xi ) { r = *s; if (cmyk) { k = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r) + qAlpha(r)), 255); *s = qRgba(0, 0, 0, k); } else { k = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255); *s = qRgba(k, k, k, qAlpha(r)); } s++; } } } void ScImage::swapRGBA() { unsigned int *ptr; unsigned char *p; unsigned char r, b; for (int i = 0; i < height(); ++i) { ptr = (unsigned int *) scanLine(i); for (int j = 0; j < width(); ++j) { p = (unsigned char *) ptr; r = p[0]; b = p[2]; p[2] = r; p[0] = b; ptr++; } } } void ScImage::createLowRes(double scale) { int w = qRound(width() / scale); int h = qRound(height() / scale); QImage tmp = scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); if (tmp.format() != QImage::Format_ARGB32) tmp = tmp.convertToFormat(QImage::Format_ARGB32); QImage::operator=(tmp); } bool ScImage::Convert2JPG(QString fn, int Quality, bool isCMYK, bool isGray) { struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; FILE *outfile; JSAMPROW row_pointer[1]; row_pointer[0] = 0; cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; outfile = NULL; if (setjmp (jerr.setjmp_buffer)) { jpeg_destroy_compress (&cinfo); if (outfile) fclose (outfile); return false; } jpeg_create_compress (&cinfo); if ((outfile = fopen (fn.toLocal8Bit(), "wb")) == NULL) return false; jpeg_stdio_dest (&cinfo, outfile); cinfo.image_width = width(); cinfo.image_height = height(); if (isCMYK) { cinfo.in_color_space = JCS_CMYK; cinfo.input_components = 4; } else { if (isGray) { cinfo.in_color_space = JCS_GRAYSCALE; cinfo.input_components = 1; } else { cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; } } jpeg_set_defaults (&cinfo); int qual[] = { 95, 85, 75, 50, 25 }; // These are the JPEG Quality settings 100 means best, 0 .. don't discuss jpeg_set_quality (&cinfo, qual[Quality], true); jpeg_start_compress (&cinfo, true); row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components]; int w = cinfo.image_width; while (cinfo.next_scanline < cinfo.image_height) { uchar *row = row_pointer[0]; if (isCMYK) { QRgb* rgba = (QRgb*)scanLine(cinfo.next_scanline); for (int i=0; i(qRed(r)); buffer[pending++] = static_cast(qGreen(r)); buffer[pending++] = static_cast(qBlue(r)); } if (pending >= bufferSize) { success &= filter->writeData(buffer.constData(), pending); pending = 0; } } if (pending) success &= filter->writeData(buffer.constData(), pending); return success; } bool ScImage::writeGrayDataToFilter(ScStreamFilter* filter, bool precal) { QRgb r, *s; QByteArray buffer; bool success = true; int h = height(); int w = width(); int pending = 0, k; int scanLineSize = w; int bufferSize = qMax(scanLineSize, (65536 - 65536 % scanLineSize)); buffer.resize(bufferSize + 16); if (buffer.isNull()) // Memory allocation failure return false; for( int yi=0; yi < h; ++yi ) { s = (QRgb*)(scanLine( yi )); if (precal) // image data is already grayscale, no need for weighted conversion { for( int xi=0; xi < w; ++xi ) { r = *s; k = qRed(r); buffer[pending++] = k; s++; } } else { for( int xi=0; xi < w; ++xi ) { r = *s; k = qMin(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255); buffer[pending++] = k; s++; } } if (pending >= bufferSize) { success &= filter->writeData(buffer.constData(), pending); pending = 0; } } if (pending) success &= filter->writeData(buffer.constData(), pending); return success; } bool ScImage::writeCMYKDataToFilter(ScStreamFilter* filter) { QRgb r, *s; QByteArray buffer; bool success = true; int h = height(); int w = width(); int pending = 0; int scanLineSize = (4 * w); int bufferSize = qMax(scanLineSize, (65536 - 65536 % scanLineSize)); buffer.resize(bufferSize + 16); if (buffer.isNull()) // Memory allocation failure return false; for( int yi=0; yi < h; ++yi ) { s = (QRgb*)(scanLine( yi )); for( int xi=0; xi < w; ++xi ) { r = *s++; buffer[pending++] = static_cast (qRed(r)); buffer[pending++] = static_cast (qGreen(r)); buffer[pending++] = static_cast (qBlue(r)); buffer[pending++] = static_cast (qAlpha(r)); } if (pending >= bufferSize) { success &= filter->writeData(buffer.constData(), pending); pending = 0; } } if (pending) success &= filter->writeData(buffer.constData(), pending); return success; } bool ScImage::writePSImageToFilter(ScStreamFilter* filter, int pl) { QRgb r, *s; QByteArray buffer; bool success = true; int c, m, y, k; int h = height(); int w = width(); int pending = 0; int scanLineSize = (pl == -1) ? (4 * w) : w; int bufferSize = qMax(scanLineSize, (65536 - 65536 % scanLineSize)); buffer.resize(bufferSize + 16); if (buffer.isNull()) // Memory allocation failure return false; for( int yi=0; yi < h; ++yi ) { s = (QRgb*)(scanLine( yi )); for( int xi=0; xi < w; ++xi ) { r = *s++; c = qRed(r); m = qGreen(r); y = qBlue(r); k = qAlpha(r); if (pl == -1) { buffer[pending++] = static_cast (c); buffer[pending++] = static_cast (m); buffer[pending++] = static_cast (y); buffer[pending++] = static_cast (k); } else { if (pl == -2) buffer[pending++] = static_cast (qMin(255, qRound(0.3 * c + 0.59 * m + 0.11 * y + k))); if (pl == 1) buffer[pending++] = static_cast (c); if (pl == 2) buffer[pending++] = static_cast (m); if (pl == 3) buffer[pending++] = static_cast (y); if (pl == 0) buffer[pending++] = static_cast (k); } } if (pending >= bufferSize) { success &= filter->writeData(buffer.constData(), pending); pending = 0; } } if (pending) success &= filter->writeData(buffer.constData(), pending); return success; } bool ScImage::writePSImageToFilter(ScStreamFilter* filter, const QByteArray& mask, int pl) { QRgb r, *s; QByteArray buffer; bool success = true; int c, m, y, k; int h = height(); int w = width(); int pending = 0; int scanLineSize = (pl == -1) ? (5 * w) : (2 * w); int bufferSize = qMax(scanLineSize, (65536 - 65536 % scanLineSize)); if (mask.size() < (h * w)) // Check if mask provide enough data return false; buffer.resize(bufferSize + 16); if (buffer.isNull()) // Check for memory allocation failure return false; unsigned char* maskData = (unsigned char*) mask.constData(); for( int yi=0; yi < h; ++yi ) { s = (QRgb*)(scanLine( yi )); for( int xi=0; xi < w; ++xi ) { r = *s++; c = qRed(r); m = qGreen(r); y = qBlue(r); k = qAlpha(r); if (pl == -1) { buffer[pending++] = *maskData++; buffer[pending++] = static_cast (c); buffer[pending++] = static_cast (m); buffer[pending++] = static_cast (y); buffer[pending++] = static_cast (k); } else { buffer[pending++] = *maskData++; if (pl == -2) buffer[pending++] = static_cast (qMin(255, qRound(0.3 * c + 0.59 * m + 0.11 * y + k))); if (pl == 1) buffer[pending++] = static_cast (c); if (pl == 2) buffer[pending++] = static_cast (m); if (pl == 3) buffer[pending++] = static_cast (y); if (pl == 0) buffer[pending++] = static_cast (k); } } if (pending >= bufferSize) { success &= filter->writeData(buffer.constData(), pending); pending = 0; } } if (pending) success &= filter->writeData(buffer.constData(), pending); return success; } void ScImage::scaleImage(int nwidth, int nheight) { int depth = this->depth(); if (depth == 32) { scaleImage32bpp(nwidth, nheight); return; } scaleImageGeneric(nwidth, nheight); } void ScImage::scaleImage32bpp(int nwidth, int nheight) { QImage dst(nwidth, nheight, QImage::Format_ARGB32); QRgb* xelrow = 0; QRgb* tempxelrow = 0; register QRgb* xP; register QRgb* nxP; int rows, cols, rowsread, newrows, newcols; register int row, col, needtoreadrow; const uchar maxval = 255; double xscale, yscale; long sxscale, syscale; register long fracrowtofill, fracrowleft; long* as; long* rs; long* gs; long* bs; int rowswritten = 0; int depth = this->depth(); if (depth != 32) { QImage::operator=(QImage::scaled(nwidth, nheight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); return; } cols = width(); rows = height(); newcols = dst.width(); newrows = dst.height(); long SCALE; long HALFSCALE; if (cols > 4096) { SCALE = 4096; HALFSCALE = 2048; } else { int fac = 4096; while ((cols * fac) > 4096) { fac /= 2; } SCALE = fac * cols; HALFSCALE = fac * cols / 2; } xscale = (double) newcols / (double) cols; yscale = (double) newrows / (double) rows; sxscale = (long)(xscale * SCALE); syscale = (long)(yscale * SCALE); if ( newrows != rows ) /* shortcut Y scaling if possible */ tempxelrow = new QRgb[cols]; as = new long[cols]; rs = new long[cols]; gs = new long[cols]; bs = new long[cols]; rowsread = 0; fracrowleft = syscale; needtoreadrow = 1; for ( col = 0; col < cols; ++col ) rs[col] = gs[col] = as[col] = bs[col] = HALFSCALE; fracrowtofill = SCALE; for ( row = 0; row < newrows; ++row ) { if ( newrows == rows ) tempxelrow = xelrow = (QRgb*)scanLine(rowsread++); else { while ( fracrowleft < fracrowtofill ) { if ( needtoreadrow && rowsread < rows ) xelrow = (QRgb*)scanLine(rowsread++); for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) { as[col] += fracrowleft * qAlpha( *xP ); rs[col] += fracrowleft * qRed( *xP ); gs[col] += fracrowleft * qGreen( *xP ); bs[col] += fracrowleft * qBlue( *xP ); } fracrowtofill -= fracrowleft; fracrowleft = syscale; needtoreadrow = 1; } if ( needtoreadrow && rowsread < rows ) { xelrow = (QRgb*)scanLine(rowsread++); needtoreadrow = 0; } register long a=0; for ( col = 0, xP = xelrow, nxP = tempxelrow; col < cols; ++col, ++xP, ++nxP ) { register long r, g, b; a = as[col] + fracrowtofill * qAlpha( *xP ); r = rs[col] + fracrowtofill * qRed( *xP ); g = gs[col] + fracrowtofill * qGreen( *xP ); b = bs[col] + fracrowtofill * qBlue( *xP ); r /= SCALE; if ( r > maxval ) r = maxval; g /= SCALE; if ( g > maxval ) g = maxval; b /= SCALE; if ( b > maxval ) b = maxval; a /= SCALE; if ( a > maxval ) a = maxval; *nxP = qRgba( (int)r, (int)g, (int)b , (int)a); rs[col] = as[col] = gs[col] = bs[col] = HALFSCALE; } fracrowleft -= fracrowtofill; if ( fracrowleft == 0 ) { fracrowleft = syscale; needtoreadrow = 1; } fracrowtofill = SCALE; } if ( newcols == cols ) memcpy(dst.scanLine(rowswritten++), tempxelrow, newcols*4); else { register long a, r, g, b; register long fraccoltofill, fraccolleft = 0; register int needcol; nxP = (QRgb*)dst.scanLine(rowswritten++); fraccoltofill = SCALE; a = r = g = b = HALFSCALE; needcol = 0; for ( col = 0, xP = tempxelrow; col < cols; ++col, ++xP ) { fraccolleft = sxscale; while ( fraccolleft >= fraccoltofill ) { if ( needcol ) { ++nxP; a = r = g = b = HALFSCALE; } a += fraccoltofill * qAlpha( *xP ); r += fraccoltofill * qRed( *xP ); g += fraccoltofill * qGreen( *xP ); b += fraccoltofill * qBlue( *xP ); r /= SCALE; if ( r > maxval ) r = maxval; g /= SCALE; if ( g > maxval ) g = maxval; b /= SCALE; if ( b > maxval ) b = maxval; a /= SCALE; if ( a > maxval ) a = maxval; *nxP = qRgba( (int)r, (int)g, (int)b, (int)a ); fraccolleft -= fraccoltofill; fraccoltofill = SCALE; needcol = 1; } if ( fraccolleft > 0 ) { if ( needcol ) { ++nxP; a = r = g = b = HALFSCALE; needcol = 0; } a += fraccolleft * qAlpha( *xP ); r += fraccolleft * qRed( *xP ); g += fraccolleft * qGreen( *xP ); b += fraccolleft * qBlue( *xP ); fraccoltofill -= fraccolleft; } } if ( fraccoltofill > 0 ) { --xP; a += fraccolleft * qAlpha( *xP ); r += fraccoltofill * qRed( *xP ); g += fraccoltofill * qGreen( *xP ); b += fraccoltofill * qBlue( *xP ); } if ( ! needcol ) { r /= SCALE; if ( r > maxval ) r = maxval; g /= SCALE; if ( g > maxval ) g = maxval; b /= SCALE; if ( b > maxval ) b = maxval; a /= SCALE; if ( a > maxval ) a = maxval; *nxP = qRgba( (int)r, (int)g, (int)b, (int)a ); } } } if ( newrows != rows && tempxelrow )// Robust, tempxelrow might be 0 1 day delete [] tempxelrow; if ( as ) // Avoid purify complaint delete [] as; if ( rs ) // Robust, rs might be 0 one day delete [] rs; if ( gs ) // Robust, gs might be 0 one day delete [] gs; if ( bs ) // Robust, bs might be 0 one day delete [] bs; QImage::operator=(QImage(nwidth, nheight, QImage::Format_ARGB32)); for( int yi=0; yi < dst.height(); ++yi ) { QRgb *s = (QRgb*)(dst.scanLine( yi )); QRgb *d = (QRgb*)(scanLine( yi )); for(int xi=0; xi < dst.width(); ++xi ) { (*d) = (*s); s++; d++; } } return; } void ScImage::scaleImageGeneric(int nwidth, int nheight) { unsigned char* xelrow = 0; unsigned char* tempxelrow = 0; register unsigned char* xP; register unsigned char* nxP; int rows, cols, rowsread, newrows, newcols; register int row, col, needtoreadrow; const uchar maxval = 255; double xscale, yscale; long sxscale, syscale; register long fracrowtofill, fracrowleft; long* ps; int rowswritten = 0; int depth = this->depth(); Format imgFormat = this->format(); bool execScaled = (depth == 1 || depth == 4 || depth == 16); execScaled |= (imgFormat == QImage::Format_ARGB8565_Premultiplied); execScaled |= (imgFormat == QImage::Format_RGB666); execScaled |= (imgFormat == QImage::Format_ARGB6666_Premultiplied); execScaled |= (imgFormat == QImage::Format_ARGB8555_Premultiplied); if (execScaled) { QImage::operator=(QImage::scaled(nwidth, nheight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); return; } QImage dst(nwidth, nheight, this->format()); int nChannels = this->depth() / 8; cols = width(); rows = height(); newcols = dst.width(); newrows = dst.height(); long SCALE; long HALFSCALE; if (cols > 4096) { SCALE = 4096; HALFSCALE = 2048; } else { int fac = 4096; while ((cols * fac) > 4096) { fac /= 2; } SCALE = fac * cols; HALFSCALE = fac * cols / 2; } xscale = (double) newcols / (double) cols; yscale = (double) newrows / (double) rows; sxscale = (long)(xscale * SCALE); syscale = (long)(yscale * SCALE); if ( newrows != rows ) /* shortcut Y scaling if possible */ tempxelrow = new unsigned char[cols * nChannels]; ps = new long[cols]; for (int chIndex = 0; chIndex < nChannels; ++chIndex) { xelrow = 0; rowsread = rowswritten = 0; fracrowleft = syscale; needtoreadrow = 1; for (col = 0; col < cols; ++col) ps[col] = HALFSCALE; fracrowtofill = SCALE; for (row = 0; row < newrows; ++row) { if (newrows == rows) tempxelrow = xelrow = scanLine(rowsread++); else { while (fracrowleft < fracrowtofill) { if (needtoreadrow && rowsread < rows) xelrow = scanLine(rowsread++); for (col = 0, xP = xelrow + chIndex; col < cols; ++col, xP += nChannels) ps[col] += fracrowleft * (*xP); fracrowtofill -= fracrowleft; fracrowleft = syscale; needtoreadrow = 1; } if (needtoreadrow && rowsread < rows) { xelrow = scanLine(rowsread++); needtoreadrow = 0; } register long p = 0; xP = xelrow + chIndex; nxP = tempxelrow + chIndex; for (col = 0; col < cols; ++col, xP += nChannels, nxP += nChannels) { p = ps[col] + fracrowtofill * (*xP); p /= SCALE; if ( p > maxval ) p = maxval; *nxP = (unsigned char) p; ps[col] = HALFSCALE; } fracrowleft -= fracrowtofill; if ( fracrowleft == 0 ) { fracrowleft = syscale; needtoreadrow = 1; } fracrowtofill = SCALE; } if (newcols == cols) { memcpy(dst.scanLine(rowswritten++), tempxelrow, newcols * nChannels); } else { register long p; register long fraccoltofill, fraccolleft = 0; register int needcol; nxP = dst.scanLine(rowswritten++) + chIndex; fraccoltofill = SCALE; p = HALFSCALE; needcol = 0; for (col = 0, xP = tempxelrow + chIndex; col < cols; ++col, xP += nChannels) { fraccolleft = sxscale; while ( fraccolleft >= fraccoltofill ) { if ( needcol ) { nxP += nChannels; p = HALFSCALE; } p += fraccoltofill * ( *xP ); p /= SCALE; if ( p > maxval ) p = maxval; *nxP = (unsigned char) p; fraccolleft -= fraccoltofill; fraccoltofill = SCALE; needcol = 1; } if (fraccolleft > 0) { if (needcol) { nxP += nChannels; p = HALFSCALE; needcol = 0; } p += fraccolleft * (*xP); fraccoltofill -= fraccolleft; } } if (fraccoltofill > 0) { xP -= nChannels; p += fraccolleft * (*xP); } if (!needcol) { p /= SCALE; if ( p > maxval ) p = maxval; *nxP = (unsigned char) p; } } } } if (newrows != rows && tempxelrow)// Robust, tempxelrow might be 0 1 day delete [] tempxelrow; if (ps) // Avoid purify complaint delete [] ps; int scanWidth = dst.width() * nChannels; QImage::operator=(QImage(nwidth, nheight, this->format())); for( int yi=0; yi < dst.height(); ++yi ) { uchar *s = (dst.scanLine( yi )); uchar *d = (scanLine( yi )); memcpy(d, s, scanWidth); } return; } bool ScImage::getAlpha(QString fn, int page, QByteArray& alpha, bool PDF, bool pdf14, int gsRes, int scaleXSize, int scaleYSize) { bool gotAlpha = false; auto_ptr pDataLoader; imgInfo.valid = false; imgInfo.clipPath = ""; imgInfo.PDSpathData.clear(); imgInfo.layerInfo.clear(); QFileInfo fi = QFileInfo(fn); if (!fi.exists()) return false; alpha.resize(0); QString tmp, BBox, tmp2; QString ext = fi.suffix().toLower(); if (extensionIndicatesJPEG(ext)) return true; if (extensionIndicatesPDF(ext)) { pDataLoader.reset( new ScImgDataLoader_PDF() ); } else if (extensionIndicatesEPSorPS(ext)) { pDataLoader.reset( new ScImgDataLoader_PS() ); } else if (extensionIndicatesTIFF(ext)) { pDataLoader.reset( new ScImgDataLoader_TIFF() ); if (pDataLoader.get()) pDataLoader->setRequest(imgInfo.isRequest, imgInfo.RequestProps); } else if (extensionIndicatesPSD(ext)) { pDataLoader.reset( new ScImgDataLoader_PSD() ); if (pDataLoader.get()) pDataLoader->setRequest(imgInfo.isRequest, imgInfo.RequestProps); } else if (ext == "pat") pDataLoader.reset( new ScImgDataLoader_GIMP() ); else pDataLoader.reset( new ScImgDataLoader_QT() ); if (pDataLoader.get()) { bool hasAlpha = false; bool alphaLoaded = pDataLoader->preloadAlphaChannel(fn, page, gsRes, hasAlpha); if (!alphaLoaded || !hasAlpha) return alphaLoaded; QImage rImage; if (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)) { if (pDataLoader->imageInfoRecord().valid) { if ((pDataLoader->r_image.channels() == 5) || (pDataLoader->imageInfoRecord().colorspace == ColorSpaceCMYK)) rImage = pDataLoader->r_image.convertToQImage(true); else rImage = pDataLoader->r_image.convertToQImage(false); } } else rImage = pDataLoader->image(); if (rImage.isNull()) return false; if ((scaleXSize != 0) && (scaleYSize != 0) && (scaleXSize != rImage.width() || scaleYSize != rImage.height())) rImage = rImage.scaled(scaleXSize, scaleYSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); int i = 0, w2; unsigned char u; int hm = rImage.height(); int wm = rImage.width(); QRgb r, *s; if (pdf14) { alpha.resize(hm * wm); if (alpha.size() > 0) // { for( int yi=0; yi < hm; ++yi ) { s = (QRgb*)(rImage.scanLine( yi )); for( int xi=0; xi < wm; ++xi ) { r = *s++; u = qAlpha(r); alpha[i++] = u; } } gotAlpha = true; } } else { uchar * s; QImage iMask = rImage.createAlphaMask(); iMask = iMask.convertToFormat(QImage::Format_Mono); hm = iMask.height(); wm = iMask.width(); w2 = wm / 8; if ((wm % 8) != 0) w2++; alpha.resize(hm * w2); if (alpha.size() > 0) { for( int yi=0; yi < hm; ++yi ) { s = iMask.scanLine( yi ); for( int xi=0; xi < w2; ++xi ) { u = *(s+xi); if(PDF) u = ~u; alpha[i++] = u; } } gotAlpha = true; } } } return gotAlpha; } void ScImage::getEmbeddedProfile(const QString & fn, QByteArray *profile, int *components, int page) { Q_ASSERT(profile); Q_ASSERT(components); ScImgDataLoader* pDataLoader = NULL; ScColorProfile prof; profile->resize(0); *components = 0; QFileInfo fi = QFileInfo(fn); if (!fi.exists()) return; QString ext = fi.suffix().toLower(); if (extensionIndicatesPSD(ext)) pDataLoader = new ScImgDataLoader_PSD(); else if (extensionIndicatesEPSorPS(ext)) pDataLoader = new ScImgDataLoader_PS(); else if (extensionIndicatesTIFF(ext)) pDataLoader = new ScImgDataLoader_TIFF(); else if (extensionIndicatesJPEG(ext)) pDataLoader = new ScImgDataLoader_JPEG(); if (pDataLoader) { pDataLoader->loadEmbeddedProfile(fn, page); QByteArray embeddedProfile = pDataLoader->embeddedProfile(); if (embeddedProfile.size()) { prof = ScColorMgmtEngine::openProfileFromMem(embeddedProfile); if (prof) { if (prof.colorSpace() == ColorSpace_Rgb) *components = 3; if (prof.colorSpace() == ColorSpace_Cmyk) *components = 4; if (prof.colorSpace() == ColorSpace_Gray) *components = 1; *profile = embeddedProfile; } } delete pDataLoader; } } bool ScImage::LoadPicture(const QString & fn, int page, const CMSettings& cmSettings, bool useEmbedded, bool useProf, RequestType requestType, int gsRes, bool *realCMYK, bool showMsg) { // requestType - 0: CMYK, 1: RGB, 2: RGB Proof 3 : RawData, 4: Thumbnail // gsRes - is the resolution that ghostscript will render at bool isCMYK = false; bool ret = false; bool inputProfisEmbedded = false; bool stdProof = false; if (realCMYK != 0) *realCMYK = false; bool bilevel = false; // short resolutionunit = 0; RequestType reqType = requestType; ScColorTransform xform = 0; ScColorProfile inputProf = 0; int cmsFlags = 0; int cmsProofFlags = 0; auto_ptr pDataLoader; QFileInfo fi = QFileInfo(fn); if (!fi.exists()) return ret; QString ext = fi.suffix().toLower(); QString tmp, dummy, cmd1, cmd2, BBox, tmp2; QChar tc; QString profileName = ""; bool hasEmbeddedProfile = false; // bool found = false; if (ext.isEmpty()) ext = getImageType(fn); if (extensionIndicatesPDF(ext)) { pDataLoader.reset( new ScImgDataLoader_PDF() ); } else if (extensionIndicatesEPSorPS(ext)) { pDataLoader.reset( new ScImgDataLoader_PS() ); } else if (extensionIndicatesTIFF(ext)) { pDataLoader.reset( new ScImgDataLoader_TIFF() ); } else if (extensionIndicatesPSD(ext)) { pDataLoader.reset( new ScImgDataLoader_PSD() ); pDataLoader->setRequest(imgInfo.isRequest, imgInfo.RequestProps); } else if (extensionIndicatesJPEG(ext)) pDataLoader.reset( new ScImgDataLoader_JPEG() ); else if (ext == "pat") pDataLoader.reset( new ScImgDataLoader_GIMP() ); else pDataLoader.reset( new ScImgDataLoader_QT() ); if (pDataLoader->loadPicture(fn, page, gsRes, (requestType == Thumbnail))) { QImage::operator=(pDataLoader->image()); imgInfo = pDataLoader->imageInfoRecord(); if (requestType == Thumbnail) reqType = RGBData; // if (!cmSettings.useColorManagement() || !useProf) // { // imgInfo.isEmbedded = false; // imgInfo.profileName = ""; // } if (imgInfo.colorspace == ColorSpaceCMYK) { isCMYK = true; if(realCMYK) *realCMYK = true; } else if (imgInfo.colorspace == ColorSpaceGray) bilevel = true; pDataLoader->image() = QImage(); } else { if (ScCore->usingGUI() && pDataLoader->issuedErrorMsg() && showMsg) { QMessageBox::critical(ScCore->primaryMainWindow(), CommonStrings::trWarning, pDataLoader->getMessage(), 1, 0, 0); } else if (pDataLoader->issuedErrorMsg()) { QString msg = pDataLoader->getMessage(); qWarning("%s", msg.toLocal8Bit().data() ); } return false; } if (!(extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext))) { if (isNull()) return ret; } QByteArray embeddedProfile = pDataLoader->embeddedProfile(); if (cmSettings.useColorManagement() && useProf) { if ((embeddedProfile.size() > 0 ) && (useEmbedded)) { inputProf = ScColorMgmtEngine::openProfileFromMem(embeddedProfile); inputProfisEmbedded = true; } else { QString profilePath; //CB If this is null, customfiledialog/picsearch/ScPreview might be sending it Q_ASSERT(cmSettings.doc()!=0); if (isCMYK) { if (ScCore->InputProfilesCMYK.contains(cmSettings.profileName()) && (cmSettings.profileName() != cmSettings.doc()->CMSSettings.DefaultImageCMYKProfile)) { imgInfo.profileName = cmSettings.profileName(); inputProfisEmbedded = true; profilePath = ScCore->InputProfilesCMYK[imgInfo.profileName]; inputProf = ScColorMgmtEngine::openProfileFromFile(profilePath); } else { inputProf = cmSettings.doc()->DocInputImageCMYKProf; imgInfo.profileName = cmSettings.doc()->CMSSettings.DefaultImageCMYKProfile; inputProfisEmbedded = false; } } else if (bilevel && (reqType == CMYKData)) inputProf = NULL; // Workaround to map directly gray to K channel else if (ScCore->InputProfiles.contains(cmSettings.profileName()) && (cmSettings.profileName() != cmSettings.doc()->CMSSettings.DefaultImageRGBProfile)) { imgInfo.profileName = cmSettings.profileName(); profilePath = ScCore->InputProfiles[imgInfo.profileName].toLocal8Bit(); inputProfisEmbedded = true; inputProf = ScColorMgmtEngine::openProfileFromFile(profilePath); } else { inputProf = cmSettings.doc()->DocInputImageRGBProf; imgInfo.profileName = cmSettings.doc()->CMSSettings.DefaultImageRGBProfile; inputProfisEmbedded = false; } } } else if ((useProf && embeddedProfile.size() > 0) && (useEmbedded)) { inputProf = ScColorMgmtEngine::openProfileFromMem(embeddedProfile); inputProfisEmbedded = true; } else if (useProf && isCMYK) inputProf = ScCore->defaultCMYKProfile; else if (useProf && bilevel && (reqType == CMYKData)) inputProf = NULL; // Workaround to map directly gray to K channel else if (useProf) inputProf = ScCore->defaultRGBProfile; ScColorProfile screenProf = cmSettings.monitorProfile() ? cmSettings.monitorProfile() : ScCore->defaultRGBProfile; ScColorProfile printerProf = cmSettings.printerProfile() ? cmSettings.printerProfile() : ScCore->defaultCMYKProfile; if (useProf && inputProf && screenProf && printerProf) { bool isPsdTiff = (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)); eColorFormat inputProfFormat = Format_BGRA_8; eColorFormat outputProfFormat = Format_YMCK_8; eColorSpaceType inputProfColorSpace = inputProf.colorSpace(); if ( inputProfColorSpace == ColorSpace_Rgb ) inputProfFormat = isPsdTiff ? Format_RGBA_8 : Format_BGRA_8; // Later make tiff and psd loader use Format_BGRA_8 else if (( inputProfColorSpace == ColorSpace_Cmyk ) && isPsdTiff) { if (pDataLoader->r_image.channels() == 5) inputProfFormat = Format_CMYKA_8; else inputProfFormat = Format_CMYK_8; } else if ( inputProfColorSpace == ColorSpace_Cmyk ) inputProfFormat = Format_YMCK_8; else if ( inputProfColorSpace == ColorSpace_Gray ) inputProfFormat = Format_GRAY_8; eColorSpaceType outputProfColorSpace = printerProf.colorSpace(); if ( outputProfColorSpace == ColorSpace_Rgb ) outputProfFormat = Format_BGRA_8; else if ( outputProfColorSpace == ColorSpace_Cmyk ) outputProfFormat = Format_YMCK_8; if (cmSettings.useColorManagement() && cmSettings.doSoftProofing()) { cmsProofFlags |= Ctf_Softproofing; if (cmSettings.doGamutCheck()) { cmsProofFlags |= Ctf_GamutCheck; } } if (!cmSettings.useColorManagement() || cmSettings.useBlackPoint()) cmsFlags |= Ctf_BlackPointCompensation; switch (reqType) { case CMYKData: // CMYK // if ((!isCMYK && (outputProfColorSpace == icSigCmykData)) || (isCMYK && (outputProfColorSpace == icSigRgbData)) ) xform = ScColorMgmtEngine::createTransform(inputProf, inputProfFormat, printerProf, outputProfFormat, cmSettings.imageRenderingIntent(), cmsFlags); if (outputProfColorSpace != ColorSpace_Cmyk ) *realCMYK = isCMYK = false; break; case Thumbnail: case RGBData: // RGB if (isCMYK) xform = ScColorMgmtEngine::createTransform(inputProf, inputProfFormat, screenProf, Format_BGRA_8, cmSettings.intent(), cmsFlags); else { if (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)) { QImage::operator=(pDataLoader->r_image.convertToQImage(false)); profileName = imgInfo.profileName; hasEmbeddedProfile = imgInfo.isEmbedded; imgInfo = pDataLoader->imageInfoRecord(); imgInfo.profileName = profileName; imgInfo.isEmbedded = hasEmbeddedProfile; // JG : this line overwrite image profile info and should not be needed here!!!! // imgInfo = pDataLoader->imageInfoRecord(); } } break; case RGBProof: // RGB Proof { if (cmSettings.useColorManagement() && cmSettings.doSoftProofing()) { if ((imgInfo.profileName == cmSettings.defaultImageRGBProfile()) || (imgInfo.profileName == cmSettings.defaultImageCMYKProfile())) { if (isCMYK) xform = cmSettings.cmykImageProofingTransform(); else xform = cmSettings.rgbImageProofingTransform(); xform.changeBufferFormat(inputProfFormat, Format_BGRA_8); stdProof = true; } else xform = ScColorMgmtEngine::createProofingTransform(inputProf, inputProfFormat, screenProf, Format_BGRA_8, printerProf, cmSettings.intent(), Intent_Relative_Colorimetric, cmsFlags | cmsProofFlags); } else xform = ScColorMgmtEngine::createTransform(inputProf, inputProfFormat, screenProf, Format_BGRA_8, cmSettings.intent(), cmsFlags); } break; case RawData: // no Conversion just raw Data xform = 0; if (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)) { QImage::operator=(pDataLoader->r_image.convertToQImage(true, true)); profileName = imgInfo.profileName; hasEmbeddedProfile = imgInfo.isEmbedded; imgInfo = pDataLoader->imageInfoRecord(); imgInfo.profileName = profileName; imgInfo.isEmbedded = hasEmbeddedProfile; // JG : this line overwrite image profile info and should not be needed here!!!! // imgInfo = pDataLoader->imageInfoRecord(); } break; } if (xform) { if (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)) { QImage::operator=(QImage(pDataLoader->r_image.width(), pDataLoader->r_image.height(), QImage::Format_ARGB32)); profileName = imgInfo.profileName; hasEmbeddedProfile = imgInfo.isEmbedded; imgInfo = pDataLoader->imageInfoRecord(); imgInfo.profileName = profileName; imgInfo.isEmbedded = hasEmbeddedProfile; // JG : this line overwrite image profile info and should not be needed here!!!! // imgInfo = pDataLoader->imageInfoRecord(); } uchar* ptr2 = NULL; for (int i = 0; i < height(); i++) { uchar* ptr = scanLine(i); if (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)) ptr2 = pDataLoader->r_image.scanLine(i); if ( inputProfFormat == Format_GRAY_8 && (reqType != CMYKData) ) { unsigned char* ucs = ptr2 ? (ptr2 + 1) : (ptr + 1); unsigned char* uc = new unsigned char[width()]; for( int uci = 0; uci < width(); ++uci ) { uc[uci] = *ucs; ucs += 4; } xform.apply(uc, ptr, width()); delete[] uc; } else if ( inputProfFormat == Format_GRAY_8 && (reqType == CMYKData) ) { unsigned char value; unsigned char* ucs = ptr2 ? ptr2 : ptr; unsigned char* uc = ptr; for( int uci = 0; uci < width(); ++uci, uc += 4 ) { value = 255 - *(ucs + 1); uc[0] = uc[1] = uc[2] = 0; uc[3] = value; ucs += 4; } } else { if (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)) { xform.apply(ptr2, ptr, width()); } else xform.apply(ptr, ptr, width()); } // if transforming from CMYK to RGB, flatten the alpha channel // which will still contain the black channel if (!(extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext))) { QRgb alphaFF = qRgba(0,0,0,255); QRgb *p; if (isCMYK && reqType != CMYKData && !bilevel) { p = (QRgb *) ptr; for (int j = 0; j < width(); j++, p++) *p |= alphaFF; } } else { // This might fix Bug #6328, please test. if (reqType != CMYKData && bilevel) { QRgb alphaFF; QRgb *p; p = (QRgb *) ptr; for (int j = 0; j < width(); j++, p++) { alphaFF = qRgba(0,0,0,ptr2[3]); *p |= alphaFF; ptr2 += 4; } } if (reqType != CMYKData && !bilevel) { if (pDataLoader->r_image.channels() == 5) { QRgb *p = (QRgb *) ptr; for (int j = 0; j < width(); j++, p++) { *p = qRgba(qRed(*p), qGreen(*p), qBlue(*p), ptr2[4]); ptr2 += 5; } } else { QRgb *p = (QRgb *) ptr; for (int j = 0; j < width(); j++, p++) { if (isCMYK) *p = qRgba(qRed(*p), qGreen(*p), qBlue(*p), 255); else *p = qRgba(qRed(*p), qGreen(*p), qBlue(*p), ptr2[3]); ptr2 += 4; } } } } } } if (isCMYK) cmSettings.cmykImageProofingTransform().changeBufferFormat(Format_CMYK_8, Format_RGBA_8); else cmSettings.rgbImageProofingTransform().changeBufferFormat(Format_RGBA_8, Format_RGBA_8); } else { switch (reqType) { case CMYKData: if (!isCMYK) { if (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)) { QImage::operator=(pDataLoader->r_image.convertToQImage(false)); profileName = imgInfo.profileName; hasEmbeddedProfile = imgInfo.isEmbedded; imgInfo = pDataLoader->imageInfoRecord(); imgInfo.profileName = profileName; imgInfo.isEmbedded = hasEmbeddedProfile; // JG : this line overwrite image profile info and should not be needed here!!!! // imgInfo = pDataLoader->imageInfoRecord(); } unsigned char cc, cm, cy ,ck; QRgb *ptr; for (int i = 0; i < height(); i++) { ptr = (QRgb *) scanLine(i); for (int j = 0; j < width(); j++) { cc = 255 - qRed(*ptr); cm = 255 - qGreen(*ptr); cy = 255 - qBlue(*ptr); ck = qMin(qMin(cc, cm), cy); *ptr++ = qRgba(cc-ck,cm-ck,cy-ck,ck); } } } else { if (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)) { QImage::operator=(pDataLoader->r_image.convertToQImage(true, true)); profileName = imgInfo.profileName; hasEmbeddedProfile = imgInfo.isEmbedded; imgInfo = pDataLoader->imageInfoRecord(); imgInfo.profileName = profileName; imgInfo.isEmbedded = hasEmbeddedProfile; // JG : this line overwrite image profile info and should not be needed here!!!! // imgInfo = pDataLoader->imageInfoRecord(); } } break; case RGBData: case RGBProof: case Thumbnail: if (isCMYK) { if (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)) { QImage::operator=(pDataLoader->r_image.convertToQImage(true)); profileName = imgInfo.profileName; hasEmbeddedProfile = imgInfo.isEmbedded; imgInfo = pDataLoader->imageInfoRecord(); imgInfo.profileName = profileName; imgInfo.isEmbedded = hasEmbeddedProfile; // JG : this line overwrite image profile info and should not be needed here!!!! // imgInfo = pDataLoader->imageInfoRecord(); } else { unsigned char cr, cg, cb, ck; QRgb *ptr; for (int i = 0; i < height(); i++) { ptr = (QRgb *) scanLine(i); for (int j = 0; j < width(); j++) { ck = qAlpha(*ptr); cr = 255 - qMin(255, qRed(*ptr) + ck); cg = 255 - qMin(255, qGreen(*ptr) + ck); cb = 255 - qMin(255, qBlue(*ptr) + ck); *ptr++ = qRgba(cr,cg,cb,255); } } } } else { if (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)) { QImage::operator=(pDataLoader->r_image.convertToQImage(false)); profileName = imgInfo.profileName; hasEmbeddedProfile = imgInfo.isEmbedded; imgInfo = pDataLoader->imageInfoRecord(); imgInfo.profileName = profileName; imgInfo.isEmbedded = hasEmbeddedProfile; // JG : this line overwrite image profile info and should not be needed here!!!! // imgInfo = pDataLoader->imageInfoRecord(); } } break; case RawData: if (extensionIndicatesPSD(ext) || extensionIndicatesTIFF(ext)) { QImage::operator=(pDataLoader->r_image.convertToQImage(true, true)); profileName = imgInfo.profileName; hasEmbeddedProfile = imgInfo.isEmbedded; imgInfo = pDataLoader->imageInfoRecord(); imgInfo.profileName = profileName; imgInfo.isEmbedded = hasEmbeddedProfile; // JG : this line overwrite image profile info and should not be needed here!!!! // imgInfo = pDataLoader->imageInfoRecord(); } break; } } // if (((reqType == CMYKData) || ((reqType == RawData) && isCMYK)) && !bilevel) // setAlphaBuffer(false); setDotsPerMeterX (qMax(2834, (int) (imgInfo.xres / 0.0254))); setDotsPerMeterY (qMax(2834, (int) (imgInfo.yres / 0.0254))); if (imgInfo.isEmbedded && useEmbedded) imgInfo.isEmbedded = true; else imgInfo.isEmbedded = false; if (ScCore->usingGUI() && pDataLoader->issuedWarningMsg() && showMsg) { QMessageBox::warning(ScCore->primaryMainWindow(), CommonStrings::trWarning, pDataLoader->getMessage(), 1, 0, 0); } else if (pDataLoader->issuedErrorMsg()) { QString msg = pDataLoader->getMessage(); qWarning("%s", msg.toLocal8Bit().data() ); } return true; }