Rev 5369 |
Rev 5593 |
Go to most recent revision |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
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 "scimage.h"
#include "scribus.h"
#include "scribuscore.h"
#include <qtextstream.h>
#include <cassert>
#ifdef HAVE_CMS
#include CMS_INC
extern cmsHPROFILE CMSoutputProf;
extern cmsHPROFILE CMSprinterProf;
extern cmsHTRANSFORM stdTransRGBMonG;
extern cmsHTRANSFORM stdTransCMYKMonG;
extern cmsHTRANSFORM stdProofG;
extern cmsHTRANSFORM stdTransImgG;
extern cmsHTRANSFORM stdProofImgG;
extern bool BlackPoint;
extern bool SoftProofing;
extern bool Gamut;
extern bool CMSuse;
extern int IntentColors;
extern int IntentImages;
#endif
#include "gsutil.h"
#include "exif.h"
#include "commonstrings.h"
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);
}
static QDataStream & operator>> ( QDataStream & s, ScImage::PSDHeader & header )
{
s >> header.signature;
s >> header.version;
for( int i = 0; i < 6; i++ )
{
s >> header.reserved[i];
}
s >> header.channel_count;
s >> header.height;
s >> header.width;
s >> header.depth;
s >> header.color_mode;
return s;
}
ScImage::ScImage(const QImage & image) : QImage(image)
{
initialize();
}
ScImage::ScImage() : QImage()
{
initialize();
}
ScImage::ScImage( int width, int height ) : QImage( width, height, 32 )
{
initialize();
}
void ScImage::initialize()
{
imgInfo.xres = 72;
imgInfo.yres = 72;
imgInfo.colorspace = 0;
imgInfo.valid = false;
imgInfo.isRequest = 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.exifInfo.cameraName = "";
imgInfo.exifInfo.cameraVendor = "";
imgInfo.exifInfo.thumbnail = QImage();
imgInfo.BBoxX = 0;
imgInfo.BBoxH = 0;
}
ScImage::~ScImage()
{
curveTable.resize(0);
}
void ScImage::applyEffect(QValueList<imageEffect> effectsList, QMap<QString,ScColor> colors, bool cmyk)
{
if (effectsList.count() != 0)
{
for (uint 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;
QTextStream fp(&tmpstr, IO_ReadOnly);
fp >> col;
fp >> shading;
colorize(colors[col], shading, cmyk);
}
if ((*effectsList.at(a)).effectCode == EF_BRIGHTNESS)
{
QString tmpstr = (*effectsList.at(a)).effectParameters;
int brightnessValue = 0;
QTextStream fp(&tmpstr, IO_ReadOnly);
fp >> brightnessValue;
brightness(brightnessValue, cmyk);
}
if ((*effectsList.at(a)).effectCode == EF_CONTRAST)
{
QString tmpstr = (*effectsList.at(a)).effectParameters;
int contrastValue = 0;
QTextStream fp(&tmpstr, IO_ReadOnly);
fp >> contrastValue;
contrast(contrastValue, cmyk);
}
if ((*effectsList.at(a)).effectCode == EF_SHARPEN)
{
QString tmpstr = (*effectsList.at(a)).effectParameters;
double radius, sigma;
QTextStream fp(&tmpstr, IO_ReadOnly);
fp >> radius;
fp >> sigma;
sharpen(radius, sigma);
}
if ((*effectsList.at(a)).effectCode == EF_BLUR)
{
QString tmpstr = (*effectsList.at(a)).effectParameters;
double radius, sigma;
QTextStream fp(&tmpstr, IO_ReadOnly);
fp >> radius;
fp >> sigma;
blur(radius, sigma);
}
if ((*effectsList.at(a)).effectCode == EF_SOLARIZE)
{
QString tmpstr = (*effectsList.at(a)).effectParameters;
double sigma;
QTextStream fp(&tmpstr, IO_ReadOnly);
fp >> sigma;
solarize(sigma, cmyk);
}
}
}
}
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)
{
curveTable.resize(256);
int fk = qRound(255 / factor);
for (int i = 0; i < 256; ++i)
{
curveTable[i] = QMIN(255, static_cast<int>(i / fk) * fk);
}
applyCurve(cmyk);
}
void ScImage::blurScanLine(double *kernel, int width, unsigned int *src, unsigned int *dest, int columns)
{
register double *p;
unsigned int *q;
register int x;
register long i;
double red, green, blue, alpha;
double scale = 0.0;
if(width > columns)
{
for(x=0; x < columns; ++x)
{
scale = 0.0;
red = blue = green = alpha = 0.0;
p = kernel;
q = src;
for(i=0; i < columns; ++i)
{
if((i >= (x-width/2)) && (i <= (x+width/2)))
{
red += (*p)*(qRed(*q)*257);
green += (*p)*(qGreen(*q)*257);
blue += (*p)*(qBlue(*q)*257);
alpha += (*p)*(qAlpha(*q)*257);
}
if(((i+width/2-x) >= 0) && ((i+width/2-x) < width))
scale+=kernel[i+width/2-x];
p++;
q++;
}
scale = 1.0/scale;
red = scale*(red+0.5);
green = scale*(green+0.5);
blue = scale*(blue+0.5);
alpha = scale*(alpha+0.5);
red = red < 0 ? 0 : red > 65535 ? 65535 : red;
green = green < 0 ? 0 : green > 65535 ? 65535 : green;
blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
dest[x] = qRgba((unsigned char)(red/257UL),
(unsigned char)(green/257UL),
(unsigned char)(blue/257UL),
(unsigned char)(alpha/257UL));
}
return;
}
for(x=0; x < width/2; ++x)
{
scale = 0.0;
red = blue = green = alpha = 0.0;
p = kernel+width/2-x;
q = src;
for(i=width/2-x; i < width; ++i)
{
red += (*p)*(qRed(*q)*257);
green += (*p)*(qGreen(*q)*257);
blue += (*p)*(qBlue(*q)*257);
alpha += (*p)*(qAlpha(*q)*257);
scale += (*p);
p++;
q++;
}
scale=1.0/scale;
red = scale*(red+0.5);
green = scale*(green+0.5);
blue = scale*(blue+0.5);
alpha = scale*(alpha+0.5);
red = red < 0 ? 0 : red > 65535 ? 65535 : red;
green = green < 0 ? 0 : green > 65535 ? 65535 : green;
blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
dest[x] = qRgba((unsigned char)(red/257UL),
(unsigned char)(green/257UL),
(unsigned char)(blue/257UL),
(unsigned char)(alpha/257UL));
}
for(; x < columns-width/2; ++x)
{
red = blue = green = alpha = 0.0;
p = kernel;
q = src+(x-width/2);
for (i=0; i < (long) width; ++i)
{
red += (*p)*(qRed(*q)*257);
green += (*p)*(qGreen(*q)*257);
blue += (*p)*(qBlue(*q)*257);
alpha += (*p)*(qAlpha(*q)*257);
p++;
q++;
}
red = scale*(red+0.5);
green = scale*(green+0.5);
blue = scale*(blue+0.5);
alpha = scale*(alpha+0.5);
red = red < 0 ? 0 : red > 65535 ? 65535 : red;
green = green < 0 ? 0 : green > 65535 ? 65535 : green;
blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
dest[x] = qRgba((unsigned char)(red/257UL),
(unsigned char)(green/257UL),
(unsigned char)(blue/257UL),
(unsigned char)(alpha/257UL));
}
for(; x < columns; ++x)
{
red = blue = green = alpha = 0.0;
scale=0;
p = kernel;
q = src+(x-width/2);
for(i=0; i < columns-x+width/2; ++i)
{
red += (*p)*(qRed(*q)*257);
green += (*p)*(qGreen(*q)*257);
blue += (*p)*(qBlue(*q)*257);
alpha += (*p)*(qAlpha(*q)*257);
scale += (*p);
p++;
q++;
}
scale=1.0/scale;
red = scale*(red+0.5);
green = scale*(green+0.5);
blue = scale*(blue+0.5);
alpha = scale*(alpha+0.5);
red = red < 0 ? 0 : red > 65535 ? 65535 : red;
green = green < 0 ? 0 : green > 65535 ? 65535 : green;
blue = blue < 0 ? 0 : blue > 65535 ? 65535 : blue;
alpha = alpha < 0 ? 0 : alpha > 65535 ? 65535 : alpha;
dest[x] = qRgba((unsigned char)(red/257UL),
(unsigned char)(green/257UL),
(unsigned char)(blue/257UL),
(unsigned char)(alpha/257UL));
}
}
int ScImage::getBlurKernel(int width, double sigma, double **kernel)
{
double alpha, normalize;
register long i;
int bias;
assert(sigma != 0.0);
if(width == 0)
width = 3;
*kernel=(double *)malloc(width*sizeof(double));
if(*kernel == (double *)NULL)
return(0);
memset(*kernel, 0, width*sizeof(double));
bias = 3*width/2;
for(i=(-bias); i <= bias; i++)
{
alpha=exp(-((double) i*i)/(2.0*3*3*sigma*sigma));
(*kernel)[(i+bias)/3]+=alpha/(2.50662827463100024161235523934010416269302368164062*sigma);
}
normalize=0;
for(i=0; i < width; i++)
normalize+=(*kernel)[i];
for(i=0; i < width; i++)
(*kernel)[i]/=normalize;
return(width);
}
void ScImage::blur(double radius, double sigma)
{
double *kernel;
QImage dest;
int widthk;
int x, y;
unsigned int *scanline, *temp;
unsigned int *p, *q;
if(sigma == 0.0)
return;
kernel=(double *) NULL;
if(radius > 0)
widthk=getBlurKernel((int) (2*ceil(radius)+1),sigma,&kernel);
else
{
double *last_kernel;
last_kernel=(double *) NULL;
widthk=getBlurKernel(3,sigma,&kernel);
while ((long) (255*kernel[0]) > 0)
{
if(last_kernel != (double *)NULL)
{
liberateMemory((void **) &last_kernel);
}
last_kernel=kernel;
kernel = (double *)NULL;
widthk = getBlurKernel(widthk+2, sigma, &kernel);
}
if(last_kernel != (double *) NULL)
{
liberateMemory((void **) &kernel);
widthk-=2;
kernel = last_kernel;
}
}
if(widthk < 3)
{
liberateMemory((void **) &kernel);
return;
}
dest.create(width(), height(), 32);
scanline = (unsigned int *)malloc(sizeof(unsigned int)*height());
temp = (unsigned int *)malloc(sizeof(unsigned int)*height());
for(y=0; y < height(); ++y)
{
p = (unsigned int *)scanLine(y);
q = (unsigned int *)dest.scanLine(y);
blurScanLine(kernel, widthk, p, q, width());
}
unsigned int **srcTable = (unsigned int **)jumpTable();
unsigned int **destTable = (unsigned int **)dest.jumpTable();
for(x=0; x < width(); ++x)
{
for(y=0; y < height(); ++y)
{
scanline[y] = srcTable[y][x];
}
blurScanLine(kernel, widthk, scanline, temp, height());
for(y=0; y < height(); ++y)
{
destTable[y][x] = temp[y];
}
}
liberateMemory((void **) &scanline);
liberateMemory((void **) &temp);
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;
}
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->reset();
dest->create(width(), height(), 32);
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];
unsigned int **jumpTablek = (unsigned int **)jumpTable();
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;
red += (*k)*(qRed(jumpTablek[my][mx])*257);
green += (*k)*(qGreen(jumpTablek[my][mx])*257);
blue += (*k)*(qBlue(jumpTablek[my][mx])*257);
alpha += (*k)*(qAlpha(jumpTablek[my][mx])*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);
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)
{
curveTable.resize(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(cmyk);
}
void ScImage::brightness(int brightnessValue, bool cmyk)
{
curveTable.resize(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(cmyk);
}
void ScImage::applyCurve(bool cmyk)
{
int h = height();
int w = width();
for( int yi=0; yi < h; ++yi )
{
QRgb * s = (QRgb*)(scanLine( yi ));
for( int xi=0; xi < w; ++xi )
{
QRgb r=*s;
int c, m, y, k;
if (cmyk)
{
unsigned char *p = (unsigned char *) s;
unsigned char rc = 255 - QMIN(255, p[0] + p[3]);
unsigned char gc = 255 - QMIN(255, p[1] + p[3]);
unsigned char bc = 255 - QMIN(255, p[2] + p[3]);
c = 255 - curveTable[(int)rc];
m = 255 - curveTable[(int)gc];
y = 255 - curveTable[(int)bc];
k = QMIN(QMIN(c, m), y);
*s = qRgba(y - k, m - k, c - k, k );
}
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(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;
if (cmyk)
color.getShadeColorCMYK(&cc, &cm, &cy, &ck, shade);
else
{
ck = 0;
color.getShadeColorRGB(&cc, &cm, &cy, shade);
}
for( int yi=0; yi < h; ++yi )
{
QRgb * s = (QRgb*)(scanLine( yi ));
for( int xi=0; xi < w; ++xi )
{
QRgb r=*s;
if (cmyk)
{
double 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
{
int k = 255 - QMIN(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255);
int cc2, cm2, cy2;
tmpR.setRgb(cc, cm, cy);
tmpR.hsv(&hu, &sa, &v);
if (cc == cm && cm == cy)
tmpR.setHsv(hu, sa, 255 - ((255 - v) * k / 255));
else
tmpR.setHsv(hu, sa * k / 255, v);
tmpR.getRgb(&cc2, &cm2, &cy2);
int a = qAlpha(r);
*s = qRgba(cc2, cm2, cy2, a);
}
s++;
}
}
}
void ScImage::invert(bool cmyk)
{
int h = height();
int w = width();
for( int yi=0; yi < h; ++yi )
{
QRgb * s = (QRgb*)(scanLine( yi ));
for( int xi=0; xi < w; ++xi )
{
if (cmyk)
{
unsigned char *p = (unsigned char *) s;
unsigned char c, m, y, k;
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();
for( int yi=0; yi < h; ++yi )
{
QRgb * s = (QRgb*)(scanLine( yi ));
for( int xi=0; xi < w; ++xi )
{
QRgb r=*s;
int k;
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);
int a = qAlpha(r);
*s = qRgba(k, k, k, a);
}
s++;
}
}
}
void ScImage::swapRGBA()
{
for (int i = 0; i < height(); ++i)
{
unsigned int *ptr = (unsigned int *) scanLine(i);
unsigned char r, b;
for (int j = 0; j < width(); ++j)
{
unsigned char *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 = smoothScale(w, h);
create(w, h, 32);
for( int yi=0; yi < tmp.height(); ++yi )
{
QRgb *s = (QRgb*)(tmp.scanLine( yi ));
QRgb *d = (QRgb*)(scanLine( yi ));
for(int xi=0; xi < tmp.width(); ++xi )
{
(*d) = (*s);
s++;
d++;
}
}
}
void 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;
}
jpeg_create_compress (&cinfo);
if ((outfile = fopen (fn.local8Bit(), "wb")) == NULL)
return;
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<w; ++i)
{
*row++ = 255-qRed(*rgba);
*row++ = 255-qGreen(*rgba);
*row++ = 255-qBlue(*rgba);
*row++ = 255-qAlpha(*rgba);
++rgba;
}
}
else
{
if (isGray)
{
QRgb* rgba = (QRgb*)scanLine(cinfo.next_scanline);
for (int i=0; i<w; ++i)
{
*row++ = qRed(*rgba);
++rgba;
}
}
else
{
QRgb* rgb = (QRgb*)scanLine(cinfo.next_scanline);
for (int i=0; i<w; i++)
{
*row++ = qRed(*rgb);
*row++ = qGreen(*rgb);
*row++ = qBlue(*rgb);
++rgb;
}
}
}
jpeg_write_scanlines (&cinfo, row_pointer, 1);
}
jpeg_finish_compress (&cinfo);
fclose (outfile);
jpeg_destroy_compress (&cinfo);
delete [] row_pointer[0];
}
QByteArray ScImage::ImageToArray()
{
int i = 0;
int h = height();
int w = width();
unsigned char u;
QByteArray imgArray(3 * h * w);
for( int yi=0; yi < h; ++yi )
{
QRgb * s = (QRgb*)(scanLine( yi ));
for( int xi=0; xi < w; ++xi )
{
QRgb r=*s++;
u=qRed(r);
imgArray[i++] = u;
u=qGreen(r);
imgArray[i++] = u;
u=qBlue(r);
imgArray[i++] = u;
}
}
return imgArray;
}
QByteArray ScImage::ImageToGray()
{
int i = 0;
int h = height();
int w = width();
QByteArray imgArray(h * w);
for( int yi=0; yi < h; ++yi )
{
QRgb * s = (QRgb*)(scanLine( yi ));
for( int xi=0; xi < w; ++xi )
{
QRgb r=*s;
int k = QMIN(qRound(0.3 * qRed(r) + 0.59 * qGreen(r) + 0.11 * qBlue(r)), 255);
*s = qRgba(k, 0, 0, 0);
imgArray[i++] = k;
s++;
}
}
return imgArray;
}
QByteArray ScImage::ImageToCMYK_PDF(bool pre)
{
int i = 0;
int h = height();
int w = width();
QByteArray imgArray( 4 * h * w );
if (pre)
{
for( int yi=0; yi < h; ++yi )
{
QRgb * s = (QRgb*)(scanLine( yi ));
for( int xi=0; xi < w; ++xi )
{
QRgb r=*s;
int c = qRed(r);
int m = qGreen(r);
int y = qBlue(r);
int k = qAlpha(r);
imgArray[i++] = static_cast<unsigned char> (c);
imgArray[i++] = static_cast<unsigned char> (m);
imgArray[i++] = static_cast<unsigned char> (y);
imgArray[i++] = static_cast<unsigned char> (k);
s++;
}
}
}
else
{
for( int yi=0; yi < h; ++yi )
{
QRgb * s = (QRgb*)(scanLine( yi ));
for( int xi=0; xi < w; ++xi )
{
QRgb r=*s;
int c = 255 - qRed(r);
int m = 255 - qGreen(r);
int y = 255 - qBlue(r);
int k = QMIN(QMIN(c, m), y);
imgArray[i++] = static_cast<unsigned char> (c - k);
imgArray[i++] = static_cast<unsigned char> (m - k);
imgArray[i++] = static_cast<unsigned char> (y - k);
imgArray[i++] = static_cast<unsigned char> (k);
s++;
}
}
}
return imgArray;
}
QByteArray ScImage::ImageToCMYK_PS(int pl, bool pre)
{
int i = 0;
int h = height();
int w = width();
QByteArray imgArray;
if(pl == -1)
imgArray.resize(4 * h * w);
else
imgArray.resize(h * w);
if (pre)
{
for( int yi=0; yi < h; ++yi )
{
QRgb * s = (QRgb*)(scanLine( yi ));
for( int xi=0; xi < w; ++xi )
{
QRgb r=*s++;
int c = qRed(r);
int m = qGreen(r);
int y = qBlue(r);
int k = qAlpha(r);
if (pl == -1)
{
imgArray[i++] = static_cast<unsigned char> (c);
imgArray[i++] = static_cast<unsigned char> (m);
imgArray[i++] = static_cast<unsigned char> (y);
imgArray[i++] = static_cast<unsigned char> (k);
}
else
{
if (pl == -2)
imgArray[i++] = static_cast<unsigned char> (QMIN(255, qRound(0.3 * c + 0.59 * m + 0.11 * y + k)));
if (pl == 1)
imgArray[i++] = static_cast<unsigned char> (c);
if (pl == 2)
imgArray[i++] = static_cast<unsigned char> (m);
if (pl == 3)
imgArray[i++] = static_cast<unsigned char> (y);
if (pl == 0)
imgArray[i++] = static_cast<unsigned char> (k);
}
}
}
}
else
{
for( int yi=0; yi < h; ++yi )
{
QRgb * s = (QRgb*)(scanLine( yi ));
for( int xi=0; xi < w; ++xi )
{
QRgb r=*s++;
int c = 255 - qRed(r);
int m = 255 - qGreen(r);
int y = 255 - qBlue(r);
int k = QMIN(QMIN(c, m), y);
if (pl == -1)
{
imgArray[i++] = static_cast<unsigned char> (c - k);
imgArray[i++] = static_cast<unsigned char> (m - k);
imgArray[i++] = static_cast<unsigned char> (y - k);
imgArray[i++] = static_cast<unsigned char> (k);
}
else
{
if (pl == -2)
imgArray[i++] = static_cast<unsigned char> (QMIN(255, qRound(0.3 * c + 0.59 * m + 0.11 * y + k)));
if (pl == 1)
imgArray[i++] = static_cast<unsigned char> (c - k);
if (pl == 2)
imgArray[i++] = static_cast<unsigned char> (m - k);
if (pl == 3)
imgArray[i++] = static_cast<unsigned char> (y - k);
if (pl == 0)
imgArray[i++] = static_cast<unsigned char> (k);
}
}
}
}
return imgArray;
}
// Check that the header is a valid PSD.
bool ScImage::IsValid( const PSDHeader & header )
{
if( header.signature != 0x38425053 )
return false;
return true;
}
// Check that the header is supported.
bool ScImage::IsSupported( const PSDHeader & header )
{
if ( header.version != 1 )
return false;
if ( header.channel_count > 16 )
return false;
if ( header.depth != 8 )
return false;
if ((header.color_mode == CM_RGB) || (header.color_mode == CM_CMYK)
|| (header.color_mode == CM_GRAYSCALE) || (header.color_mode == CM_INDEXED))
return true;
return false;
}
unsigned char ScImage::INT_MULT ( unsigned char a, unsigned char b )
{
int c = a * b + 0x80;
return (unsigned char)(( ( c >> 8 ) + c ) >> 8);
}
/*!
* Convert a color in RGB space to HSV space (Hue, Saturation, Value).
* \param red the red component (modified in place).
* \param green the green component (modified in place).
* \param blue the blue component (modified in place).
*/
void ScImage::RGBTOHSV ( uchar& red, uchar& green, uchar& blue )
{
int r, g, b;
double h, s, v;
int min, max;
h = 0.;
r = red;
g = green;
b = blue;
if ( r > g )
{
max = QMAX( r, b );
min = QMIN( g, b );
}
else
{
max = QMAX( g, b );
min = QMIN( r, b );
}
v = max;
if ( max != 0 )
s = ( ( max - min ) * 255 ) / (double)max;
else
s = 0;
if ( s == 0 )
h = 0;
else
{
int delta = max - min;
if ( r == max )
h = ( g - b ) / (double)delta;
else if ( g == max )
h = 2 + ( b - r ) / (double)delta;
else if ( b == max )
h = 4 + ( r - g ) / (double)delta;
h *= 42.5;
if ( h < 0 )
h += 255;
if ( h > 255 )
h -= 255;
}
red = (uchar)h;
green = (uchar)s;
blue = (uchar)v;
}
/*!
* Convert a color in HSV space to RGB space.
* \param hue the hue component (modified in place).
* \param saturation the saturation component (modified in place).
* \param value the value component (modified in place).
*/
void ScImage::HSVTORGB ( uchar& hue, uchar& saturation, uchar& value )
{
if ( saturation == 0 )
{
hue = value;
saturation = value;
value = value;
}
else
{
double h = hue * 6. / 255.;
double s = saturation / 255.;
double v = value / 255.;
double f = h - (int)h;
double p = v * ( 1. - s );
double q = v * ( 1. - ( s * f ) );
double t = v * ( 1. - ( s * ( 1. - f ) ) );
// Worth a note here that gcc 2.96 will generate different results
// depending on optimization mode on i386.
switch ((int)h)
{
case 0:
hue = (uchar)( v * 255 );
saturation = (uchar)( t * 255 );
value = (uchar)( p * 255 );
break;
case 1:
hue = (uchar)( q * 255 );
saturation = (uchar)( v * 255 );
value = (uchar)( p * 255 );
break;
case 2:
hue = (uchar)( p * 255 );
saturation = (uchar)( v * 255 );
value = (uchar)( t * 255 );
break;
case 3:
hue = (uchar)( p * 255 );
saturation = (uchar)( q * 255 );
value = (uchar)( v * 255 );
break;
case 4:
hue = (uchar)( t * 255 );
saturation = (uchar)( p * 255 );
value = (uchar)( v * 255 );
break;
case 5:
hue = (uchar)( v * 255 );
saturation = (uchar)( p * 255 );
value = (uchar)( q * 255 );
}
}
}
/*!
* Convert a color in RGB space to HLS space (Hue, Lightness, Saturation).
* \param red the red component (modified in place).
* \param green the green component (modified in place).
* \param blue the blue component (modified in place).
*/
void ScImage::RGBTOHLS ( uchar& red, uchar& green, uchar& blue )
{
int r = red;
int g = green;
int b = blue;
int min, max;
if ( r > g )
{
max = QMAX( r, b );
min = QMIN( g, b );
}
else
{
max = QMAX( g, b );
min = QMIN( r, b );
}
double h;
double l = ( max + min ) / 2.;
double s;
if ( max == min )
{
s = 0.;
h = 0.;
}
else
{
int delta = max - min;
if ( l < 128 )
s = 255 * (double)delta / (double)( max + min );
else
s = 255 * (double)delta / (double)( 511 - max - min );
if ( r == max )
h = ( g - b ) / (double)delta;
else if ( g == max )
h = 2 + ( b - r ) / (double)delta;
else
h = 4 + ( r - g ) / (double)delta;
h *= 42.5;
if ( h < 0 )
h += 255;
else if ( h > 255 )
h -= 255;
}
red = (uchar)h;
green = (uchar)l;
blue = (uchar)s;
}
/*!
* Implement the HLS "double hex-cone".
* \param n1 lightness fraction (?)
* \param n2 saturation fraction (?)
* \param hue hue "angle".
* \return HLS value.
*/
int ScImage::HLSVALUE ( double n1, double n2, double hue )
{
double value;
if ( hue > 255 )
hue -= 255;
else if ( hue < 0 )
hue += 255;
if ( hue < 42.5 )
value = n1 + ( n2 - n1 ) * ( hue / 42.5 );
else if ( hue < 127.5 )
value = n2;
else if ( hue < 170 )
value = n1 + ( n2 - n1 ) * ( ( 170 - hue ) / 42.5 );
else
value = n1;
return (int)( value * 255 );
}
/*!
* Convert a color in HLS space to RGB space.
* \param hue the hue component (modified in place).
* \param lightness the lightness component (modified in place).
* \param saturation the saturation component (modified in place).
*/
void ScImage::HLSTORGB ( uchar& hue, uchar& lightness, uchar& saturation )
{
double h = hue;
double l = lightness;
double s = saturation;
if ( s == 0 )
{
hue = (uchar)l;
lightness = (uchar)l;
saturation = (uchar)l;
}
else
{
double m1, m2;
if ( l < 128 )
m2 = ( l * ( 255 + s ) ) / 65025.;
else
m2 = ( l + s - ( l * s ) / 255. ) / 255.;
m1 = ( l / 127.5 ) - m2;
hue = HLSVALUE( m1, m2, h + 85 );
lightness = HLSVALUE( m1, m2, h );
saturation = HLSVALUE( m1, m2, h - 85 );
}
}
bool ScImage::loadChannel( QDataStream & s, const PSDHeader & header, QValueList<PSDLayer> &layerInfo, uint layer, int channel, int component, QImage &tmpImg)
{
uint base = s.device()->at();
uchar cbyte;
ushort compression;
s >> compression;
if( compression > 1 )
return false;
if (compression == 0)
{
int count = layerInfo[layer].channelLen[channel]-2;
for (int i = 0; i < tmpImg.height(); i++)
{
uchar *ptr = tmpImg.scanLine(i);
for (int j = 0; j < tmpImg.width(); j++)
{
s >> cbyte;
count--;
if (header.color_mode == CM_CMYK)
cbyte = 255 - cbyte;
if ((header.color_mode == CM_GRAYSCALE) && (component != 3))
{
ptr[0] = cbyte;
ptr[1] = cbyte;
ptr[2] = cbyte;
}
else if ((header.color_mode == CM_INDEXED) && (component != 3))
{
int ccol = colorTable[cbyte];
ptr[2] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[0] = qBlue(ccol);
}
else
{
if (channel < 4)
ptr[component] = cbyte;
}
if (count == 0)
break;
ptr += 4;
}
if (count == 0)
break;
}
}
else
{
s.device()->at( s.device()->at() + tmpImg.height() * 2 );
uint pixel_count = tmpImg.width();
for (int hh = 0; hh < tmpImg.height(); hh++)
{
uint count = 0;
uchar *ptr = tmpImg.scanLine(hh);
uchar *ptr2 = ptr+tmpImg.width() * 4;
ptr += component;
while( count < pixel_count )
{
uchar c;
if(s.atEnd())
return false;
s >> c;
uint len = c;
if( len < 128 )
{
// Copy next len+1 bytes literally.
len++;
count += len;
while( len != 0 )
{
s >> cbyte;
if (ptr < ptr2)
{
if (header.color_mode == CM_CMYK)
cbyte = 255 - cbyte;
if ((header.color_mode == CM_GRAYSCALE) && (component != 3))
{
ptr -= component;
ptr[0] = cbyte;
ptr[1] = cbyte;
ptr[2] = cbyte;
ptr += component;
}
else if ((header.color_mode == CM_INDEXED) && (component != 3))
{
ptr -= component;
int ccol = colorTable[cbyte];
ptr[2] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[0] = qBlue(ccol);
ptr += component;
}
else
{
*ptr = cbyte;
}
}
ptr += 4;
len--;
}
}
else if( len > 128 )
{
// Next -len+1 bytes in the dest are replicated from next source byte.
// (Interpret len as a negative 8-bit int.)
len ^= 0xFF;
len += 2;
count += len;
uchar val;
s >> val;
if (header.color_mode == CM_CMYK)
val = 255 - val;
while( len != 0 )
{
if (ptr < ptr2)
{
if ((header.color_mode == CM_GRAYSCALE) && (component != 3))
{
ptr -= component;
ptr[0] = val;
ptr[1] = val;
ptr[2] = val;
ptr += component;
}
else if ((header.color_mode == CM_INDEXED) && (component != 3))
{
ptr -= component;
int ccol = colorTable[val];
ptr[2] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[0] = qBlue(ccol);
ptr += component;
}
else
*ptr = val;
}
ptr += 4;
len--;
}
}
else if( len == 128 )
{
// No-op.
}
}
}
}
s.device()->at( base+layerInfo[layer].channelLen[channel] );
return true;
}
bool ScImage::loadLayerChannels( QDataStream & s, const PSDHeader & header, QValueList<PSDLayer> &layerInfo, uint layer, bool* firstLayer)
{
// Find out if the data is compressed.
// Known values:
// 0: no compression
// 1: RLE compressed
uint base = s.device()->at();
uint base2 = base;
uint channel_num = layerInfo[layer].channelLen.count();
QImage tmpImg = QImage();
QImage mask = QImage();
if( !tmpImg.create( layerInfo[layer].width, layerInfo[layer].height, 32 ))
{
for(uint channel = 0; channel < channel_num; channel++)
{
base2 += layerInfo[layer].channelLen[channel];
}
s.device()->at( base2 );
return false;
}
tmpImg.fill(qRgba(255, 255, 255, 0));
tmpImg.setAlphaBuffer( true );
channel_num = QMIN(channel_num, 39);
uint components[40];
for(uint channel = 0; channel < channel_num; channel++)
{
switch(layerInfo[layer].channelType[channel])
{
case 0:
components[channel] = 2;
break;
case 1:
components[channel] = 1;
break;
case 2:
components[channel] = 0;
break;
case 3:
components[channel] = 3;
break;
case -1:
case -2:
components[channel] = 3;
break;
}
}
if (channel_num < 4)
{
for (int i = 0; i < tmpImg.height(); i++)
{
QRgb * s = (QRgb*)(tmpImg.scanLine( i ));
for (int j = 0; j < tmpImg.width(); j++)
{
*s++ = qRgba(255, 255, 255, 255);
}
}
}
for(uint channel = 0; channel < channel_num; channel++)
{
if ((layerInfo[layer].channelType[channel] < 0) && (header.color_mode == CM_CMYK))
{
s.device()->at( base+layerInfo[layer].channelLen[channel] );
base = base+layerInfo[layer].channelLen[channel];
continue;
}
// if ((layerInfo[layer].channelType[channel] == -2) || (layerInfo[layer].channelType[channel] == -1))
if (layerInfo[layer].channelType[channel] == -2)
{
if (!mask.create( layerInfo[layer].maskWidth, layerInfo[layer].maskHeight, 32 ))
// {
// if (!mask.create(layerInfo[layer].width, layerInfo[layer].height, 32 ))
break;
// }
mask.fill(qRgba(255, 255, 255, 0));
mask.setAlphaBuffer( true );
if (!loadChannel(s, header, layerInfo, layer, channel, components[channel], mask))
break;
}
else
{
if (!loadChannel(s, header, layerInfo, layer, channel, components[channel], tmpImg))
break;
}
}
for(uint channel = 0; channel < channel_num; channel++)
{
base2 += layerInfo[layer].channelLen[channel];
}
s.device()->at( base2 );
QImage tmpImg2 = tmpImg.copy();
if (header.color_mode == CM_CMYK)
{
for (int i = 0; i < tmpImg.height(); i++)
{
unsigned int *ptr = (unsigned int *) tmpImg.scanLine(i);
unsigned int *ptr2 = (unsigned int *) tmpImg2.scanLine(i);
unsigned char r, g, b;
for (int j = 0; j < tmpImg.width(); j++)
{
unsigned char *p = (unsigned char *) ptr;
unsigned char *p2 = (unsigned char *) ptr2;
r = 255 - QMIN(255, p[0] + p[3]);
g = 255 - QMIN(255, p[1] + p[3]);
b = 255 - QMIN(255, p[2] + p[3]);
p2[0] = r;
p2[1] = g;
p2[2] = b;
p2[3] = 255;
ptr++;
ptr2++;
}
}
}
QImage imt;
double sx = tmpImg.width() / 40.0;
double sy = tmpImg.height() / 40.0;
imt = sy < sx ? tmpImg2.smoothScale(qRound(tmpImg.width() / sx), qRound(tmpImg.height() / sx)) :
tmpImg2.smoothScale(qRound(tmpImg.width() / sy), qRound(tmpImg.height() / sy));
layerInfo[layer].thumb = imt.copy();
bool visible = !(layerInfo[layer].flags & 2);
if ((imgInfo.isRequest) && (imgInfo.RequestProps.contains(layer)))
visible = imgInfo.RequestProps[layer].visible;
if (visible)
{
unsigned int startSrcY, startSrcX, startDstY, startDstX;
if (layerInfo[layer].ypos < 0)
{
startSrcY = abs(layerInfo[layer].ypos);
startDstY = 0;
}
else
{
startSrcY = 0;
startDstY = layerInfo[layer].ypos;
}
if (layerInfo[layer].xpos < 0)
{
startSrcX = abs(layerInfo[layer].xpos);
startDstX = 0;
}
else
{
startSrcX = 0;
startDstX = layerInfo[layer].xpos;
}
unsigned int startSrcYm, startSrcXm, startDstYm, startDstXm;
if (layerInfo[layer].maskYpos < 0)
{
startSrcYm = abs(layerInfo[layer].maskYpos);
startDstYm = 0;
}
else
{
startSrcYm = 0;
startDstYm = layerInfo[layer].maskYpos;
}
if (layerInfo[layer].maskXpos < 0)
{
startSrcXm = abs(layerInfo[layer].maskXpos);
startDstXm = 0;
}
else
{
startSrcXm = 0;
startDstXm = layerInfo[layer].maskXpos;
}
QString layBlend2 = layerInfo[layer].blend;
if ((imgInfo.isRequest) && (imgInfo.RequestProps.contains(layer)))
layBlend2 = imgInfo.RequestProps[layer].blend;
if ((layBlend2 == "diss") && (header.color_mode != CM_CMYK))
{
for (int l = 0; l < tmpImg.height(); l++)
{
srand(random_table[ l % 4096]);
for (int k = 0; k < tmpImg.width(); k++)
{
int rand_val = rand() & 0xff;
QRgb pixel = tmpImg.pixel(k, l);
if (rand_val > 128)
tmpImg.setPixel(k, l, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), 0));
}
}
}
if (*firstLayer)
{
for( int yi=static_cast<int>(startSrcY); yi < QMIN(tmpImg.height(), height()); ++yi )
{
QRgb *s = (QRgb*)(tmpImg.scanLine( yi ));
QRgb *d = (QRgb*)(scanLine( QMIN(static_cast<int>(startDstY), height()-1) ));
d += QMIN(static_cast<int>(startDstX), width()-1);
s += QMIN(static_cast<int>(startSrcX), tmpImg.width()-1);
/* unsigned int *srcm;
if (!mask.isNull())
{
srcm = (unsigned int *)mask.scanLine(QMIN(yi, mask.height()-1));
srcm += QMIN(static_cast<int>(startSrcXm), mask.width()-1);
} */
for(int xi=static_cast<int>(startSrcX); xi < QMIN(tmpImg.width(), width()); ++xi )
{
(*d) = (*s);
/* unsigned char *sm = (unsigned char *) srcm;
unsigned char *sc = (unsigned char *) d;
unsigned char *ss = (unsigned char *) s;
if (!mask.isNull())
{
if (header.color_mode == CM_CMYK)
{
sc[0] = (sc[0] * (255 - sm[3]) + ss[0] * sm[3]) / 255;
sc[1] = (sc[1] * (255 - sm[3]) + ss[1] * sm[3]) / 255;
sc[2] = (sc[2] * (255 - sm[3]) + ss[2] * sm[3]) / 255;
sc[3] = (sc[3] * (255 - sm[3]) + ss[3] * sm[3]) / 255;
}
else
sc[3] = sm[3];
}
srcm++; */
s++;
d++;
}
startDstY++;
}
}
else
{
for (int i = static_cast<int>(startSrcY); i < layerInfo[layer].height; i++)
{
unsigned int *dst = (unsigned int *)scanLine(QMIN(static_cast<int>(startDstY), height()-1));
unsigned int *src = (unsigned int *)tmpImg.scanLine(QMIN(i, tmpImg.height()-1));
dst += QMIN(static_cast<int>(startDstX), width()-1);
src += QMIN(static_cast<int>(startSrcX), tmpImg.width()-1);
unsigned int *srcm = 0;
if (!mask.isNull())
{
srcm = (unsigned int *)mask.scanLine(QMIN(i, mask.height()-1));
srcm += QMIN(static_cast<int>(startSrcXm), mask.width()-1);
}
startDstY++;
unsigned char r, g, b, a, src_r, src_g, src_b, src_a, mask_a;
//<<#3356
unsigned int maxDestX = width() - startDstX + startSrcX - 1;
for (unsigned int j = startSrcX; j < QMIN(maxDestX, static_cast<unsigned int>(layerInfo[layer].width)); j++)
//for (unsigned int j = startSrcX; j < static_cast<unsigned int>(layerInfo[layer].width); j++)
//>>#3356
{
unsigned char *d = (unsigned char *) dst;
unsigned char *s = (unsigned char *) src;
unsigned char *sm = (unsigned char *) srcm;
src_r = s[0];
src_g = s[1];
src_b = s[2];
src_a = s[3];
if (!mask.isNull())
mask_a = sm[3];
QString layBlend = layerInfo[layer].blend;
if ((imgInfo.isRequest) && (imgInfo.RequestProps.contains(layer)))
layBlend = imgInfo.RequestProps[layer].blend;
if (layBlend == "mul ")
{
if (header.color_mode == CM_CMYK)
{
src_r = INT_MULT(src_r, d[0]);
src_g = INT_MULT(src_g, d[1]);
src_b = INT_MULT(src_b, d[2]);
src_a = INT_MULT(src_a, d[3]);
}
else
{
if (d[3] > 0)
{
src_r = INT_MULT(src_r, d[0]);
src_g = INT_MULT(src_g, d[1]);
src_b = INT_MULT(src_b, d[2]);
}
}
}
else if (layBlend == "scrn")
{
if (header.color_mode == CM_CMYK)
{
src_r = 255 - INT_MULT(255 - d[0], 255 - src_r);
src_g = 255 - INT_MULT(255 - d[1], 255 - src_g);
src_b = 255 - INT_MULT(255 - d[2], 255 - src_b);
src_a = 255 - INT_MULT(255 - d[3], 255 - src_a);
}
else
{
if (d[3] > 0)
{
src_r = 255 - INT_MULT(255 - d[0], 255 - src_r);
src_g = 255 - INT_MULT(255 - d[1], 255 - src_g);
src_b = 255 - INT_MULT(255 - d[2], 255 - src_b);
}
}
}
else if (layBlend == "over")
{
if (header.color_mode == CM_CMYK)
{
src_r = INT_MULT(d[0], d[0] + INT_MULT(2 * src_r, 255 - d[0]));
src_g = INT_MULT(d[1], d[1] + INT_MULT(2 * src_g, 255 - d[1]));
src_b = INT_MULT(d[2], d[2] + INT_MULT(2 * src_b, 255 - d[2]));
src_a = INT_MULT(d[3], d[3] + INT_MULT(2 * src_a, 255 - d[3]));
}
else
{
if (d[3] > 0)
{
src_r = INT_MULT(d[0], d[0] + INT_MULT(2 * src_r, 255 - d[0]));
src_g = INT_MULT(d[1], d[1] + INT_MULT(2 * src_g, 255 - d[1]));
src_b = INT_MULT(d[2], d[2] + INT_MULT(2 * src_b, 255 - d[2]));
}
}
}
else if (layBlend == "diff")
{
if (header.color_mode == CM_CMYK)
{
src_r = d[0] > src_r ? d[0] - src_r : src_r - d[0];
src_g = d[1] > src_g ? d[1] - src_g : src_g - d[1];
src_b = d[2] > src_b ? d[2] - src_b : src_b - d[2];
src_a = d[3] > src_a ? d[3] - src_a : src_a - d[3];
}
else
{
if (d[3] > 0)
{
src_r = d[0] > src_r ? d[0] - src_r : src_r - d[0];
src_g = d[1] > src_g ? d[1] - src_g : src_g - d[1];
src_b = d[2] > src_b ? d[2] - src_b : src_b - d[2];
}
}
}
else if (layBlend == "dark")
{
if (header.color_mode == CM_CMYK)
{
src_r = d[0] < src_r ? d[0] : src_r;
src_g = d[1] < src_g ? d[1] : src_g;
src_b = d[2] < src_b ? d[2] : src_b;
src_a = d[3] < src_a ? d[3] : src_a;
}
else
{
if (d[3] > 0)
{
src_r = d[0] < src_r ? d[0] : src_r;
src_g = d[1] < src_g ? d[1] : src_g;
src_b = d[2] < src_b ? d[2] : src_b;
}
}
}
else if (layBlend == "hLit")
{
if (header.color_mode == CM_CMYK)
{
src_r = src_r < 128 ? src_r * d[0] / 128 : 255 - ((255-src_r) * (255-d[0]) / 128);
src_g = src_g < 128 ? src_g * d[1] / 128 : 255 - ((255-src_g) * (255-d[1]) / 128);
src_b = src_b < 128 ? src_b * d[2] / 128 : 255 - ((255-src_b) * (255-d[2]) / 128);
src_a = src_a < 128 ? src_a * d[3] / 128 : 255 - ((255-src_a) * (255-d[3]) / 128);
}
else
{
if (d[3] > 0)
{
src_r = src_r < 128 ? src_r * d[0] / 128 : 255 - ((255-src_r) * (255-d[0]) / 128);
src_g = src_g < 128 ? src_g * d[1] / 128 : 255 - ((255-src_g) * (255-d[1]) / 128);
src_b = src_b < 128 ? src_b * d[2] / 128 : 255 - ((255-src_b) * (255-d[2]) / 128);
}
}
}
else if (layBlend == "sLit")
{
if (header.color_mode == CM_CMYK)
{
src_r = src_r * d[0] / 256 + src_r * (255 - ((255-src_r)*(255-d[0]) / 256) - src_r * d[0] / 256) / 256;
src_g = src_g * d[1] / 256 + src_g * (255 - ((255-src_g)*(255-d[1]) / 256) - src_g * d[1] / 256) / 256;
src_b = src_b * d[2] / 256 + src_b * (255 - ((255-src_b)*(255-d[2]) / 256) - src_b * d[2] / 256) / 256;
src_a = src_a * d[3] / 256 + src_a * (255 - ((255-src_a)*(255-d[3]) / 256) - src_a * d[3] / 256) / 256;
}
else
{
if (d[3] > 0)
{
src_r = src_r * d[0] / 256 + src_r * (255 - ((255-src_r)*(255-d[0]) / 256) - src_r * d[0] / 256) / 256;
src_g = src_g * d[1] / 256 + src_g * (255 - ((255-src_g)*(255-d[1]) / 256) - src_g * d[1] / 256) / 256;
src_b = src_b * d[2] / 256 + src_b * (255 - ((255-src_b)*(255-d[2]) / 256) - src_b * d[2] / 256) / 256;
}
}
}
else if (layBlend == "lite")
{
if (header.color_mode == CM_CMYK)
{
src_r = d[0] < src_r ? src_r : d[0];
src_g = d[1] < src_g ? src_g : d[1];
src_b = d[2] < src_b ? src_b : d[2];
src_a = d[3] < src_a ? src_a : d[3];
}
else
{
if (d[3] > 0)
{
src_r = d[0] < src_r ? src_r : d[0];
src_g = d[1] < src_g ? src_g : d[1];
src_b = d[2] < src_b ? src_b : d[2];
}
}
}
else if (layBlend == "smud")
{
if (header.color_mode == CM_CMYK)
{
src_r = d[0] + src_r - src_r * d[0] / 128;
src_g = d[1] + src_g - src_g * d[1] / 128;
src_b = d[2] + src_b - src_b * d[2] / 128;
src_a = d[3] + src_a - src_a * d[3] / 128;
}
else
{
if (d[3] > 0)
{
src_r = d[0] + src_r - src_r * d[0] / 128;
src_g = d[1] + src_g - src_g * d[1] / 128;
src_b = d[2] + src_b - src_b * d[2] / 128;
}
}
}
else if (layBlend == "div ")
{
if (header.color_mode == CM_CMYK)
{
src_r = src_r == 255 ? 255 : ((d[0] * 256) / (255-src_r)) > 255 ? 255 : (d[0] * 256) / (255-src_r);
src_g = src_g == 255 ? 255 : ((d[1] * 256) / (255-src_g)) > 255 ? 255 : (d[1] * 256) / (255-src_g);
src_b = src_b == 255 ? 255 : ((d[2] * 256) / (255-src_b)) > 255 ? 255 : (d[2] * 256) / (255-src_b);
src_a = src_a == 255 ? 255 : ((d[3] * 256) / (255-src_a)) > 255 ? 255 : (d[3] * 256) / (255-src_a);
}
else
{
if (d[3] > 0)
{
src_r = src_r == 255 ? 255 : ((d[0] * 256) / (255-src_r)) > 255 ? 255 : (d[0] * 256) / (255-src_r);
src_g = src_g == 255 ? 255 : ((d[1] * 256) / (255-src_g)) > 255 ? 255 : (d[1] * 256) / (255-src_g);
src_b = src_b == 255 ? 255 : ((d[2] * 256) / (255-src_b)) > 255 ? 255 : (d[2] * 256) / (255-src_b);
}
}
}
else if (layBlend == "idiv")
{
if (header.color_mode == CM_CMYK)
{
src_r = src_r == 0 ? 0 : (255 - (((255-d[0]) * 256) / src_r)) < 0 ? 0 : 255 - (((255-d[0]) * 256) / src_r);
src_g = src_g == 0 ? 0 : (255 - (((255-d[1]) * 256) / src_g)) < 0 ? 0 : 255 - (((255-d[1]) * 256) / src_g);
src_b = src_b == 0 ? 0 : (255 - (((255-d[2]) * 256) / src_b)) < 0 ? 0 : 255 - (((255-d[2]) * 256) / src_b);
src_a = src_a == 0 ? 0 : (255 - (((255-d[3]) * 256) / src_a)) < 0 ? 0 : 255 - (((255-d[3]) * 256) / src_a);
}
else
{
if (d[3] > 0)
{
src_r = src_r == 0 ? 0 : (255 - (((255-d[0]) * 256) / src_r)) < 0 ? 0 : 255 - (((255-d[0]) * 256) / src_r);
src_g = src_g == 0 ? 0 : (255 - (((255-d[1]) * 256) / src_g)) < 0 ? 0 : 255 - (((255-d[1]) * 256) / src_g);
src_b = src_b == 0 ? 0 : (255 - (((255-d[2]) * 256) / src_b)) < 0 ? 0 : 255 - (((255-d[2]) * 256) / src_b);
}
}
}
else if (layBlend == "hue ")
{
if (header.color_mode != CM_CMYK)
{
if (d[3] > 0)
{
uchar new_r = d[0];
uchar new_g = d[1];
uchar new_b = d[2];
RGBTOHSV(src_r, src_g, src_b);
RGBTOHSV(new_r, new_g, new_b);
new_r = src_r;
HSVTORGB(new_r, new_g, new_b);
src_r = new_r;
src_g = new_g;
src_b = new_b;
}
}
}
else if (layBlend == "sat ")
{
if (header.color_mode != CM_CMYK)
{
if (d[3] > 0)
{
uchar new_r = d[0];
uchar new_g = d[1];
uchar new_b = d[2];
RGBTOHSV(src_r, src_g, src_b);
RGBTOHSV(new_r, new_g, new_b);
new_g = src_g;
HSVTORGB(new_r, new_g, new_b);
src_r = new_r;
src_g = new_g;
src_b = new_b;
}
}
}
else if (layBlend == "lum ")
{
if (header.color_mode != CM_CMYK)
{
if (d[3] > 0)
{
uchar new_r = d[0];
uchar new_g = d[1];
uchar new_b = d[2];
RGBTOHSV(src_r, src_g, src_b);
RGBTOHSV(new_r, new_g, new_b);
new_b = src_b;
HSVTORGB(new_r, new_g, new_b);
src_r = new_r;
src_g = new_g;
src_b = new_b;
}
}
}
else if (layBlend == "colr")
{
if (header.color_mode != CM_CMYK)
{
if (d[3] > 0)
{
uchar new_r = d[0];
uchar new_g = d[1];
uchar new_b = d[2];
RGBTOHLS(src_r, src_g, src_b);
RGBTOHLS(new_r, new_g, new_b);
new_r = src_r;
new_b = src_b;
HLSTORGB(new_r, new_g, new_b);
src_r = new_r;
src_g = new_g;
src_b = new_b;
}
}
}
int layOpa = layerInfo[layer].opacity;
if ((imgInfo.isRequest) && (imgInfo.RequestProps.contains(layer)))
layOpa = imgInfo.RequestProps[layer].opacity;
if (!mask.isNull())
layOpa = INT_MULT(mask_a, layOpa);
if (header.color_mode != CM_CMYK)
src_a = INT_MULT(src_a, layOpa);
if (d[3] > 0)
{
r = (d[0] * (255 - layOpa) + src_r * layOpa) / 255;
g = (d[1] * (255 - layOpa) + src_g * layOpa) / 255;
b = (d[2] * (255 - layOpa) + src_b * layOpa) / 255;
if (header.color_mode == CM_CMYK)
a = (d[3] * (255 - layOpa) + src_a * layOpa) / 255;
else
{
a = d[3] + INT_MULT(255 - d[3], src_a);
r = (d[0] * (255 - src_a) + src_r * src_a) / 255;
g = (d[1] * (255 - src_a) + src_g * src_a) / 255;
b = (d[2] * (255 - src_a) + src_b * src_a) / 255;
}
}
else
{
r = src_r;
g = src_g;
b = src_b;
a = src_a;
}
if (header.color_mode == CM_CMYK)
{
d[0] = r;
d[1] = g;
d[2] = b;
d[3] = a;
}
else
{
if (src_a > 0)
{
d[0] = r;
d[1] = g;
d[2] = b;
d[3] = a;
}
}
dst++;
src++;
if (!mask.isNull())
srcm++;
}
}
}
}
*firstLayer = false;
return true;
}
bool ScImage::loadLayer( QDataStream & s, const PSDHeader & header )
{
// Find out if the data is compressed.
// Known values:
// 0: no compression
// 1: RLE compressed
ushort compression;
uchar cbyte;
s >> compression;
if( compression > 1 )
{
// Unknown compression type.
return false;
}
uint channel_num = header.channel_count;
if (channel_num < 4)
{
for (int i = 0; i < height(); i++)
{
QRgb * s = (QRgb*)(scanLine( i ));
for (int j = 0; j < width(); j++)
{
*s++ = qRgba(0, 0, 0, 255);
}
}
}
// channel_num = 4;
const uint pixel_count = header.height * header.width;
static const uint components[4] = {2, 1, 0, 3};
if( compression )
{
// Skip row lengths.
ushort w;
for(uint i = 0; i < header.height * header.channel_count; i++)
{
s >> w;
}
// Read RLE data.
for(uint channel = 0; channel < channel_num; channel++)
{
uchar * ptr = bits() + components[channel];
uint count = 0;
while( count < pixel_count )
{
uchar c;
if(s.atEnd())
return false;
s >> c;
uint len = c;
if( len < 128 )
{
// Copy next len+1 bytes literally.
len++;
count += len;
if ( count > pixel_count )
return false;
while( len != 0 )
{
s >> cbyte;
if (header.color_mode == CM_CMYK)
cbyte = 255 - cbyte;
if ((header.color_mode == CM_GRAYSCALE) && (components[channel] != 3))
{
ptr -= components[channel];
ptr[0] = cbyte;
ptr[1] = cbyte;
ptr[2] = cbyte;
ptr += components[channel];
}
else if ((header.color_mode == CM_INDEXED) && (components[channel] != 3))
{
ptr -= components[channel];
int ccol = colorTable[cbyte];
ptr[2] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[0] = qBlue(ccol);
ptr += components[channel];
}
else
*ptr = cbyte;
ptr += 4;
len--;
}
}
else if( len > 128 )
{
// Next -len+1 bytes in the dest are replicated from next source byte.
// (Interpret len as a negative 8-bit int.)
len ^= 0xFF;
len += 2;
count += len;
if(s.atEnd() || count > pixel_count)
return false;
uchar val;
s >> val;
if (header.color_mode == CM_CMYK)
val = 255 - val;
while( len != 0 )
{
if ((header.color_mode == CM_GRAYSCALE) && (components[channel] != 3))
{
ptr -= components[channel];
ptr[0] = val;
ptr[1] = val;
ptr[2] = val;
ptr += components[channel];
}
else if ((header.color_mode == CM_INDEXED) && (components[channel] != 3))
{
ptr -= components[channel];
int ccol = colorTable[val];
ptr[2] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[0] = qBlue(ccol);
ptr += components[channel];
}
else
*ptr = val;
ptr += 4;
len--;
}
}
else if( len == 128 )
{
// No-op.
}
}
}
}
else
{
// We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...)
// where each channel consists of an 8-bit value for each pixel in the image.
// Read the data by channel.
for(uint channel = 0; channel < channel_num; channel++)
{
uchar * ptr = bits() + components[channel];
// Read the data.
uint count = pixel_count;
while( count != 0 )
{
s >> cbyte;
if (header.color_mode == CM_CMYK)
cbyte = 255 - cbyte;
if ((header.color_mode == CM_GRAYSCALE) && (components[channel] != 3))
{
ptr -= components[channel];
ptr[0] = cbyte;
ptr[1] = cbyte;
ptr[2] = cbyte;
ptr += components[channel];
}
else if ((header.color_mode == CM_INDEXED) && (components[channel] != 3))
{
ptr -= components[channel];
int ccol = colorTable[cbyte];
ptr[2] = qRed(ccol);
ptr[1] = qGreen(ccol);
ptr[0] = qBlue(ccol);
ptr += components[channel];
}
else
*ptr = cbyte;
ptr += 4;
count--;
}
}
}
return true;
}
QString ScImage::getLayerString(QDataStream & s)
{
uchar len, tmp;
uint adj;
QString ret = "";
s >> len;
if (len == 0)
{
s >> tmp;
s >> tmp;
s >> tmp;
return ret;
}
for( int i = 0; i < len; i++ )
{
s >> tmp;
ret += QChar(tmp);
}
adj = 0;
if (((ret.length()+1) % 4) != 0)
adj = 4 - ((ret.length()+1) % 4);
s.device()->at( s.device()->at() + adj );
return ret;
}
QString ScImage::getPascalString(QDataStream & s)
{
uchar len, tmp;
uint adj;
QString ret = "";
s >> len;
if (len == 0)
{
s >> tmp;
return ret;
}
for( int i = 0; i < len; i++ )
{
s >> tmp;
ret += QChar(tmp);
}
adj = (ret.length()+1) % 2;
s.device()->at( s.device()->at() + adj );
return ret;
}
void ScImage::parseRessourceData( QDataStream & s, const PSDHeader & header, uint size )
{
uint signature, resSize, offset, resBase, vRes, hRes, adj;
ushort resID, hResUnit, vResUnit, dummyW;
QString resName;
uchar filler;
offset = 0;
bool first = false;
bool pathOpen = false;
FPoint firstPoint, firstControl;
FPointArray clip2;
while ((offset + 6)< size)
{
s >> signature;
offset += 4;
if(((signature >> 24)&0xff) != '8' ||
((signature >> 16)&0xff) != 'B' ||
((signature >> 8)&0xff) != 'I' ||
((signature )&0xff) != 'M' )
break;
s >> resID;
offset += 2;
adj = s.device()->at();
resName = getPascalString(s);
offset += s.device()->at() - adj;
s >> resSize;
if(offset + resSize > size)
break;
resBase = s.device()->at();
if ( (resID >= 0x07d0) && (resID <= 0x0bb6) )
{
QString db1, db2;
short type;
uint data1, data2, data3, data4, data5, data6;
double frac1, frac2, frac3, frac4, frac5, frac6;
ushort man1, man2, man3, man4, man5, man6;
uint offset2;
offset2 = 0;
first = false;
pathOpen = false;
clip2.resize(0);
while (offset2 < resSize)
{
s >> type;
s >> data1;
frac1 = (data1 & 0x00FFFFFF) / 16777215.0;
man1 = (data1 & 0x0F000000) >> 24;
frac1 = (frac1 + man1) * header.height;
s >> data2;
frac2 = (data2 & 0x00FFFFFF) / 16777215.0;
man2 = (data2 & 0x0F000000) >> 24;
frac2 = (frac2 + man2) * header.width;
s >> data3;
frac3 = (data3 & 0x00FFFFFF) / 16777215.0;
man3 = (data3 & 0x0F000000) >> 24;
frac3 = (frac3 + man3) * header.height;
s >> data4;
frac4 = (data4 & 0x00FFFFFF) / 16777215.0;
man4 = (data4 & 0x0F000000) >> 24;
frac4 = (frac4 + man4) * header.width;
s >> data5;
frac5 = (data5 & 0x00FFFFFF) / 16777215.0;
man5 = (data5 & 0x0F000000) >> 24;
frac5 = (frac5 + man5) * header.height;
s >> data6;
frac6 = (data6 & 0x00FFFFFF) / 16777215.0;
man6 = (data6 & 0x0F000000) >> 24;
frac6 = (frac6 + man6) * header.width;
switch (type)
{
case 0:
case 3:
if (pathOpen)
{
clip2.addPoint(firstPoint);
clip2.addPoint(firstControl);
clip2.setMarker();
}
pathOpen = false;
first = true;
break;
case 1:
case 2:
case 4:
case 5:
if (first)
{
firstControl = FPoint(frac2, frac1);
firstPoint = FPoint(frac4, frac3);
clip2.addPoint(FPoint(frac4, frac3));
clip2.addPoint(FPoint(frac6, frac5));
}
else
{
clip2.addPoint(frac4, frac3);
clip2.addPoint(frac2, frac1);
clip2.addPoint(frac4, frac3);
clip2.addPoint(frac6, frac5);
}
pathOpen = true;
first = false;
break;
case 6:
first = true;
break;
default:
break;
}
offset2 += 26;
}
clip2.addPoint(firstPoint);
clip2.addPoint(firstControl);
imgInfo.PDSpathData.insert(resName, clip2.copy());
}
else
{
switch (resID)
{
case 0x0bb7:
adj = s.device()->at();
imgInfo.clipPath = getPascalString(s);
offset += s.device()->at() - adj;
break;
case 0x03ed:
s >> hRes;
s >> hResUnit;
s >> dummyW;
s >> vRes;
s >> vResUnit;
s >> dummyW;
imgInfo.xres = qRound(hRes / 65536.0);
imgInfo.yres = qRound(vRes / 65536.0);
break;
case 0x040f:
{
icclen = resSize;
char* buffer = (char*)malloc(resSize);
iccbuf = buffer;
s.readRawBytes(buffer, resSize);
}
break;
case 0x0409:
case 0x040C:
{
uint thdummy, thsize;
s >> thdummy;
s >> thdummy;
s >> thdummy;
s >> thdummy;
s >> thdummy;
s >> thsize;
s >> thdummy;
char* buffer = (char*)malloc(thsize);
s.readRawBytes(buffer, thsize);
QImage imth;
imth.loadFromData((const uchar*)buffer, thsize, "JPEG");
imth.convertDepth(32);
if (resID == 0x0409)
imgInfo.exifInfo.thumbnail = imth.swapRGB();
else
imgInfo.exifInfo.thumbnail = imth;
imgInfo.exifDataValid = true;
free(buffer);
}
default:
break;
}
}
s.device()->at( resBase + resSize );
offset += resSize;
if (resSize & 1)
{
s >> filler;
offset += 1;
}
}
if(offset<size)
s.device()->at( size );
}
bool ScImage::parseLayer( QDataStream & s, const PSDHeader & header )
{
uint addRes, layerinfo, channelLen, signature, extradata, layermasksize, layerRange, dummy;
int top, left, bottom, right;
short numLayers, numChannels;
short channelType;
uchar blendKey[4];
uchar opacity, clipping, flags, filler;
QString layerName, blend;
struct PSDLayer lay;
s >> layerinfo;
s >> numLayers;
if (numLayers < 0)
numLayers = -numLayers;
if (numLayers != 0)
{
for (int layer = 0; layer < numLayers; layer++)
{
s >> top;
lay.ypos = top;
s >> left;
lay.xpos = left;
s >> bottom;
lay.height = bottom - top;
s >> right;
lay.width = right - left;
s >> numChannels;
lay.channelType.clear();
lay.channelLen.clear();
for (int channels = 0; channels < numChannels; channels++)
{
s >> channelType;
s >> channelLen;
lay.channelType.append(channelType);
lay.channelLen.append(channelLen);
}
s >> signature;
blend = "";
for( int i = 0; i < 4; i++ )
{
s >> blendKey[i];
blend += QChar(blendKey[i]);
}
lay.blend = blend;
s >> opacity;
lay.opacity = opacity;
s >> clipping;
lay.clipping = clipping;
s >> flags;
lay.flags = flags;
s >> filler;
s >> extradata;
s >> layermasksize;
lay.maskYpos = 0;
lay.maskXpos = 0;
lay.maskHeight = 0;
lay.maskWidth = 0;
if (layermasksize != 0)
{
s >> lay.maskYpos;
s >> lay.maskXpos;
s >> dummy;
lay.maskHeight = dummy - lay.maskYpos;
s >> dummy;
lay.maskWidth = dummy - lay.maskXpos;
s >> dummy;
}
s >> layerRange;
s.device()->at( s.device()->at() + layerRange );
lay.layerName = getLayerString(s);
imgInfo.layerInfo.append(lay);
s >> signature;
if( signature == 0x3842494D )
{
while (signature == 0x3842494D )
{
s >> signature;
s >> addRes;
s.device()->at( s.device()->at() + addRes );
s >> signature;
}
s.device()->at( s.device()->at() - 4 );
}
else
{
s.device()->at( s.device()->at() - 2 );
s >> signature;
if( signature == 0x3842494D )
{
while (signature == 0x3842494D )
{
s >> signature;
s >> addRes;
s.device()->at( s.device()->at() + addRes );
s >> signature;
}
s.device()->at( s.device()->at() - 4 );
}
else
s.device()->at( s.device()->at() - 6 );
}
}
bool firstLayer = true;
for (int layer = 0; layer < numLayers; layer++)
{
loadLayerChannels( s, header, imgInfo.layerInfo, layer, &firstLayer );
}
}
else
{
s >> numLayers;
loadLayer( s, header);
}
return true;
}
// Load the PSD image.
bool ScImage::LoadPSD( QDataStream & s, const PSDHeader & header)
{
// Create dst image.
if( !create( header.width, header.height, 32 ))
return false;
setAlphaBuffer( true );
uint tmp;
uint cdataStart;
uint ressourceDataLen;
uint startRessource;
uint layerDataLen;
uint startLayers;
srand(314159265);
for (int i = 0; i < 4096; i++)
random_table[i] = rand();
for (int i = 0; i < 4096; i++)
{
int tmp;
int swap = i + rand() % (4096 - i);
tmp = random_table[i];
random_table[i] = random_table[swap];
random_table[swap] = tmp;
}
// Skip mode data. FIX: this is incorrect, it's the Colormap Data for indexed Images
s >> tmp;
cdataStart = s.device()->at();
if (tmp != 0)
{
QValueList<uchar> colorTableR;
QValueList<uchar> colorTableG;
QValueList<uchar> colorTableB;
colorTableR.clear();
colorTableG.clear();
colorTableB.clear();
colorTable.clear();
uchar r;
for (uint cc = 0; cc < 256; cc++)
{
s >> r;
colorTableR.append(r);
}
for (uint cc = 0; cc < 256; cc++)
{
s >> r;
colorTableG.append(r);
}
for (uint cc = 0; cc < 256; cc++)
{
s >> r;
colorTableB.append(r);
}
for (uint cc = 0; cc < 256; cc++)
{
colorTable.append(qRgb(colorTableR[cc], colorTableG[cc], colorTableB[cc]));
}
}
s.device()->at( cdataStart + tmp );
s >> ressourceDataLen;
startRessource = s.device()->at();
if (ressourceDataLen != 0)
parseRessourceData(s, header, ressourceDataLen);
if ((!imgInfo.exifInfo.thumbnail.isNull()) && (header.reserved[0] == 't'))
return true;
s.device()->at( startRessource + ressourceDataLen );
// Skip the reserved data. FIX: Also incorrect, this is the actual Layer Data for Images with Layers
s >> layerDataLen;
startLayers = s.device()->at();
if (layerDataLen != 0)
return parseLayer( s, header);
else
{
// Decoding simple psd file, no layers
s.device()->at( s.device()->at() + layerDataLen );
loadLayer( s, header);
}
return true;
}
void ScImage::scaleImage(int nwidth, int nheight)
{
QImage dst;
dst.create(nwidth, nheight,32);
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;
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;
create(nwidth, nheight,32);
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;
}
QByteArray ScImage::getAlpha(QString fn, bool PDF, bool pdf14, int gsRes)
{
QByteArray retArray;
float xres, yres;
short resolutionunit = 0;
imgInfo.valid = false;
imgInfo.clipPath = "";
imgInfo.PDSpathData.clear();
imgInfo.layerInfo.clear();
QFileInfo fi = QFileInfo(fn);
if (!fi.exists())
return retArray;
QString tmp, BBox, tmp2;
QString ext = fi.extension(false).lower();
QString tmpFile = QDir::convertSeparators(QDir::homeDirPath()+"/.scribus/sc.png");
QString picFile = QDir::convertSeparators(fn);
if ((ext == "jpg") || (ext == "jpeg"))
return retArray;
double x, y, b, h;
bool found = false;
int retg = -1;
QChar tc;
if (ext == "pdf")
{
QStringList args;
xres = gsRes;
yres = gsRes;
args.append("-r"+QString::number(gsRes));
args.append("-sOutputFile=\""+tmpFile + "\"");
args.append("-dFirstPage=1");
args.append("-dLastPage=1");
args.append("\""+picFile+"\"");
retg = callGS(args);
if (retg == 0)
{
load(tmpFile);
unlink(tmpFile);
setAlphaBuffer(true);
if (ScCore->havePNGAlpha() != 0)
{
for( int yi=0; yi < height(); ++yi )
{
QRgb *s = (QRgb*)(scanLine( yi ));
for(int xi=0; xi < width(); ++xi )
{
if((*s) == 0xffffffff)
(*s) &= 0x00ffffff;
s++;
}
}
}
}
}
else if ((ext == "eps") || (ext == "ps"))
{
QFile f(fn);
if (f.open(IO_ReadOnly))
{
QTextStream ts(&f);
while (!ts.atEnd())
{
tc = ' ';
tmp = "";
while ((tc != '\n') && (tc != '\r'))
{
ts >> tc;
if ((tc != '\n') && (tc != '\r'))
tmp += tc;
}
if (tmp.startsWith("%%BoundingBox:"))
{
found = true;
BBox = tmp.remove("%%BoundingBox:");
}
if (!found)
{
if (tmp.startsWith("%%BoundingBox"))
{
found = true;
BBox = tmp.remove("%%BoundingBox");
}
}
if (tmp.startsWith("%%EndComments"))
break;
}
}
f.close();
if (found)
{
QTextStream ts2(&BBox, IO_ReadOnly);
ts2 >> x >> y >> b >> h;
h = h * gsRes / 72.0;
QStringList args;
xres = gsRes;
yres = gsRes;
if (ext == "eps")
args.append("-dEPSCrop");
args.append("-r"+QString::number(gsRes));
args.append("-sOutputFile="+tmpFile);
args.append(picFile);
retg = callGS(args);
if (retg == 0)
{
QImage image;
image.load(tmpFile);
image.setAlphaBuffer(true);
if (ScCore->havePNGAlpha() != 0)
{
int wi = image.width();
int hi = image.height();
for( int yi=0; yi < hi; ++yi )
{
QRgb *s = (QRgb*)(image.scanLine( yi ));
QRgb alphaFF = qRgba(255,255,255,255);
QRgb alpha00 = qRgba(255,255,255, 0);
for(int xi=0; xi < wi; ++xi )
{
if((*s) == alphaFF)
(*s) &= alpha00;
s++;
}
}
}
*this = static_cast<ScImage>(image.copy());
setAlphaBuffer(true);
unlink(tmpFile);
}
}
}
else if ((ext == "tif") || (ext == "tiff"))
{
#ifdef HAVE_TIFF
TIFF* tif = TIFFOpen(fn.local8Bit(), "r");
if(tif)
{
unsigned width, height, size;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres);
TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres);
TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT , &resolutionunit);
size = width * height;
uint16 photometric, bitspersample, samplesperpixel, fillorder;
TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric);
TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample);
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
TIFFGetField(tif, TIFFTAG_FILLORDER, &fillorder);
uint32 *bits = 0;
if (photometric == PHOTOMETRIC_SEPARATED)
{
TIFFClose(tif);
return retArray;
}
else
{
create(width,height,32);
setAlphaBuffer(true);
bits = (uint32 *) _TIFFmalloc(size * sizeof(uint32));
if(bits)
{
if (TIFFReadRGBAImage(tif, width, height, bits, 0))
{
for(unsigned int y = 0; y < height; y++)
memcpy(scanLine(height - 1 - y), bits + y * width, width * 4);
}
_TIFFfree(bits);
}
TIFFClose(tif);
}
}
#else
qDebug("TIFF Support not available");
#endif // HAVE_TIFF
}
else if (ext == "psd")
{
QFile f(fn);
if (f.open(IO_ReadOnly))
{
xres = 72.0;
yres = 72.0;
QDataStream s( &f );
s.setByteOrder( QDataStream::BigEndian );
PSDHeader header;
s >> header;
// Check image file format.
if( s.atEnd() || !IsValid( header ) )
return retArray;
// Check if it's a supported format.
if( !IsSupported( header ) )
return retArray;
if (header.color_mode == CM_CMYK)
return retArray;
if( !LoadPSD(s, header) )
return retArray;
f.close();
}
else
return retArray;
}
else
{
if (load(fn))
{
*this = convertDepth(32);
if (hasAlphaBuffer())
setAlphaBuffer(true);
else
return retArray;
}
else
return retArray;
}
if (isNull())
return retArray;
int i = 0;
unsigned char u;
int hm = height();
int wm = width();
int w2;
if (pdf14)
{
retArray.resize(hm * wm);
for( int yi=0; yi < hm; ++yi )
{
QRgb * s = (QRgb*)(scanLine( yi ));
for( int xi=0; xi < wm; ++xi )
{
QRgb r=*s++;
u=qAlpha(r);
retArray[i++] = u;
}
}
}
else
{
QImage iMask = createAlphaMask();
hm = iMask.height();
wm = iMask.width();
w2 = wm / 8;
if ((wm % 8) != 0)
w2++;
retArray.resize(hm * w2);
for( int yi=0; yi < hm; ++yi )
{
uchar * s = iMask.scanLine( yi );
for( int xi=0; xi < w2; ++xi )
{
u = *(s+xi);
if(PDF) u = ~u;
retArray[i++] = u;
}
}
}
return retArray;
}
#define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */
#define PHOTOSHOP_MARKER (JPEG_APP0 + 13) /* JPEG marker code for PHOTOSHOP */
#define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */
#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */
#define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN)
bool ScImage::marker_is_icc (jpeg_saved_marker_ptr marker)
{
return
marker->marker == ICC_MARKER &&
marker->data_length >= ICC_OVERHEAD_LEN &&
/* verify the identifying string */
GETJOCTET(marker->data[0]) == 0x49 &&
GETJOCTET(marker->data[1]) == 0x43 &&
GETJOCTET(marker->data[2]) == 0x43 &&
GETJOCTET(marker->data[3]) == 0x5F &&
GETJOCTET(marker->data[4]) == 0x50 &&
GETJOCTET(marker->data[5]) == 0x52 &&
GETJOCTET(marker->data[6]) == 0x4F &&
GETJOCTET(marker->data[7]) == 0x46 &&
GETJOCTET(marker->data[8]) == 0x49 &&
GETJOCTET(marker->data[9]) == 0x4C &&
GETJOCTET(marker->data[10]) == 0x45 &&
GETJOCTET(marker->data[11]) == 0x0;
}
bool ScImage::marker_is_photoshop (jpeg_saved_marker_ptr marker)
{
return
marker->marker == PHOTOSHOP_MARKER &&
marker->data_length >= ICC_OVERHEAD_LEN &&
/* verify the identifying string */
GETJOCTET(marker->data[0]) == 0x50 &&
GETJOCTET(marker->data[1]) == 0x68 &&
GETJOCTET(marker->data[2]) == 0x6F &&
GETJOCTET(marker->data[3]) == 0x74 &&
GETJOCTET(marker->data[4]) == 0x6F &&
GETJOCTET(marker->data[5]) == 0x73 &&
GETJOCTET(marker->data[6]) == 0x68 &&
GETJOCTET(marker->data[7]) == 0x6F &&
GETJOCTET(marker->data[8]) == 0x70 &&
GETJOCTET(marker->data[9]) == 0x20 &&
GETJOCTET(marker->data[10]) == 0x33 &&
GETJOCTET(marker->data[11]) == 0x2E &&
GETJOCTET(marker->data[12]) == 0x30 &&
GETJOCTET(marker->data[13]) == 0x0;
}
/* Small modification of original read_icc_profile method from jpegicc of lcms project
* to enable read of Photoshop marker
*/
bool ScImage::read_jpeg_marker (UINT8 requestmarker, j_decompress_ptr cinfo, JOCTET **icc_data_ptr, unsigned int *icc_data_len)
{
jpeg_saved_marker_ptr marker;
int num_markers = 0;
int seq_no;
JOCTET *icc_data;
unsigned int total_length;
#define MAX_SEQ_NO 255 /* sufficient since marker numbers are bytes */
char marker_present[MAX_SEQ_NO+1]; /* 1 if marker found */
unsigned int data_length[MAX_SEQ_NO+1]; /* size of profile data in marker */
unsigned int data_offset[MAX_SEQ_NO+1]; /* offset for data in marker */
*icc_data_ptr = NULL; /* avoid confusion if false return */
*icc_data_len = 0;
/* This first pass over the saved markers discovers whether there are
* any ICC markers and verifies the consistency of the marker numbering.
*/
for (seq_no = 1; seq_no <= MAX_SEQ_NO; seq_no++)
marker_present[seq_no] = 0;
seq_no = 0;
for (marker = cinfo->marker_list; marker != NULL; marker = marker->next)
{
if (requestmarker == ICC_MARKER && marker_is_icc(marker))
{
if (num_markers == 0)
num_markers = GETJOCTET(marker->data[13]);
else if (num_markers != GETJOCTET(marker->data[13]))
return false; /* inconsistent num_markers fields */
seq_no = GETJOCTET(marker->data[12]);
if (seq_no <= 0 || seq_no > num_markers)
return false; /* bogus sequence number */
if (marker_present[seq_no])
return false; /* duplicate sequence numbers */
marker_present[seq_no] = 1;
data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
}
else if(requestmarker == PHOTOSHOP_MARKER && marker_is_photoshop(marker))
{
num_markers = ++seq_no;
marker_present[seq_no] = 1;
data_length[seq_no] = marker->data_length - ICC_OVERHEAD_LEN;
}
}
if (num_markers == 0)
return false;
/* Check for missing markers, count total space needed,
* compute offset of each marker's part of the data.
*/
total_length = 0;
for (seq_no = 1; seq_no <= num_markers; seq_no++)
{
if (marker_present[seq_no] == 0)
return false; /* missing sequence number */
data_offset[seq_no] = total_length;
total_length += data_length[seq_no];
}
if (total_length <= 0)
return false; /* found only empty markers? */
/* Allocate space for assembled data */
icc_data = (JOCTET *) malloc(total_length * sizeof(JOCTET));
if (icc_data == NULL)
return false; /* oops, out of memory */
seq_no=0;
/* and fill it in */
for (marker = cinfo->marker_list; marker != NULL; marker = marker->next)
{
if ( (requestmarker == ICC_MARKER && marker_is_icc(marker)) ||
(requestmarker == PHOTOSHOP_MARKER && marker_is_photoshop(marker)) || (requestmarker == 0xE1))
{
JOCTET FAR *src_ptr;
JOCTET *dst_ptr;
unsigned int length;
if(requestmarker == ICC_MARKER)
seq_no = GETJOCTET(marker->data[12]);
else if(requestmarker == PHOTOSHOP_MARKER)
seq_no++;
dst_ptr = icc_data + data_offset[seq_no];
src_ptr = marker->data + ICC_OVERHEAD_LEN;
length = data_length[seq_no];
while (length--)
{
*dst_ptr++ = *src_ptr++;
}
}
}
*icc_data_ptr = icc_data;
*icc_data_len = total_length;
return true;
}
void ScImage::getEmbeddedProfile(const QString & fn, QString *profile, int *components)
{
Q_ASSERT(profile);
Q_ASSERT(components);
#ifdef HAVE_CMS
cmsHPROFILE tiffProf = 0;
QFileInfo fi = QFileInfo(fn);
if (!fi.exists())
return;
QString ext = fi.extension(false).lower();
iccbuf = 0;
icclen = 0;
if (ext == "psd")
{
QFile f(fn);
if (f.open(IO_ReadOnly))
{
imgInfo.xres = 72;
imgInfo.yres = 72;
QDataStream s( &f );
s.setByteOrder( QDataStream::BigEndian );
PSDHeader header;
s >> header;
// Check image file format.
if( s.atEnd() || !IsValid( header ) )
return;
// Check if it's a supported format.
if( !IsSupported( header ) )
return;
if( !LoadPSD(s, header) )
return;
if (icclen > 0)
{
tiffProf = cmsOpenProfileFromMem(iccbuf, icclen);
if (tiffProf)
{
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigRgbData)
*components = 3;
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigCmykData)
*components = 4;
for (uint el = 0; el < icclen; ++el)
*profile += iccbuf[el];
}
cmsCloseProfile(tiffProf);
free(iccbuf);
}
f.close();
}
else
return;
}
#ifdef HAVE_TIFF
else if ((ext == "tif") || (ext == "tiff"))
{
TIFF* tif = TIFFOpen(fn.local8Bit(), "r");
if(tif)
{
DWORD EmbedLen = 0;
LPBYTE EmbedBuffer;
if (TIFFGetField(tif, TIFFTAG_ICCPROFILE, &EmbedLen, &EmbedBuffer))
{
tiffProf = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);
if (tiffProf)
{
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigRgbData)
*components = 3;
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigCmykData)
*components = 4;
for (uint el = 0; el < EmbedLen; ++el)
*profile += EmbedBuffer[el];
}
cmsCloseProfile(tiffProf);
}
TIFFClose(tif);
}
}
#endif // HAVE_TIFF
else if ((ext == "jpg") || (ext == "jpeg"))
{
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
FILE *infile;
cinfo.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = my_error_exit;
infile = NULL;
if (setjmp (jerr.setjmp_buffer))
{
jpeg_destroy_decompress (&cinfo);
if (infile)
fclose (infile);
return;
}
jpeg_create_decompress (&cinfo);
if ((infile = fopen (fn.local8Bit(), "rb")) == NULL)
return;
jpeg_stdio_src(&cinfo, infile);
jpeg_save_markers(&cinfo, ICC_MARKER, 0xFFFF);
jpeg_read_header(&cinfo, true);
jpeg_start_decompress(&cinfo);
unsigned int EmbedLen = 0;
unsigned char* EmbedBuffer;
if (read_jpeg_marker(ICC_MARKER,&cinfo, &EmbedBuffer, &EmbedLen))
{
tiffProf = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);
if (tiffProf)
{
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigRgbData)
*components = 3;
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigCmykData)
*components = 4;
for (uint el = 0; el < EmbedLen; ++el)
*profile += EmbedBuffer[el];
}
cmsCloseProfile(tiffProf);
free(EmbedBuffer);
}
(void) jpeg_finish_decompress(&cinfo);
fclose (infile);
jpeg_destroy_decompress (&cinfo);
}
else
return;
#endif // HAVE_CMS
}
void ScImage::getEmbeddedProfile(const QString & fn, QByteArray *profile, int *components)
{
Q_ASSERT(profile);
Q_ASSERT(components);
#ifdef HAVE_CMS
cmsHPROFILE tiffProf = 0;
QFileInfo fi = QFileInfo(fn);
if (!fi.exists())
return;
QString ext = fi.extension(false).lower();
iccbuf = 0;
icclen = 0;
if (ext == "psd")
{
QFile f(fn);
if (f.open(IO_ReadOnly))
{
imgInfo.xres = 72;
imgInfo.yres = 72;
QDataStream s( &f );
s.setByteOrder( QDataStream::BigEndian );
PSDHeader header;
s >> header;
// Check image file format.
if( s.atEnd() || !IsValid( header ) )
return;
// Check if it's a supported format.
if( !IsSupported( header ) )
return;
if( !LoadPSD(s, header) )
return;
if (icclen > 0)
{
tiffProf = cmsOpenProfileFromMem(iccbuf, icclen);
if (tiffProf)
{
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigRgbData)
*components = 3;
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigCmykData)
*components = 4;
profile->resize(icclen);
for (uint el = 0; el < icclen; ++el)
(*profile)[el] = iccbuf[el];
}
cmsCloseProfile(tiffProf);
free(iccbuf);
}
f.close();
}
else
return;
}
#ifdef HAVE_TIFF
else if ((ext == "tif") || (ext == "tiff"))
{
TIFF* tif = TIFFOpen(fn.local8Bit(), "r");
if(tif)
{
DWORD EmbedLen = 0;
LPBYTE EmbedBuffer;
if (TIFFGetField(tif, TIFFTAG_ICCPROFILE, &EmbedLen, &EmbedBuffer))
{
tiffProf = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);
if (tiffProf)
{
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigRgbData)
*components = 3;
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigCmykData)
*components = 4;
profile->resize(EmbedLen);
for (uint el = 0; el < EmbedLen; ++el)
(*profile)[el] = EmbedBuffer[el];
}
cmsCloseProfile(tiffProf);
}
TIFFClose(tif);
}
}
#endif // HAVE_TIFF
else if ((ext == "jpg") || (ext == "jpeg"))
{
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
FILE *infile;
cinfo.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = my_error_exit;
infile = NULL;
if (setjmp (jerr.setjmp_buffer))
{
jpeg_destroy_decompress (&cinfo);
if (infile)
fclose (infile);
return;
}
jpeg_create_decompress (&cinfo);
if ((infile = fopen (fn.local8Bit(), "rb")) == NULL)
return;
jpeg_stdio_src(&cinfo, infile);
jpeg_save_markers(&cinfo, ICC_MARKER, 0xFFFF);
jpeg_read_header(&cinfo, true);
jpeg_start_decompress(&cinfo);
unsigned int EmbedLen = 0;
unsigned char* EmbedBuffer;
if (read_jpeg_marker(ICC_MARKER,&cinfo, &EmbedBuffer, &EmbedLen))
{
tiffProf = cmsOpenProfileFromMem(EmbedBuffer, EmbedLen);
if (tiffProf)
{
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigRgbData)
*components = 3;
if (static_cast<int>(cmsGetColorSpace(tiffProf)) == icSigCmykData)
*components = 4;
profile->resize(EmbedLen);
for (uint el = 0; el < EmbedLen; ++el)
(*profile)[el] = EmbedBuffer[el];
}
cmsCloseProfile(tiffProf);
free(EmbedBuffer);
}
(void) jpeg_finish_decompress(&cinfo);
fclose (infile);
jpeg_destroy_decompress (&cinfo);
}
else
return;
#endif // HAVE_CMS
}
bool ScImage::LoadPicture(const QString & fn, const QString & Prof,
int rend, bool useEmbedded, bool useProf,
RequestType requestType, int gsRes, bool *realCMYK)
{
// 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;
if (realCMYK != 0)
*realCMYK = false;
bool bilevel = false;
float xres, yres;
short resolutionunit = 0;
RequestType reqType = requestType;
#ifdef HAVE_CMS
cmsHTRANSFORM xform = 0;
cmsHPROFILE inputProf = 0;
cmsHPROFILE tiffProf = 0;
int cmsFlags = 0;
#endif
QFileInfo fi = QFileInfo(fn);
if (!fi.exists())
return ret;
QString ext = fi.extension(false).lower();
QString tmp, dummy, cmd1, cmd2, BBox, tmp2;
QChar tc;
double x, y, b, h;
bool found = false;
int retg = -1;
QString tmpFile = QDir::convertSeparators(QDir::homeDirPath()+"/.scribus/sc.png");
QString picFile = QDir::convertSeparators(fn);
if (ext ==